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

Hi,

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

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

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

Can you see what you get when you load snd_uaudio after applying the attached 
patch + r240078 ?

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

--HPS
=== 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);
_______________________________________________
freebsd-usb@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-usb
To unsubscribe, send any mail to "freebsd-usb-unsubscr...@freebsd.org"

Reply via email to