Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 3 Sep 2012 21:30:52 +0200
From:      Hans Petter Selasky <hselasky@c2i.net>
To:        Roberth =?iso-8859-1?q?Sjon=F8y?= <roberth.sjonoy@gmail.com>
Cc:        freebsd-multimedia@freebsd.org, freebsd-usb@freebsd.org
Subject:   Re: M2Tech HiFace Two and FreeBSD
Message-ID:  <201209032130.52971.hselasky@c2i.net>
In-Reply-To: <CAFLBWR2FxNrucc217f_aG=0xJYvFbkDwN921wL0a9acgeWxYYg@mail.gmail.com>
References:  <CAFLBWR0CBT8kqe9xFYzNoGZTy4fbXV1YsimytuTHqrZRr5BxUw@mail.gmail.com> <201209021300.58695.hselasky@c2i.net> <CAFLBWR2FxNrucc217f_aG=0xJYvFbkDwN921wL0a9acgeWxYYg@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
--Boundary-00=_sVQRQoKLq20BXa9
Content-Type: Text/Plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

On Sunday 02 September 2012 13:06:40 Roberth Sjon=F8y wrote:
> Here you go,
>=20
> http://pastebin.com/LKT1LkNd
>=20
> Regards,
>=20
> Roberth Sjon=F8y

Hi,

I spent some time today to pull together USB AUDIO V2.0 support for FreeBSD=
=2E=20
See:

http://svn.freebsd.org/changeset/base/240078

The attached patch will update uaudio.c, but is not complete. Only mixer=20
parsing is complete. Audio descriptors and sample rate selection is not=20
complete.

Can you see what you get when you load snd_uaudio after applying the attach=
ed=20
patch + r240078 ?

If you want to help out fix the remaining few bits and pieces feel free. Th=
ey=20
are all located inside "uaudio_chan_fill_info()" in uaudio.c !

=2D-HPS

--Boundary-00=_sVQRQoKLq20BXa9
Content-Type: text/x-patch;
  charset="iso-8859-1";
  name="uaudio.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
	filename="uaudio.diff"

=== sys/dev/sound/usb/uaudio.c
==================================================================
--- sys/dev/sound/usb/uaudio.c	(revision 240078)
+++ sys/dev/sound/usb/uaudio.c	(local)
@@ -162,7 +162,6 @@
 	struct uaudio_softc *priv_sc;
 	struct pcm_channel *pcm_ch;
 	struct usb_xfer *xfer[UAUDIO_NCHANBUFS];
-	const struct usb_audio_streaming_interface_descriptor *p_asid;
 	const struct usb_audio_streaming_type1_descriptor *p_asf1d;
 	const struct usb_audio_streaming_endpoint_descriptor *p_sed;
 	const usb_endpoint_descriptor_audio_t *p_ed1;
@@ -296,6 +295,26 @@
 	struct uaudio_terminal_node *root;
 };
 
+struct uaudio20_terminal_node {
+	union {
+		const struct usb_descriptor *desc;
+		const struct usb_audio20_clock_source_unit *csrc;
+		const struct usb_audio20_clock_selector_unit *csel;
+		const struct usb_audio20_clock_multiplier_unit *cmul;
+		const struct usb_audio20_input_terminal *it;
+		const struct usb_audio20_output_terminal *ot;
+		const struct usb_audio20_mixer_unit_0 *mu;
+		const struct usb_audio20_selector_unit *su;
+		const struct usb_audio20_feature_unit *fu;
+		const struct usb_audio20_sample_rate_unit *ru;
+		const struct usb_audio20_processing_unit_0 *pu;
+		const struct usb_audio20_extension_unit_0 *eu;
+		const struct usb_audio20_effect_unit *ef;
+	}	u;
+	struct uaudio_search_result usr;
+	struct uaudio20_terminal_node *root;
+};
+
 struct uaudio_format {
 	uint16_t wFormat;
 	uint8_t	bPrecision;
@@ -321,6 +340,31 @@
 	{0, 0, 0, NULL}
 };
 
+struct uaudio20_format {
+	uint32_t dwFormat;
+	uint8_t	bPrecision;
+	uint32_t freebsd_fmt;
+	const char *description;
+};
+
+static const struct uaudio20_format uaudio20_formats[] = {
+
+	{UA20_FMT_PCM8, 8, AFMT_U8, "8-bit U-LE PCM"},
+	{UA20_FMT_PCM8, 16, AFMT_U16_LE, "16-bit U-LE PCM"},
+	{UA20_FMT_PCM8, 24, AFMT_U24_LE, "24-bit U-LE PCM"},
+	{UA20_FMT_PCM8, 32, AFMT_U32_LE, "32-bit U-LE PCM"},
+
+	{UA20_FMT_PCM, 8, AFMT_S8, "8-bit S-LE PCM"},
+	{UA20_FMT_PCM, 16, AFMT_S16_LE, "16-bit S-LE PCM"},
+	{UA20_FMT_PCM, 24, AFMT_S24_LE, "24-bit S-LE PCM"},
+	{UA20_FMT_PCM, 32, AFMT_S32_LE, "32-bit S-LE PCM"},
+
+	{UA20_FMT_ALAW, 8, AFMT_A_LAW, "8-bit A-Law"},
+	{UA20_FMT_MULAW, 8, AFMT_MU_LAW, "8-bit mu-Law"},
+
+	{0, 0, 0, NULL}
+};
+
 #define	UAC_OUTPUT	0
 #define	UAC_INPUT	1
 #define	UAC_EQUAL	2
@@ -346,18 +390,8 @@
 static usb_callback_t umidi_bulk_read_callback;
 static usb_callback_t umidi_bulk_write_callback;
 
-static void	uaudio_chan_fill_info_sub(struct uaudio_softc *,
-		    struct usb_device *, uint32_t, uint8_t, uint8_t);
-static void	uaudio_chan_fill_info(struct uaudio_softc *,
-		    struct usb_device *);
-static void	uaudio_mixer_add_ctl_sub(struct uaudio_softc *,
-		    struct uaudio_mixer_node *);
-static void	uaudio_mixer_add_ctl(struct uaudio_softc *,
-		    struct uaudio_mixer_node *);
-static void	uaudio_mixer_add_input(struct uaudio_softc *,
-		    const struct uaudio_terminal_node *, int);
-static void	uaudio_mixer_add_output(struct uaudio_softc *,
-		    const struct uaudio_terminal_node *, int);
+/* ==== USB audio v1.0 ==== */
+
 static void	uaudio_mixer_add_mixer(struct uaudio_softc *,
 		    const struct uaudio_terminal_node *, int);
 static void	uaudio_mixer_add_selector(struct uaudio_softc *,
@@ -386,6 +420,42 @@
 		    const uint8_t *, uint8_t, struct uaudio_search_result *);
 static void	uaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *,
 		    uint8_t, uint8_t, struct uaudio_search_result *);
+static const void *uaudio_mixer_verify_desc(const void *, uint32_t);
+
+/* ==== USB audio v2.0 ==== */
+
+static void	uaudio20_mixer_add_mixer(struct uaudio_softc *,
+		    const struct uaudio20_terminal_node *, int);
+static void	uaudio20_mixer_add_selector(struct uaudio_softc *,
+		    const struct uaudio20_terminal_node *, int);
+static void	uaudio20_mixer_add_feature(struct uaudio_softc *,
+		    const struct uaudio20_terminal_node *, int);
+static struct	usb_audio20_cluster uaudio20_mixer_get_cluster(uint8_t,
+		    const struct uaudio20_terminal_node *);
+static uint16_t	uaudio20_mixer_determine_class(const struct uaudio20_terminal_node *,
+		    struct uaudio_mixer_node *);
+static uint16_t	uaudio20_mixer_feature_name(const struct uaudio20_terminal_node *,
+		    struct uaudio_mixer_node *);
+static const struct uaudio20_terminal_node *uaudio20_mixer_get_input(
+		    const struct uaudio20_terminal_node *, uint8_t);
+static const struct uaudio20_terminal_node *uaudio20_mixer_get_output(
+		    const struct uaudio20_terminal_node *, uint8_t);
+static void	uaudio20_mixer_find_inputs_sub(struct uaudio20_terminal_node *,
+		    const uint8_t *, uint8_t, struct uaudio_search_result *);
+static void	uaudio20_mixer_find_outputs_sub(struct uaudio20_terminal_node *,
+		    uint8_t, uint8_t, struct uaudio_search_result *);
+static const void *uaudio20_mixer_verify_desc(const void *, uint32_t);
+
+/* USB audio v1.0 and v2.0 */
+
+static void	uaudio_chan_fill_info_sub(struct uaudio_softc *,
+		    struct usb_device *, uint32_t, uint8_t, uint8_t);
+static void	uaudio_chan_fill_info(struct uaudio_softc *,
+		    struct usb_device *);
+static void	uaudio_mixer_add_ctl_sub(struct uaudio_softc *,
+		    struct uaudio_mixer_node *);
+static void	uaudio_mixer_add_ctl(struct uaudio_softc *,
+		    struct uaudio_mixer_node *);
 static void	uaudio_mixer_fill_info(struct uaudio_softc *,
 		    struct usb_device *, void *);
 static uint16_t	uaudio_mixer_get(struct usb_device *, uint8_t,
@@ -395,7 +465,6 @@
 static usb_error_t uaudio_set_speed(struct usb_device *, uint8_t, uint32_t);
 static int	uaudio_mixer_signext(uint8_t, int);
 static int	uaudio_mixer_bsd2value(struct uaudio_mixer_node *, int32_t val);
-static const void *uaudio_mixer_verify_desc(const void *, uint32_t);
 static void	uaudio_mixer_init(struct uaudio_softc *);
 static uint8_t	umidi_convert_to_usb(struct umidi_sub_chan *, uint8_t, uint8_t);
 static struct	umidi_sub_chan *umidi_sub_by_fifo(struct usb_fifo *);
@@ -413,9 +482,6 @@
 #ifdef USB_DEBUG
 static void	uaudio_chan_dump_ep_desc(
 		    const usb_endpoint_descriptor_audio_t *);
-static void	uaudio_mixer_dump_cluster(uint8_t,
-		    const struct uaudio_terminal_node *);
-static const char *uaudio_mixer_get_terminal_name(uint16_t);
 #endif
 
 static const struct usb_config
@@ -614,10 +680,10 @@
 
 	id = usbd_get_interface_descriptor(uaa->iface);
 
+	uaudio_mixer_fill_info(sc, uaa->device, id);
+
 	uaudio_chan_fill_info(sc, uaa->device);
 
-	uaudio_mixer_fill_info(sc, uaa->device, id);
-
 	DPRINTF("audio rev %d.%02x\n",
 	    sc->sc_audio_rev >> 8,
 	    sc->sc_audio_rev & 0xff);
@@ -862,7 +928,7 @@
     uint32_t rate, uint8_t channels, uint8_t bit_resolution)
 {
 	struct usb_descriptor *desc = NULL;
-	const struct usb_audio_streaming_interface_descriptor *asid = NULL;
+	const struct usb_audio_streaming_interface_descriptor *asid= NULL;
 	const struct usb_audio_streaming_type1_descriptor *asf1d = NULL;
 	const struct usb_audio_streaming_endpoint_descriptor *sed = NULL;
 	usb_endpoint_descriptor_audio_t *ed1 = NULL;
@@ -1047,7 +1113,6 @@
 					    bit_resolution, p_fmt->description);
 
 					chan->sample_rate = rate;
-					chan->p_asid = asid;
 					chan->p_asf1d = asf1d;
 					chan->p_ed1 = ed1;
 					chan->p_ed2 = ed2;
@@ -1724,43 +1789,94 @@
 }
 
 static void
-uaudio_mixer_add_input(struct uaudio_softc *sc,
+uaudio_mixer_add_mixer(struct uaudio_softc *sc,
     const struct uaudio_terminal_node *iot, int id)
 {
-#ifdef USB_DEBUG
-	const struct usb_audio_input_terminal *d = iot[id].u.it;
+	struct uaudio_mixer_node mix;
 
-	DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x "
-	    "bAssocTerminal=%d bNrChannels=%d wChannelConfig=%d "
-	    "iChannelNames=%d\n",
-	    d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal,
-	    d->bNrChannels, UGETW(d->wChannelConfig),
-	    d->iChannelNames);
-#endif
-}
+	const struct usb_audio_mixer_unit_0 *d0 = iot[id].u.mu;
+	const struct usb_audio_mixer_unit_1 *d1;
 
-static void
-uaudio_mixer_add_output(struct uaudio_softc *sc,
-    const struct uaudio_terminal_node *iot, int id)
-{
-#ifdef USB_DEBUG
-	const struct usb_audio_output_terminal *d = iot[id].u.ot;
+	uint32_t bno;			/* bit number */
+	uint32_t p;			/* bit number accumulator */
+	uint32_t mo;			/* matching outputs */
+	uint32_t mc;			/* matching channels */
+	uint32_t ichs;			/* input channels */
+	uint32_t ochs;			/* output channels */
+	uint32_t c;
+	uint32_t chs;			/* channels */
+	uint32_t i;
+	uint32_t o;
 
-	DPRINTFN(3, "bTerminalId=%d wTerminalType=0x%04x "
-	    "bAssocTerminal=%d bSourceId=%d iTerminal=%d\n",
-	    d->bTerminalId, UGETW(d->wTerminalType), d->bAssocTerminal,
-	    d->bSourceId, d->iTerminal);
-#endif
+	DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n",
+	    d0->bUnitId, d0->bNrInPins);
+
+	/* compute the number of input channels */
+
+	ichs = 0;
+	for (i = 0; i < d0->bNrInPins; i++) {
+		ichs += uaudio_mixer_get_cluster(
+		    d0->baSourceId[i], iot).bNrChannels;
+	}
+
+	d1 = (const void *)(d0->baSourceId + d0->bNrInPins);
+
+	/* and the number of output channels */
+
+	ochs = d1->bNrChannels;
+
+	DPRINTFN(3, "ichs=%d ochs=%d\n", ichs, ochs);
+
+	memset(&mix, 0, sizeof(mix));
+
+	mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
+	uaudio_mixer_determine_class(&iot[id], &mix);
+	mix.type = MIX_SIGNED_16;
+
+	if (uaudio_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL)
+		return;
+
+	for (p = i = 0; i < d0->bNrInPins; i++) {
+		chs = uaudio_mixer_get_cluster(
+		    d0->baSourceId[i], iot).bNrChannels;
+		mc = 0;
+		for (c = 0; c < chs; c++) {
+			mo = 0;
+			for (o = 0; o < ochs; o++) {
+				bno = ((p + c) * ochs) + o;
+				if (BIT_TEST(d1->bmControls, bno))
+					mo++;
+			}
+			if (mo == 1)
+				mc++;
+		}
+		if ((mc == chs) && (chs <= MIX_MAX_CHAN)) {
+
+			/* repeat bit-scan */
+
+			mc = 0;
+			for (c = 0; c < chs; c++) {
+				for (o = 0; o < ochs; o++) {
+					bno = ((p + c) * ochs) + o;
+					if (BIT_TEST(d1->bmControls, bno))
+						mix.wValue[mc++] = MAKE_WORD(p + c + 1, o + 1);
+				}
+			}
+			mix.nchan = chs;
+			uaudio_mixer_add_ctl(sc, &mix);
+		}
+		p += chs;
+	}
 }
 
 static void
-uaudio_mixer_add_mixer(struct uaudio_softc *sc,
-    const struct uaudio_terminal_node *iot, int id)
+uaudio20_mixer_add_mixer(struct uaudio_softc *sc,
+    const struct uaudio20_terminal_node *iot, int id)
 {
 	struct uaudio_mixer_node mix;
 
-	const struct usb_audio_mixer_unit_0 *d0 = iot[id].u.mu;
-	const struct usb_audio_mixer_unit_1 *d1;
+	const struct usb_audio20_mixer_unit_0 *d0 = iot[id].u.mu;
+	const struct usb_audio20_mixer_unit_1 *d1;
 
 	uint32_t bno;			/* bit number */
 	uint32_t p;			/* bit number accumulator */
@@ -1780,8 +1896,8 @@
 
 	ichs = 0;
 	for (i = 0; i < d0->bNrInPins; i++) {
-		ichs += (uaudio_mixer_get_cluster(d0->baSourceId[i], iot)
-		    .bNrChannels);
+		ichs += uaudio20_mixer_get_cluster(
+		    d0->baSourceId[i], iot).bNrChannels;
 	}
 
 	d1 = (const void *)(d0->baSourceId + d0->bNrInPins);
@@ -1795,26 +1911,25 @@
 	memset(&mix, 0, sizeof(mix));
 
 	mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
-	uaudio_mixer_determine_class(&iot[id], &mix);
+	uaudio20_mixer_determine_class(&iot[id], &mix);
 	mix.type = MIX_SIGNED_16;
 
-	if (uaudio_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL) {
+	if (uaudio20_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL)
 		return;
-	}
+
 	for (p = i = 0; i < d0->bNrInPins; i++) {
-		chs = uaudio_mixer_get_cluster(d0->baSourceId[i], iot).bNrChannels;
+		chs = uaudio20_mixer_get_cluster(
+		    d0->baSourceId[i], iot).bNrChannels;
 		mc = 0;
 		for (c = 0; c < chs; c++) {
 			mo = 0;
 			for (o = 0; o < ochs; o++) {
 				bno = ((p + c) * ochs) + o;
-				if (BIT_TEST(d1->bmControls, bno)) {
+				if (BIT_TEST(d1->bmControls, bno))
 					mo++;
-				}
 			}
-			if (mo == 1) {
+			if (mo == 1)
 				mc++;
-			}
 		}
 		if ((mc == chs) && (chs <= MIX_MAX_CHAN)) {
 
@@ -1824,15 +1939,12 @@
 			for (c = 0; c < chs; c++) {
 				for (o = 0; o < ochs; o++) {
 					bno = ((p + c) * ochs) + o;
-					if (BIT_TEST(d1->bmControls, bno)) {
+					if (BIT_TEST(d1->bmControls, bno))
 						mix.wValue[mc++] = MAKE_WORD(p + c + 1, o + 1);
-					}
 				}
 			}
 			mix.nchan = chs;
 			uaudio_mixer_add_ctl(sc, &mix);
-		} else {
-			/* XXX */
 		}
 		p += chs;
 	}
@@ -1882,6 +1994,49 @@
 	uaudio_mixer_add_ctl(sc, &mix);
 }
 
+static void
+uaudio20_mixer_add_selector(struct uaudio_softc *sc,
+    const struct uaudio20_terminal_node *iot, int id)
+{
+	const struct usb_audio20_selector_unit *d = iot[id].u.su;
+	struct uaudio_mixer_node mix;
+	uint16_t i;
+
+	DPRINTFN(3, "bUnitId=%d bNrInPins=%d\n",
+	    d->bUnitId, d->bNrInPins);
+
+	if (d->bNrInPins == 0)
+		return;
+
+	memset(&mix, 0, sizeof(mix));
+
+	mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no);
+	mix.wValue[0] = MAKE_WORD(0, 0);
+	uaudio20_mixer_determine_class(&iot[id], &mix);
+	mix.nchan = 1;
+	mix.type = MIX_SELECTOR;
+
+	mix.ctl = SOUND_MIXER_NRDEVICES;
+	mix.minval = 1;
+	mix.maxval = d->bNrInPins;
+
+	if (mix.maxval > MAX_SELECTOR_INPUT_PIN)
+		mix.maxval = MAX_SELECTOR_INPUT_PIN;
+
+	mix.mul = (mix.maxval - mix.minval);
+	for (i = 0; i < MAX_SELECTOR_INPUT_PIN; i++)
+		mix.slctrtype[i] = SOUND_MIXER_NRDEVICES;
+
+	for (i = 0; i < mix.maxval; i++) {
+		mix.slctrtype[i] = uaudio20_mixer_feature_name(
+		    &iot[d->baSourceId[i]], &mix);
+	}
+
+	mix.class = 0;			/* not used */
+
+	uaudio_mixer_add_ctl(sc, &mix);
+}
+
 static uint32_t
 uaudio_mixer_feature_get_bmaControls(const struct usb_audio_feature_unit *d,
     uint8_t i)
@@ -2031,6 +2186,127 @@
 }
 
 static void
+uaudio20_mixer_add_feature(struct uaudio_softc *sc,
+    const struct uaudio20_terminal_node *iot, int id)
+{
+	const struct usb_audio20_feature_unit *d = iot[id].u.fu;
+	struct uaudio_mixer_node mix;
+	uint32_t ctl;
+	uint32_t mmask;
+	uint32_t cmask;
+	uint16_t mixernumber;
+	uint8_t nchan;
+	uint8_t chan;
+	uint8_t i;
+	uint8_t what;
+
+	if (UGETDW(d->bmaControls[0]) == 0)
+		return;
+
+	memset(&mix, 0, sizeof(mix));
+
+	nchan = (d->bLength - 6) / 4;
+	mmask = UGETDW(d->bmaControls[0]);
+	cmask = 0;
+
+	if (nchan == 0)
+		return;
+
+	/* figure out what we can control */
+
+	for (chan = 1; chan < nchan; chan++)
+		cmask |= UGETDW(d->bmaControls[chan]);
+
+	if (nchan > MIX_MAX_CHAN)
+		nchan = MIX_MAX_CHAN;
+
+	mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no);
+
+	for (ctl = 3; ctl != 0; ctl <<= 2) {
+
+		mixernumber = uaudio20_mixer_feature_name(&iot[id], &mix);
+
+		switch (ctl) {
+		case (3 << 0):
+			mix.type = MIX_ON_OFF;
+			mix.ctl = SOUND_MIXER_NRDEVICES;
+			what = MUTE_CONTROL;
+			break;
+		case (3 << 2): 
+			mix.type = MIX_SIGNED_16;
+			mix.ctl = mixernumber;
+			what = VOLUME_CONTROL;
+			break;
+		case (3 << 4):
+			mix.type = MIX_SIGNED_8;
+			mix.ctl = SOUND_MIXER_BASS;
+			what = BASS_CONTROL;
+			break;
+		case (3 << 6):
+			mix.type = MIX_SIGNED_8;
+			mix.ctl = SOUND_MIXER_NRDEVICES;	/* XXXXX */
+			what = MID_CONTROL;
+			break;
+		case (3 << 8):
+			mix.type = MIX_SIGNED_8;
+			mix.ctl = SOUND_MIXER_TREBLE;
+			what = TREBLE_CONTROL;
+			break;
+		case (3 << 12):
+			mix.type = MIX_ON_OFF;
+			mix.ctl = SOUND_MIXER_NRDEVICES;	/* XXXXX */
+			what = AGC_CONTROL;
+			break;
+		case (3 << 14):
+			mix.type = MIX_UNSIGNED_16;
+			mix.ctl = SOUND_MIXER_NRDEVICES;	/* XXXXX */
+			what = DELAY_CONTROL;
+			break;
+		case (3 << 16):
+			mix.type = MIX_ON_OFF;
+			mix.ctl = SOUND_MIXER_NRDEVICES;	/* XXXXX */
+			what = BASS_BOOST_CONTROL;
+			break;
+		case (3 << 18):
+			mix.type = MIX_ON_OFF;
+			mix.ctl = SOUND_MIXER_LOUD;	/* Is this correct ? */
+			what = LOUDNESS_CONTROL;
+			break;
+		case (3 << 20):
+			mix.type = MIX_SIGNED_16;
+			mix.ctl = mixernumber;
+			what = INPUT_GAIN_CONTROL;
+			break;
+		case (3 << 22):
+			mix.type = MIX_SIGNED_16;
+			mix.ctl = mixernumber;
+			what = INPUT_GAIN_PAD_CONTROL;
+			break;
+		default:
+			continue;
+		}
+
+		if ((mmask & ctl) == ctl) {
+			mix.nchan = 1;
+			mix.wValue[0] = MAKE_WORD(what, 0);
+		} else if ((cmask & ctl) == ctl) {
+			mix.nchan = nchan - 1;
+			for (i = 1; i < nchan; i++) {
+				if ((UGETDW(d->bmaControls[i]) & ctl) == ctl)
+					mix.wValue[i - 1] = MAKE_WORD(what, i);
+				else
+					mix.wValue[i - 1] = -1;
+			}
+		} else {
+			continue;
+		}
+
+		if (mix.type != MIX_UNKNOWN)
+			uaudio_mixer_add_ctl(sc, &mix);
+	}
+}
+
+static void
 uaudio_mixer_add_processing_updown(struct uaudio_softc *sc,
     const struct uaudio_terminal_node *iot, int id)
 {
@@ -2276,35 +2552,144 @@
 	return (NULL);
 }
 
-#ifdef USB_DEBUG
-static void
-uaudio_mixer_dump_cluster(uint8_t id, const struct uaudio_terminal_node *iot)
+static const void *
+uaudio20_mixer_verify_desc(const void *arg, uint32_t len)
 {
-	static const char *channel_names[16] = {
-		"LEFT", "RIGHT", "CENTER", "LFE",
-		"LEFT_SURROUND", "RIGHT_SURROUND", "LEFT_CENTER", "RIGHT_CENTER",
-		"SURROUND", "LEFT_SIDE", "RIGHT_SIDE", "TOP",
-		"RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15",
-	};
-	uint16_t cc;
-	uint8_t i;
-	const struct usb_audio_cluster cl = uaudio_mixer_get_cluster(id, iot);
+	const struct usb_audio20_mixer_unit_1 *d1;
+	const struct usb_audio20_extension_unit_1 *e1;
+	const struct usb_audio20_processing_unit_1 *u1;
 
-	cc = UGETW(cl.wChannelConfig);
+	union {
+		const struct usb_descriptor *desc;
+		const struct usb_audio20_clock_source_unit *csrc;
+		const struct usb_audio20_clock_selector_unit *csel;
+		const struct usb_audio20_clock_multiplier_unit *cmul;
+		const struct usb_audio20_input_terminal *it;
+		const struct usb_audio20_output_terminal *ot;
+		const struct usb_audio20_mixer_unit_0 *mu;
+		const struct usb_audio20_selector_unit *su;
+		const struct usb_audio20_feature_unit *fu;
+		const struct usb_audio20_sample_rate_unit *ru;
+		const struct usb_audio20_processing_unit_0 *pu;
+		const struct usb_audio20_extension_unit_0 *eu;
+		const struct usb_audio20_effect_unit *ef;
+	}     u;
 
-	DPRINTF("cluster: bNrChannels=%u iChannelNames=%u wChannelConfig="
-	    "0x%04x:\n", cl.iChannelNames, cl.bNrChannels, cc);
+	u.desc = arg;
 
-	for (i = 0; cc; i++) {
-		if (cc & 1) {
-			DPRINTF(" - %s\n", channel_names[i]);
-		}
-		cc >>= 1;
+	if (u.desc == NULL)
+		goto error;
+	if (u.desc->bDescriptorType != UDESC_CS_INTERFACE)
+		goto error;
+	switch (u.desc->bDescriptorSubtype) {
+	case UDESCSUB_AC_INPUT:
+		len += sizeof(*u.it);
+		break;
+
+	case UDESCSUB_AC_OUTPUT:
+		len += sizeof(*u.ot);
+		break;
+
+	case UDESCSUB_AC_MIXER:
+		len += sizeof(*u.mu);
+
+		if (u.desc->bLength < len)
+			goto error;
+		len += u.mu->bNrInPins;
+
+		if (u.desc->bLength < len)
+			goto error;
+
+		d1 = (const void *)(u.mu->baSourceId + u.mu->bNrInPins);
+
+		len += sizeof(*d1) + d1->bNrChannels;
+		break;
+
+	case UDESCSUB_AC_SELECTOR:
+		len += sizeof(*u.su);
+
+		if (u.desc->bLength < len)
+			goto error;
+
+		len += u.su->bNrInPins;
+		break;
+
+	case UDESCSUB_AC_FEATURE:
+		len += sizeof(*u.fu);
+		break;
+
+	case UDESCSUB_AC_EFFECT:
+		len += sizeof(*u.ef) + 4;
+		break;
+
+	case UDESCSUB_AC_PROCESSING_V2:
+		len += sizeof(*u.pu);
+
+		if (u.desc->bLength < len)
+			goto error;
+
+		len += u.pu->bNrInPins;
+
+		if (u.desc->bLength < len)
+			goto error;
+
+		u1 = (const void *)(u.pu->baSourceId + u.pu->bNrInPins);
+
+		len += sizeof(*u1);
+		break;
+
+	case UDESCSUB_AC_EXTENSION_V2:
+		len += sizeof(*u.eu);
+
+		if (u.desc->bLength < len)
+			goto error;
+
+		len += u.eu->bNrInPins;
+
+		if (u.desc->bLength < len)
+			goto error;
+
+		e1 = (const void *)(u.eu->baSourceId + u.eu->bNrInPins);
+
+		len += sizeof(*e1);
+		break;
+
+	case UDESCSUB_AC_CLOCK_SRC:
+		len += sizeof(*u.csrc);
+		break;
+
+	case UDESCSUB_AC_CLOCK_SEL:
+		len += sizeof(*u.csel);
+		break;
+
+	case UDESCSUB_AC_CLOCK_MUL:
+		len += sizeof(*u.cmul);
+		break;
+
+	case UDESCSUB_AC_SAMPLE_RT:
+		len += sizeof(*u.ru);
+		break;
+
+	default:
+		goto error;
 	}
+
+	if (u.desc->bLength < len)
+		goto error;
+
+	return (u.desc);
+
+error:
+	if (u.desc) {
+		DPRINTF("invalid descriptor, type=%d, "
+		    "sub_type=%d, len=%d of %d bytes\n",
+		    u.desc->bDescriptorType,
+		    u.desc->bDescriptorSubtype,
+		    u.desc->bLength, len);
+	}
+	return (NULL);
 }
 
-#endif
-
 static struct usb_audio_cluster
 uaudio_mixer_get_cluster(uint8_t id, const struct uaudio_terminal_node *iot)
 {
@@ -2369,108 +2754,80 @@
 	return (r);
 }
 
-#ifdef USB_DEBUG
+static struct usb_audio20_cluster
+uaudio20_mixer_get_cluster(uint8_t id, const struct uaudio20_terminal_node *iot)
+{
+	struct usb_audio20_cluster r;
+	const struct usb_descriptor *dp;
+	uint8_t i;
 
-struct uaudio_tt_to_string {
-	uint16_t terminal_type;
-	const char *desc;
-};
+	for (i = 0; i < UAUDIO_RECURSE_LIMIT; i++) {	/* avoid infinite loops */
+		dp = iot[id].u.desc;
+		if (dp == NULL)
+			goto error;
 
-static const struct uaudio_tt_to_string uaudio_tt_to_string[] = {
+		switch (dp->bDescriptorSubtype) {
+		case UDESCSUB_AC_INPUT:
+			r.bNrChannels = iot[id].u.it->bNrChannels;
+			r.bmChannelConfig[0] = iot[id].u.it->bmChannelConfig[0];
+			r.bmChannelConfig[1] = iot[id].u.it->bmChannelConfig[1];
+			r.bmChannelConfig[2] = iot[id].u.it->bmChannelConfig[2];
+			r.bmChannelConfig[3] = iot[id].u.it->bmChannelConfig[3];
+			r.iChannelNames = iot[id].u.it->iTerminal;
+			goto done;
 
-	/* USB terminal types */
-	{UAT_UNDEFINED, "UAT_UNDEFINED"},
-	{UAT_STREAM, "UAT_STREAM"},
-	{UAT_VENDOR, "UAT_VENDOR"},
+		case UDESCSUB_AC_OUTPUT:
+			id = iot[id].u.ot->bSourceId;
+			break;
 
-	/* input terminal types */
-	{UATI_UNDEFINED, "UATI_UNDEFINED"},
-	{UATI_MICROPHONE, "UATI_MICROPHONE"},
-	{UATI_DESKMICROPHONE, "UATI_DESKMICROPHONE"},
-	{UATI_PERSONALMICROPHONE, "UATI_PERSONALMICROPHONE"},
-	{UATI_OMNIMICROPHONE, "UATI_OMNIMICROPHONE"},
-	{UATI_MICROPHONEARRAY, "UATI_MICROPHONEARRAY"},
-	{UATI_PROCMICROPHONEARR, "UATI_PROCMICROPHONEARR"},
+		case UDESCSUB_AC_MIXER:
+			r = *(const struct usb_audio20_cluster *)
+			    &iot[id].u.mu->baSourceId[iot[id].u.mu->
+			    bNrInPins];
+			goto done;
 
-	/* output terminal types */
-	{UATO_UNDEFINED, "UATO_UNDEFINED"},
-	{UATO_SPEAKER, "UATO_SPEAKER"},
-	{UATO_HEADPHONES, "UATO_HEADPHONES"},
-	{UATO_DISPLAYAUDIO, "UATO_DISPLAYAUDIO"},
-	{UATO_DESKTOPSPEAKER, "UATO_DESKTOPSPEAKER"},
-	{UATO_ROOMSPEAKER, "UATO_ROOMSPEAKER"},
-	{UATO_COMMSPEAKER, "UATO_COMMSPEAKER"},
-	{UATO_SUBWOOFER, "UATO_SUBWOOFER"},
+		case UDESCSUB_AC_SELECTOR:
+			if (iot[id].u.su->bNrInPins > 0) {
+				/* XXX This is not really right */
+				id = iot[id].u.su->baSourceId[0];
+			}
+			break;
 
-	/* bidir terminal types */
-	{UATB_UNDEFINED, "UATB_UNDEFINED"},
-	{UATB_HANDSET, "UATB_HANDSET"},
-	{UATB_HEADSET, "UATB_HEADSET"},
-	{UATB_SPEAKERPHONE, "UATB_SPEAKERPHONE"},
-	{UATB_SPEAKERPHONEESUP, "UATB_SPEAKERPHONEESUP"},
-	{UATB_SPEAKERPHONEECANC, "UATB_SPEAKERPHONEECANC"},
+		case UDESCSUB_AC_SAMPLE_RT:
+			id = iot[id].u.ru->bSourceId;
+			break;
 
-	/* telephony terminal types */
-	{UATT_UNDEFINED, "UATT_UNDEFINED"},
-	{UATT_PHONELINE, "UATT_PHONELINE"},
-	{UATT_TELEPHONE, "UATT_TELEPHONE"},
-	{UATT_DOWNLINEPHONE, "UATT_DOWNLINEPHONE"},
+		case UDESCSUB_AC_EFFECT:
+			id = iot[id].u.ef->bSourceId;
+			break;
 
-	/* external terminal types */
-	{UATE_UNDEFINED, "UATE_UNDEFINED"},
-	{UATE_ANALOGCONN, "UATE_ANALOGCONN"},
-	{UATE_LINECONN, "UATE_LINECONN"},
-	{UATE_LEGACYCONN, "UATE_LEGACYCONN"},
-	{UATE_DIGITALAUIFC, "UATE_DIGITALAUIFC"},
-	{UATE_SPDIF, "UATE_SPDIF"},
-	{UATE_1394DA, "UATE_1394DA"},
-	{UATE_1394DV, "UATE_1394DV"},
+		case UDESCSUB_AC_FEATURE:
+			id = iot[id].u.fu->bSourceId;
+			break;
 
-	/* embedded function terminal types */
-	{UATF_UNDEFINED, "UATF_UNDEFINED"},
-	{UATF_CALIBNOISE, "UATF_CALIBNOISE"},
-	{UATF_EQUNOISE, "UATF_EQUNOISE"},
-	{UATF_CDPLAYER, "UATF_CDPLAYER"},
-	{UATF_DAT, "UATF_DAT"},
-	{UATF_DCC, "UATF_DCC"},
-	{UATF_MINIDISK, "UATF_MINIDISK"},
-	{UATF_ANALOGTAPE, "UATF_ANALOGTAPE"},
-	{UATF_PHONOGRAPH, "UATF_PHONOGRAPH"},
-	{UATF_VCRAUDIO, "UATF_VCRAUDIO"},
-	{UATF_VIDEODISCAUDIO, "UATF_VIDEODISCAUDIO"},
-	{UATF_DVDAUDIO, "UATF_DVDAUDIO"},
-	{UATF_TVTUNERAUDIO, "UATF_TVTUNERAUDIO"},
-	{UATF_SATELLITE, "UATF_SATELLITE"},
-	{UATF_CABLETUNER, "UATF_CABLETUNER"},
-	{UATF_DSS, "UATF_DSS"},
-	{UATF_RADIORECV, "UATF_RADIORECV"},
-	{UATF_RADIOXMIT, "UATF_RADIOXMIT"},
-	{UATF_MULTITRACK, "UATF_MULTITRACK"},
-	{UATF_SYNTHESIZER, "UATF_SYNTHESIZER"},
+		case UDESCSUB_AC_PROCESSING_V2:
+			r = *((const struct usb_audio20_cluster *)
+			    &iot[id].u.pu->baSourceId[iot[id].u.pu->
+			    bNrInPins]);
+			goto done;
 
-	/* unknown */
-	{0x0000, "UNKNOWN"},
-};
+		case UDESCSUB_AC_EXTENSION_V2:
+			r = *((const struct usb_audio20_cluster *)
+			    &iot[id].u.eu->baSourceId[iot[id].u.eu->
+			    bNrInPins]);
+			goto done;
 
-static const char *
-uaudio_mixer_get_terminal_name(uint16_t terminal_type)
-{
-	const struct uaudio_tt_to_string *uat = uaudio_tt_to_string;
-
-	while (uat->terminal_type) {
-		if (uat->terminal_type == terminal_type) {
-			break;
+		default:
+			goto error;
 		}
-		uat++;
 	}
-	if (uat->terminal_type == 0) {
-		DPRINTF("unknown terminal type (0x%04x)", terminal_type);
-	}
-	return (uat->desc);
+error:
+	DPRINTF("Bad data!\n");
+	memset(&r, 0, sizeof(r));
+done:
+	return (r);
 }
 
-#endif
-
 static uint16_t
 uaudio_mixer_determine_class(const struct uaudio_terminal_node *iot,
     struct uaudio_mixer_node *mix)
@@ -2524,6 +2881,58 @@
 	return (terminal_type);
 }
 
+static uint16_t
+uaudio20_mixer_determine_class(const struct uaudio20_terminal_node *iot,
+    struct uaudio_mixer_node *mix)
+{
+	uint16_t terminal_type = 0x0000;
+	const struct uaudio20_terminal_node *input[2];
+	const struct uaudio20_terminal_node *output[2];
+
+	input[0] = uaudio20_mixer_get_input(iot, 0);
+	input[1] = uaudio20_mixer_get_input(iot, 1);
+
+	output[0] = uaudio20_mixer_get_output(iot, 0);
+	output[1] = uaudio20_mixer_get_output(iot, 1);
+
+	/*
+	 * check if there is only
+	 * one output terminal:
+	 */
+	if (output[0] && (!output[1]))
+		terminal_type = UGETW(output[0]->u.ot->wTerminalType);
+	/*
+	 * If the only output terminal is USB,
+	 * the class is UAC_RECORD.
+	 */
+	if ((terminal_type & 0xff00) == (UAT_UNDEFINED & 0xff00)) {
+
+		mix->class = UAC_RECORD;
+		if (input[0] && (!input[1])) {
+			terminal_type = UGETW(input[0]->u.it->wTerminalType);
+		} else {
+			terminal_type = 0;
+		}
+		goto done;
+	}
+	/*
+	 * if the unit is connected to just
+	 * one input terminal, the
+	 * class is UAC_INPUT:
+	 */
+	if (input[0] && (!input[1])) {
+		mix->class = UAC_INPUT;
+		terminal_type = UGETW(input[0]->u.it->wTerminalType);
+		goto done;
+	}
+	/*
+	 * Otherwise, the class is UAC_OUTPUT.
+	 */
+	mix->class = UAC_OUTPUT;
+done:
+	return (terminal_type);
+}
+
 struct uaudio_tt_to_feature {
 	uint16_t terminal_type;
 	uint16_t feature;
@@ -2636,6 +3045,28 @@
 	return (uat->feature);
 }
 
+static uint16_t
+uaudio20_mixer_feature_name(const struct uaudio20_terminal_node *iot,
+    struct uaudio_mixer_node *mix)
+{
+	const struct uaudio_tt_to_feature *uat;
+	uint16_t terminal_type = uaudio20_mixer_determine_class(iot, mix);
+
+	if ((mix->class == UAC_RECORD) && (terminal_type == 0))
+		return (SOUND_MIXER_IMIX);
+	
+	for (uat = uaudio_tt_to_feature; uat->terminal_type != 0; uat++) {
+		if (uat->terminal_type == terminal_type)
+			break;
+	}
+
+	DPRINTF("terminal_type=%s (0x%04x) -> %d\n",
+	    uaudio_mixer_get_terminal_name(terminal_type),
+	    terminal_type, uat->feature);
+
+	return (uat->feature);
+}
+
 static const struct uaudio_terminal_node *
 uaudio_mixer_get_input(const struct uaudio_terminal_node *iot, uint8_t i)
 {
@@ -2653,6 +3084,21 @@
 	return (NULL);
 }
 
+static const struct uaudio20_terminal_node *
+uaudio20_mixer_get_input(const struct uaudio20_terminal_node *iot, uint8_t i)
+{
+	struct uaudio20_terminal_node *root = iot->root;
+	uint8_t n;
+
+	for (n = iot->usr.id_max; n != 0xFFU; n--) {
+		if (iot->usr.bit_input[n / 8] & (1 << (n % 8))) {
+			if (!i--)
+				return (root + n);
+		}
+	}
+	return (NULL);
+}
+
 static const struct uaudio_terminal_node *
 uaudio_mixer_get_output(const struct uaudio_terminal_node *iot, uint8_t i)
 {
@@ -2670,6 +3116,21 @@
 	return (NULL);
 }
 
+static const struct uaudio20_terminal_node *
+uaudio20_mixer_get_output(const struct uaudio20_terminal_node *iot, uint8_t i)
+{
+	struct uaudio20_terminal_node *root = iot->root;
+	uint8_t n;
+
+	for (n = iot->usr.id_max; n != 0xFFU; n--) {
+		if (iot->usr.bit_output[n / 8] & (1 << (n % 8))) {
+			if (!i--)
+				return (root + n);
+		}
+	}
+	return (NULL);
+}
+
 static void
 uaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *root,
     const uint8_t *p_id, uint8_t n_id,
@@ -2749,6 +3210,95 @@
 }
 
 static void
+uaudio20_mixer_find_inputs_sub(struct uaudio20_terminal_node *root,
+    const uint8_t *p_id, uint8_t n_id,
+    struct uaudio_search_result *info)
+{
+	struct uaudio20_terminal_node *iot;
+	uint8_t n;
+	uint8_t i;
+
+	if (info->recurse_level >= UAUDIO_RECURSE_LIMIT)
+		return;
+
+	info->recurse_level++;
+
+	for (n = 0; n < n_id; n++) {
+
+		i = p_id[n];
+
+		if (info->bit_visited[i / 8] & (1 << (i % 8))) {
+			/* don't go into a circle */
+			DPRINTF("avoided going into a circle at id=%d!\n", i);
+			continue;
+		} else {
+			info->bit_visited[i / 8] |= (1 << (i % 8));
+		}
+
+		iot = (root + i);
+
+		if (iot->u.desc == NULL)
+			continue;
+
+		switch (iot->u.desc->bDescriptorSubtype) {
+		case UDESCSUB_AC_INPUT:
+			info->bit_input[i / 8] |= (1 << (i % 8));
+			break;
+
+		case UDESCSUB_AC_OUTPUT:
+			uaudio20_mixer_find_inputs_sub(
+			    root, &iot->u.ot->bSourceId, 1, info);
+			break;
+
+		case UDESCSUB_AC_MIXER:
+			uaudio20_mixer_find_inputs_sub(
+			    root, iot->u.mu->baSourceId,
+			    iot->u.mu->bNrInPins, info);
+			break;
+
+		case UDESCSUB_AC_SELECTOR:
+			uaudio20_mixer_find_inputs_sub(
+			    root, iot->u.su->baSourceId,
+			    iot->u.su->bNrInPins, info);
+			break;
+
+		case UDESCSUB_AC_SAMPLE_RT:
+			uaudio20_mixer_find_inputs_sub(
+			    root, &iot->u.ru->bSourceId,
+			    1, info);
+			break;
+
+		case UDESCSUB_AC_EFFECT:
+			uaudio20_mixer_find_inputs_sub(
+			    root, &iot->u.ef->bSourceId,
+			    1, info);
+			break;
+
+		case UDESCSUB_AC_FEATURE:
+			uaudio20_mixer_find_inputs_sub(
+			    root, &iot->u.fu->bSourceId, 1, info);
+			break;
+
+		case UDESCSUB_AC_PROCESSING_V2:
+			uaudio20_mixer_find_inputs_sub(
+			    root, iot->u.pu->baSourceId,
+			    iot->u.pu->bNrInPins, info);
+			break;
+
+		case UDESCSUB_AC_EXTENSION_V2:
+			uaudio20_mixer_find_inputs_sub(
+			    root, iot->u.eu->baSourceId,
+			    iot->u.eu->bNrInPins, info);
+			break;
+		default:
+			break;
+		}
+	}
+	info->recurse_level--;
+}
+
+
+static void
 uaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *root, uint8_t id,
     uint8_t n_id, struct uaudio_search_result *info)
 {
@@ -2774,6 +3324,33 @@
 }
 
 static void
+uaudio20_mixer_find_outputs_sub(struct uaudio20_terminal_node *root, uint8_t id,
+    uint8_t n_id, struct uaudio_search_result *info)
+{
+	struct uaudio20_terminal_node *iot = (root + id);
+	uint8_t j;
+
+	for (j = n_id; j != 0xFFU; j--) {
+		if ((j != id) && ((root + j)->u.desc) &&
+		    ((root + j)->u.desc->bDescriptorSubtype == UDESCSUB_AC_OUTPUT)) {
+
+			/*
+			 * "j" (output) <--- virtual wire <--- "id" (input)
+			 *
+			 * if "j" has "id" on the input, then "id" have "j" on
+			 * the output, because they are connected:
+			 */
+			if ((root + j)->usr.bit_input[id / 8] & (1 << (id % 8))) {
+				iot->usr.bit_output[j / 8] |= (1 << (j % 8));
+			}
+		}
+	}
+}
+
+extern uint8_t uaudio_mixer_assert[(sizeof(struct uaudio_terminal_node) ==
+    sizeof(struct uaudio20_terminal_node)) ? 1 : -1];
+
+static void
 uaudio_mixer_fill_info(struct uaudio_softc *sc, struct usb_device *udev,
     void *desc)
 {
@@ -2809,7 +3386,8 @@
 	DPRINTFN(3, "found AC header, vers=%03x, len=%d\n",
 	    sc->sc_audio_rev, wTotalLen);
 
-	if (sc->sc_audio_rev != UAUDIO_VERSION) {
+	if (sc->sc_audio_rev != UAUDIO_VERSION &&
+	    sc->sc_audio_rev != UAUDIO_VERSION_20) {
 
 		if (sc->sc_uq_bad_adc) {
 
@@ -2835,7 +3413,10 @@
 			wTotalLen -= dp->bLength;
 		}
 
-		au = uaudio_mixer_verify_desc(dp, 0);
+		if (sc->sc_audio_rev >= UAUDIO_VERSION_20)
+			au = uaudio20_mixer_verify_desc(dp, 0);
+		else
+			au = uaudio_mixer_verify_desc(dp, 0);
 
 		if (au) {
 			iot[au->bUnitId].u.desc = (const void *)au;
@@ -2853,7 +3434,13 @@
 	 */
 	i = ID_max;
 	do {
-		uaudio_mixer_find_inputs_sub(iot, &i, 1, &((iot + i)->usr));
+		if (sc->sc_audio_rev >= UAUDIO_VERSION_20) {
+			uaudio20_mixer_find_inputs_sub((void *)iot,
+			    &i, 1, &((iot + i)->usr));
+		} else {
+			uaudio_mixer_find_inputs_sub(iot,
+			    &i, 1, &((iot + i)->usr));
+		}
 	} while (i--);
 
 	/*
@@ -2862,7 +3449,13 @@
 	 */
 	i = ID_max;
 	do {
-		uaudio_mixer_find_outputs_sub(iot, i, ID_max, &((iot + i)->usr));
+		if (sc->sc_audio_rev >= UAUDIO_VERSION_20) {
+			uaudio20_mixer_find_outputs_sub((void *)iot,
+			    i, ID_max, &((iot + i)->usr));
+		} else {
+			uaudio_mixer_find_outputs_sub(iot,
+			    i, ID_max, &((iot + i)->usr));
+		}
 	} while (i--);
 
 	/* set "id_max" and "root" */
@@ -2873,106 +3466,57 @@
 		(iot + i)->root = iot;
 	} while (i--);
 
-#ifdef USB_DEBUG
+	/*
+	 * Scan the config to create a linked list of "mixer" nodes:
+	 */
+
 	i = ID_max;
 	do {
-		uint8_t j;
+		dp = iot[i].u.desc;
 
-		if (iot[i].u.desc == NULL) {
+		if (dp == NULL)
 			continue;
-		}
-		DPRINTF("id %d:\n", i);
 
-		switch (iot[i].u.desc->bDescriptorSubtype) {
-		case UDESCSUB_AC_INPUT:
-			DPRINTF(" - AC_INPUT type=%s\n",
-			    uaudio_mixer_get_terminal_name
-			    (UGETW(iot[i].u.it->wTerminalType)));
-			uaudio_mixer_dump_cluster(i, iot);
-			break;
+		DPRINTFN(11, "id=%d subtype=%d\n",
+		    i, dp->bDescriptorSubtype);
 
-		case UDESCSUB_AC_OUTPUT:
-			DPRINTF(" - AC_OUTPUT type=%s "
-			    "src=%d\n", uaudio_mixer_get_terminal_name
-			    (UGETW(iot[i].u.ot->wTerminalType)),
-			    iot[i].u.ot->bSourceId);
-			break;
+		if (sc->sc_audio_rev >= UAUDIO_VERSION_20) {
 
-		case UDESCSUB_AC_MIXER:
-			DPRINTF(" - AC_MIXER src:\n");
-			for (j = 0; j < iot[i].u.mu->bNrInPins; j++) {
-				DPRINTF("   - %d\n", iot[i].u.mu->baSourceId[j]);
-			}
-			uaudio_mixer_dump_cluster(i, iot);
-			break;
+			switch (dp->bDescriptorSubtype) {
+			case UDESCSUB_AC_HEADER:
+				DPRINTF("unexpected AC header\n");
+				break;
 
-		case UDESCSUB_AC_SELECTOR:
-			DPRINTF(" - AC_SELECTOR src:\n");
-			for (j = 0; j < iot[i].u.su->bNrInPins; j++) {
-				DPRINTF("   - %d\n", iot[i].u.su->baSourceId[j]);
-			}
-			break;
+			case UDESCSUB_AC_INPUT:
+			case UDESCSUB_AC_OUTPUT:
+			case UDESCSUB_AC_PROCESSING_V2:
+			case UDESCSUB_AC_EXTENSION_V2:
+			case UDESCSUB_AC_EFFECT:
+			case UDESCSUB_AC_CLOCK_SRC:
+			case UDESCSUB_AC_CLOCK_SEL:
+			case UDESCSUB_AC_CLOCK_MUL:
+			case UDESCSUB_AC_SAMPLE_RT:
+				break;
 
-		case UDESCSUB_AC_FEATURE:
-			DPRINTF(" - AC_FEATURE src=%d\n", iot[i].u.fu->bSourceId);
-			break;
+			case UDESCSUB_AC_MIXER:
+				uaudio20_mixer_add_mixer(sc, (void *)iot, i);
+				break;
 
-		case UDESCSUB_AC_PROCESSING:
-			DPRINTF(" - AC_PROCESSING src:\n");
-			for (j = 0; j < iot[i].u.pu->bNrInPins; j++) {
-				DPRINTF("   - %d\n", iot[i].u.pu->baSourceId[j]);
-			}
-			uaudio_mixer_dump_cluster(i, iot);
-			break;
+			case UDESCSUB_AC_SELECTOR:
+				uaudio20_mixer_add_selector(sc, (void *)iot, i);
+				break;
 
-		case UDESCSUB_AC_EXTENSION:
-			DPRINTF(" - AC_EXTENSION src:\n");
-			for (j = 0; j < iot[i].u.eu->bNrInPins; j++) {
-				DPRINTF("%d ", iot[i].u.eu->baSourceId[j]);
-			}
-			uaudio_mixer_dump_cluster(i, iot);
-			break;
+			case UDESCSUB_AC_FEATURE:
+				uaudio20_mixer_add_feature(sc, (void *)iot, i);
+				break;
 
-		default:
-			DPRINTF("unknown audio control (subtype=%d)\n",
-			    iot[i].u.desc->bDescriptorSubtype);
-		}
-
-		DPRINTF("Inputs to this ID are:\n");
-
-		j = ID_max;
-		do {
-			if (iot[i].usr.bit_input[j / 8] & (1 << (j % 8))) {
-				DPRINTF("  -- ID=%d\n", j);
+			default:
+				DPRINTF("bad AC desc subtype=0x%02x\n",
+				    dp->bDescriptorSubtype);
+				break;
 			}
-		} while (j--);
-
-		DPRINTF("Outputs from this ID are:\n");
-
-		j = ID_max;
-		do {
-			if (iot[i].usr.bit_output[j / 8] & (1 << (j % 8))) {
-				DPRINTF("  -- ID=%d\n", j);
-			}
-		} while (j--);
-
-	} while (i--);
-#endif
-
-	/*
-	 * scan the config to create a linked
-	 * list of "mixer" nodes:
-	 */
-
-	i = ID_max;
-	do {
-		dp = iot[i].u.desc;
-
-		if (dp == NULL) {
 			continue;
 		}
-		DPRINTFN(11, "id=%d subtype=%d\n",
-		    i, dp->bDescriptorSubtype);
 
 		switch (dp->bDescriptorSubtype) {
 		case UDESCSUB_AC_HEADER:
@@ -2980,11 +3524,7 @@
 			break;
 
 		case UDESCSUB_AC_INPUT:
-			uaudio_mixer_add_input(sc, iot, i);
-			break;
-
 		case UDESCSUB_AC_OUTPUT:
-			uaudio_mixer_add_output(sc, iot, i);
 			break;
 
 		case UDESCSUB_AC_MIXER:
@@ -3016,9 +3556,7 @@
 	} while (i--);
 
 done:
-	if (iot) {
-		free(iot, M_TEMP);
-	}
+	free(iot, M_TEMP);
 }
 
 static uint16_t
@@ -3031,9 +3569,9 @@
 	uint8_t data[4];
 	usb_error_t err;
 
-	if (mc->wValue[0] == -1) {
+	if (mc->wValue[0] == -1)
 		return (0);
-	}
+
 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
 	req.bRequest = what;
 	USETW(req.wValue, mc->wValue[0]);
@@ -3045,12 +3583,12 @@
 		DPRINTF("err=%s\n", usbd_errstr(err));
 		return (0);
 	}
-	if (len < 1) {
+	if (len < 1)
 		data[0] = 0;
-	}
-	if (len < 2) {
+
+	if (len < 2)
 		data[1] = 0;
-	}
+
 	val = (data[0] | (data[1] << 8));
 
 	DPRINTFN(3, "val=%d\n", val);

--Boundary-00=_sVQRQoKLq20BXa9--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201209032130.52971.hselasky>