Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 13 Apr 2020 16:27:06 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r359879 - stable/12/sys/dev/sound/usb
Message-ID:  <202004131627.03DGR6sV087047@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Mon Apr 13 16:27:05 2020
New Revision: 359879
URL: https://svnweb.freebsd.org/changeset/base/359879

Log:
  MFC r359355:
  Improve USB audio mixer support for USB audio class 1 and 2.
  - make sure volume controls are correctly mapped to "pcm" and "rec" depending
    on how they deliver audio to the USB host.
  - make sure there are no duplicate record selections.
  - remove internal only mixer class type.
  - don't add software volume controls for recording only.
  - some minor mixer code cleanup.
  
  Tested by:	Horse Ma <Shichun.Ma@dell.com>
  Sponsored by:	Mellanox Technologies

Modified:
  stable/12/sys/dev/sound/usb/uaudio.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/dev/sound/usb/uaudio.c
==============================================================================
--- stable/12/sys/dev/sound/usb/uaudio.c	Mon Apr 13 16:26:15 2020	(r359878)
+++ stable/12/sys/dev/sound/usb/uaudio.c	Mon Apr 13 16:27:05 2020	(r359879)
@@ -194,7 +194,6 @@ struct uaudio_mixer_node {
 
 #define	MAX_SELECTOR_INPUT_PIN 256
 	uint8_t	slctrtype[MAX_SELECTOR_INPUT_PIN];
-	uint8_t	class;
 	uint8_t val_default;
 
 	uint8_t desc[64];
@@ -455,19 +454,6 @@ static const struct uaudio_format uaudio20_formats[] =
 	{0, 0, 0, NULL}
 };
 
-#define	UAC_OUTPUT	0
-#define	UAC_INPUT	1
-#define	UAC_EQUAL	2
-#define	UAC_RECORD	3
-#define	UAC_NCLASSES	4
-
-#ifdef USB_DEBUG
-static const char *uac_names[] = {
-	"outputs", "inputs", "equalization", "record"
-};
-
-#endif
-
 /* prototypes */
 
 static device_probe_t uaudio_probe;
@@ -511,10 +497,7 @@ static void	uaudio_mixer_add_extension(struct uaudio_s
 		    const struct uaudio_terminal_node *, int);
 static struct	usb_audio_cluster uaudio_mixer_get_cluster(uint8_t,
 		    const struct uaudio_terminal_node *);
-static uint16_t	uaudio_mixer_determine_class(const struct uaudio_terminal_node *,
-		    struct uaudio_mixer_node *);
-static uint16_t	uaudio_mixer_feature_name(const struct uaudio_terminal_node *,
-		    struct uaudio_mixer_node *);
+static uint16_t	uaudio_mixer_determine_class(const struct uaudio_terminal_node *);
 static void	uaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *,
 		    const uint8_t *, uint8_t, struct uaudio_search_result *);
 static const void *uaudio_mixer_verify_desc(const void *, uint32_t);
@@ -532,10 +515,7 @@ static void	uaudio20_mixer_add_feature(struct uaudio_s
 		    const struct uaudio_terminal_node *, int);
 static struct	usb_audio20_cluster uaudio20_mixer_get_cluster(uint8_t,
 		    const struct uaudio_terminal_node *);
-static uint16_t	uaudio20_mixer_determine_class(const struct uaudio_terminal_node *,
-		    struct uaudio_mixer_node *);
-static uint16_t	uaudio20_mixer_feature_name(const struct uaudio_terminal_node *,
-		    struct uaudio_mixer_node *);
+static uint16_t	uaudio20_mixer_determine_class(const struct uaudio_terminal_node *);
 static void	uaudio20_mixer_find_inputs_sub(struct uaudio_terminal_node *,
 		    const uint8_t *, uint8_t, struct uaudio_search_result *);
 static const void *uaudio20_mixer_verify_desc(const void *, uint32_t);
@@ -556,12 +536,6 @@ static void	uaudio_mixer_fill_info(struct uaudio_softc
 		    struct usb_device *, void *);
 static int	uaudio_mixer_signext(uint8_t, int);
 static void	uaudio_mixer_init(struct uaudio_softc *);
-static const struct uaudio_terminal_node *uaudio_mixer_get_input(
-		    const struct uaudio_terminal_node *, uint8_t);
-static const struct uaudio_terminal_node *uaudio_mixer_get_output(
-		    const struct uaudio_terminal_node *, uint8_t);
-static void	uaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *,
-		    uint8_t, uint8_t, struct uaudio_search_result *);
 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 *);
 static void	umidi_start_read(struct usb_fifo *);
@@ -1138,7 +1112,8 @@ uaudio_attach_sub(device_t dev, kobj_class_t mixer_cla
 		DPRINTF("hardware has swapped left and right\n");
 		/* uaudio_pcm_setflags(dev, SD_F_PSWAPLR); */
 	}
-	if (!(sc->sc_mix_info & SOUND_MASK_PCM)) {
+	if (sc->sc_play_chan.num_alt > 0 &&
+	    (sc->sc_mix_info & SOUND_MASK_PCM) == 0) {
 
 		DPRINTF("emulating master volume\n");
 
@@ -2962,7 +2937,6 @@ uaudio_mixer_controls_create_ftu(struct uaudio_softc *
 	memset(&MIX(sc), 0, sizeof(MIX(sc)));
 	MIX(sc).wIndex = MAKE_WORD(6, sc->sc_mixer_iface_no);
 	MIX(sc).wValue[0] = MAKE_WORD(8, 0);
-	MIX(sc).class = UAC_OUTPUT;
 	MIX(sc).type = MIX_UNSIGNED_16;
 	MIX(sc).ctl = SOUND_MIXER_NRDEVICES;
 	MIX(sc).name = "effect";
@@ -3009,7 +2983,6 @@ uaudio_mixer_controls_create_ftu(struct uaudio_softc *
 	memset(&MIX(sc), 0, sizeof(MIX(sc)));
 	MIX(sc).wIndex = MAKE_WORD(6, sc->sc_mixer_iface_no);
 	MIX(sc).wValue[0] = MAKE_WORD(2, 0);
-	MIX(sc).class = UAC_OUTPUT;
 	MIX(sc).type = MIX_SIGNED_8;
 	MIX(sc).ctl = SOUND_MIXER_NRDEVICES;
 	MIX(sc).name = "effect_vol";
@@ -3026,7 +2999,6 @@ uaudio_mixer_controls_create_ftu(struct uaudio_softc *
 	memset(&MIX(sc), 0, sizeof(MIX(sc)));
 	MIX(sc).wIndex = MAKE_WORD(6, sc->sc_mixer_iface_no);
 	MIX(sc).wValue[0] = MAKE_WORD(3, 0);
-	MIX(sc).class = UAC_OUTPUT;
 	MIX(sc).type = MIX_SIGNED_16;
 	MIX(sc).ctl = SOUND_MIXER_NRDEVICES;
 	MIX(sc).name = "effect_dur";
@@ -3043,7 +3015,6 @@ uaudio_mixer_controls_create_ftu(struct uaudio_softc *
 	memset(&MIX(sc), 0, sizeof(MIX(sc)));
 	MIX(sc).wIndex = MAKE_WORD(6, sc->sc_mixer_iface_no);
 	MIX(sc).wValue[0] = MAKE_WORD(4, 0);
-	MIX(sc).class = UAC_OUTPUT;
 	MIX(sc).type = MIX_SIGNED_8;
 	MIX(sc).ctl = SOUND_MIXER_NRDEVICES;
 	MIX(sc).name = "effect_fb";
@@ -3165,12 +3136,7 @@ uaudio_mixer_add_ctl(struct uaudio_softc *sc, struct u
 {
 	int32_t res;
 
-	if (mc->class < UAC_NCLASSES) {
-		DPRINTF("adding %s.%d\n",
-		    uac_names[mc->class], mc->ctl);
-	} else {
-		DPRINTF("adding %d\n", mc->ctl);
-	}
+	DPRINTF("adding %d\n", mc->ctl);
 
 	if (mc->type == MIX_ON_OFF) {
 		mc->minval = 0;
@@ -3262,7 +3228,6 @@ uaudio_mixer_add_mixer(struct uaudio_softc *sc,
 	memset(&MIX(sc), 0, sizeof(MIX(sc)));
 
 	MIX(sc).wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
-	uaudio_mixer_determine_class(&iot[id], &MIX(sc));
 	MIX(sc).type = MIX_SIGNED_16;
 
 	if (uaudio_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL)
@@ -3341,7 +3306,6 @@ uaudio20_mixer_add_mixer(struct uaudio_softc *sc,
 	memset(&MIX(sc), 0, sizeof(MIX(sc)));
 
 	MIX(sc).wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
-	uaudio20_mixer_determine_class(&iot[id], &MIX(sc));
 	MIX(sc).type = MIX_SIGNED_16;
 
 	if (uaudio20_mixer_verify_desc(d0, ((ichs * ochs) + 7) / 8) == NULL)
@@ -3381,6 +3345,58 @@ uaudio20_mixer_add_mixer(struct uaudio_softc *sc,
 }
 
 static void
+uaudio_mixer_check_selectors(struct uaudio_softc *sc)
+{
+	uint8_t reserve_feature[] = {
+	    SOUND_MIXER_LINE,
+	    SOUND_MIXER_LINE1,
+	    SOUND_MIXER_LINE2,
+	    SOUND_MIXER_LINE3,
+	    SOUND_MIXER_DIGITAL1,
+	    SOUND_MIXER_DIGITAL2,
+	    SOUND_MIXER_DIGITAL3,
+	};
+	const uint16_t reserve_max =
+	    sizeof(reserve_feature) / sizeof(reserve_feature[0]);
+	uint16_t i;
+	uint16_t j;
+	uint16_t k;
+
+	/* remove existing selector types from the reserve */	
+	for (i = 0; i < MIX(sc).maxval; i++) {
+		if (MIX(sc).slctrtype[i] == SOUND_MIXER_NRDEVICES)
+			continue;
+		for (j = 0; j != reserve_max; j++) {
+			if (reserve_feature[j] == MIX(sc).slctrtype[i])
+				reserve_feature[j] = SOUND_MIXER_NRDEVICES;
+		}
+	}
+
+	/* make sure selector types are not overlapping */
+	for (i = 0; i < MIX(sc).maxval; i++) {
+		if (MIX(sc).slctrtype[i] == SOUND_MIXER_NRDEVICES)
+			continue;
+		for (j = i + 1; j < MIX(sc).maxval; j++) {
+			if (MIX(sc).slctrtype[j] == SOUND_MIXER_NRDEVICES)
+				continue;
+			if (MIX(sc).slctrtype[i] != MIX(sc).slctrtype[j])
+				continue;
+			for (k = 0; k != reserve_max; k++) {
+				if (reserve_feature[k] == SOUND_MIXER_NRDEVICES)
+					continue;
+				MIX(sc).slctrtype[j] = reserve_feature[k];
+				reserve_feature[k] = SOUND_MIXER_NRDEVICES;
+				break;
+			}
+			if (k == reserve_max) {
+				DPRINTF("Selector type %d is not selectable!\n", j);
+				MIX(sc).slctrtype[j] = SOUND_MIXER_NRDEVICES;
+			}
+		}
+	}
+}
+
+static void
 uaudio_mixer_add_selector(struct uaudio_softc *sc,
     const struct uaudio_terminal_node *iot, int id)
 {
@@ -3397,7 +3413,6 @@ uaudio_mixer_add_selector(struct uaudio_softc *sc,
 
 	MIX(sc).wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no);
 	MIX(sc).wValue[0] = MAKE_WORD(0, 0);
-	uaudio_mixer_determine_class(&iot[id], &MIX(sc));
 	MIX(sc).nchan = 1;
 	MIX(sc).type = MIX_SELECTOR;
 	MIX(sc).ctl = SOUND_MIXER_NRDEVICES;
@@ -3412,21 +3427,19 @@ uaudio_mixer_add_selector(struct uaudio_softc *sc,
 		MIX(sc).desc[0] = 0;
 	}
 
-	if (MIX(sc).maxval > MAX_SELECTOR_INPUT_PIN) {
+	if (MIX(sc).maxval > MAX_SELECTOR_INPUT_PIN)
 		MIX(sc).maxval = MAX_SELECTOR_INPUT_PIN;
-	}
-	MIX(sc).mul = (MIX(sc).maxval - MIX(sc).minval);
-	for (i = 0; i < MAX_SELECTOR_INPUT_PIN; i++) {
-		MIX(sc).slctrtype[i] = SOUND_MIXER_NRDEVICES;
-	}
 
+	MIX(sc).mul = MIX(sc).maxval - MIX(sc).minval;
+
 	for (i = 0; i < MIX(sc).maxval; i++) {
-		MIX(sc).slctrtype[i] = uaudio_mixer_feature_name(
-		    &iot[d->baSourceId[i]], &MIX(sc));
+		MIX(sc).slctrtype[i] =
+		    uaudio_mixer_determine_class(&iot[d->baSourceId[i]]);
 	}
+	for (; i < MAX_SELECTOR_INPUT_PIN; i++)
+		MIX(sc).slctrtype[i] = SOUND_MIXER_NRDEVICES;
 
-	MIX(sc).class = 0;			/* not used */
-
+	uaudio_mixer_check_selectors(sc);
 	uaudio_mixer_add_ctl(sc, &MIX(sc));
 }
 
@@ -3447,7 +3460,6 @@ uaudio20_mixer_add_selector(struct uaudio_softc *sc,
 
 	MIX(sc).wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no);
 	MIX(sc).wValue[0] = MAKE_WORD(0, 0);
-	uaudio20_mixer_determine_class(&iot[id], &MIX(sc));
 	MIX(sc).nchan = 1;
 	MIX(sc).type = MIX_SELECTOR;
 	MIX(sc).ctl = SOUND_MIXER_NRDEVICES;
@@ -3465,17 +3477,16 @@ uaudio20_mixer_add_selector(struct uaudio_softc *sc,
 	if (MIX(sc).maxval > MAX_SELECTOR_INPUT_PIN)
 		MIX(sc).maxval = MAX_SELECTOR_INPUT_PIN;
 
-	MIX(sc).mul = (MIX(sc).maxval - MIX(sc).minval);
-	for (i = 0; i < MAX_SELECTOR_INPUT_PIN; i++)
-		MIX(sc).slctrtype[i] = SOUND_MIXER_NRDEVICES;
+	MIX(sc).mul = MIX(sc).maxval - MIX(sc).minval;
 
 	for (i = 0; i < MIX(sc).maxval; i++) {
-		MIX(sc).slctrtype[i] = uaudio20_mixer_feature_name(
-		    &iot[d->baSourceId[i]], &MIX(sc));
+		MIX(sc).slctrtype[i] =
+		    uaudio20_mixer_determine_class(&iot[d->baSourceId[i]]);
 	}
+	for (; i < MAX_SELECTOR_INPUT_PIN; i++)
+		MIX(sc).slctrtype[i] = SOUND_MIXER_NRDEVICES;
 
-	MIX(sc).class = 0;			/* not used */
-
+	uaudio_mixer_check_selectors(sc);
 	uaudio_mixer_add_ctl(sc, &MIX(sc));
 }
 
@@ -3536,9 +3547,9 @@ uaudio_mixer_add_feature(struct uaudio_softc *sc,
 		cmask |= uaudio_mixer_feature_get_bmaControls(d, chan);
 	}
 
-	if (nchan > MIX_MAX_CHAN) {
+	if (nchan > MIX_MAX_CHAN)
 		nchan = MIX_MAX_CHAN;
-	}
+
 	MIX(sc).wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no);
 
 	i = d->bmaControls[d->bControlSize];
@@ -3570,7 +3581,7 @@ uaudio_mixer_add_feature(struct uaudio_softc *sc,
 			continue;
 		}
 
-		mixernumber = uaudio_mixer_feature_name(&iot[id], &MIX(sc));
+		mixernumber = uaudio_mixer_determine_class(&iot[id]);
 
 		switch (ctl) {
 		case MUTE_CONTROL:
@@ -3685,7 +3696,7 @@ uaudio20_mixer_add_feature(struct uaudio_softc *sc,
 
 	for (ctl = 3; ctl != 0; ctl <<= 2) {
 
-		mixernumber = uaudio20_mixer_feature_name(&iot[id], &MIX(sc));
+		mixernumber = uaudio20_mixer_determine_class(&iot[id]);
 
 		switch (ctl) {
 		case (3 << 0):
@@ -3808,7 +3819,6 @@ uaudio_mixer_add_processing_updown(struct uaudio_softc
 	MIX(sc).wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
 	MIX(sc).nchan = 1;
 	MIX(sc).wValue[0] = MAKE_WORD(UD_MODE_SELECT_CONTROL, 0);
-	uaudio_mixer_determine_class(&iot[id], &MIX(sc));
 	MIX(sc).type = MIX_ON_OFF;		/* XXX */
 
 	for (i = 0; i < ud->bNrModes; i++) {
@@ -3842,7 +3852,6 @@ uaudio_mixer_add_processing(struct uaudio_softc *sc,
 		MIX(sc).wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
 		MIX(sc).nchan = 1;
 		MIX(sc).wValue[0] = MAKE_WORD(XX_ENABLE_CONTROL, 0);
-		uaudio_mixer_determine_class(&iot[id], &MIX(sc));
 		MIX(sc).type = MIX_ON_OFF;
 		uaudio_mixer_add_ctl(sc, &MIX(sc));
 	}
@@ -3887,7 +3896,6 @@ uaudio_mixer_add_extension(struct uaudio_softc *sc,
 		MIX(sc).wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
 		MIX(sc).nchan = 1;
 		MIX(sc).wValue[0] = MAKE_WORD(UA_EXT_ENABLE, 0);
-		uaudio_mixer_determine_class(&iot[id], &MIX(sc));
 		MIX(sc).type = MIX_ON_OFF;
 
 		uaudio_mixer_add_ctl(sc, &MIX(sc));
@@ -4317,114 +4325,42 @@ done:
 	return (r);
 }
 
-static uint16_t
-uaudio_mixer_determine_class(const struct uaudio_terminal_node *iot,
-    struct uaudio_mixer_node *mix)
+static bool
+uaudio_mixer_foreach_input(const struct uaudio_terminal_node *iot, uint8_t *pindex)
 {
-	uint16_t terminal_type = 0x0000;
-	const struct uaudio_terminal_node *input[2];
-	const struct uaudio_terminal_node *output[2];
+	uint8_t n;
 
-	input[0] = uaudio_mixer_get_input(iot, 0);
-	input[1] = uaudio_mixer_get_input(iot, 1);
+	n = *pindex;
 
-	output[0] = uaudio_mixer_get_output(iot, 0);
-	output[1] = uaudio_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_v1->wTerminalType);
+	while (1) {
+		if (!n--)
+			n = iot->usr.id_max;
+		if (n == 0)
+			return (false);
+		if (iot->usr.bit_input[n / 8] & (1 << (n % 8)))
+			break;
 	}
-	/*
-	 * 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_v1->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_v1->wTerminalType);
-		goto done;
-	}
-	/*
-	 * Otherwise, the class is UAC_OUTPUT.
-	 */
-	mix->class = UAC_OUTPUT;
-done:
-	return (terminal_type);
+	*pindex = n;
+	return (true);
 }
 
-static uint16_t
-uaudio20_mixer_determine_class(const struct uaudio_terminal_node *iot,
-    struct uaudio_mixer_node *mix)
+static bool
+uaudio_mixer_foreach_output(const struct uaudio_terminal_node *iot, uint8_t *pindex)
 {
-	uint16_t terminal_type = 0x0000;
-	const struct uaudio_terminal_node *input[2];
-	const struct uaudio_terminal_node *output[2];
+	uint8_t n;
 
-	input[0] = uaudio_mixer_get_input(iot, 0);
-	input[1] = uaudio_mixer_get_input(iot, 1);
+	n = *pindex;
 
-	output[0] = uaudio_mixer_get_output(iot, 0);
-	output[1] = uaudio_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_v2->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_v2->wTerminalType);
-		} else {
-			terminal_type = 0;
-		}
-		goto done;
+	while (1) {
+		if (!n--)
+			n = iot->usr.id_max;
+		if (n == 0)
+			return (false);
+		if (iot->usr.bit_output[n / 8] & (1 << (n % 8)))
+			break;
 	}
-	/*
-	 * 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_v2->wTerminalType);
-		goto done;
-	}
-	/*
-	 * Otherwise, the class is UAC_OUTPUT.
-	 */
-	mix->class = UAC_OUTPUT;
-done:
-	return (terminal_type);
+	*pindex = n;
+	return (true);
 }
 
 struct uaudio_tt_to_feature {
@@ -4434,8 +4370,6 @@ struct uaudio_tt_to_feature {
 
 static const struct uaudio_tt_to_feature uaudio_tt_to_feature[] = {
 
-	{UAT_STREAM, SOUND_MIXER_PCM},
-
 	{UATI_MICROPHONE, SOUND_MIXER_MIC},
 	{UATI_DESKMICROPHONE, SOUND_MIXER_MIC},
 	{UATI_PERSONALMICROPHONE, SOUND_MIXER_MIC},
@@ -4443,11 +4377,6 @@ static const struct uaudio_tt_to_feature uaudio_tt_to_
 	{UATI_MICROPHONEARRAY, SOUND_MIXER_MIC},
 	{UATI_PROCMICROPHONEARR, SOUND_MIXER_MIC},
 
-	{UATO_SPEAKER, SOUND_MIXER_SPEAKER},
-	{UATO_DESKTOPSPEAKER, SOUND_MIXER_SPEAKER},
-	{UATO_ROOMSPEAKER, SOUND_MIXER_SPEAKER},
-	{UATO_COMMSPEAKER, SOUND_MIXER_SPEAKER},
-
 	{UATE_ANALOGCONN, SOUND_MIXER_LINE},
 	{UATE_LINECONN, SOUND_MIXER_LINE},
 	{UATE_LEGACYCONN, SOUND_MIXER_LINE},
@@ -4465,63 +4394,21 @@ static const struct uaudio_tt_to_feature uaudio_tt_to_
 	{UATF_DVDAUDIO, SOUND_MIXER_VIDEO},
 	{UATF_TVTUNERAUDIO, SOUND_MIXER_VIDEO},
 
-	/* telephony terminal types */
-	{UATT_UNDEFINED, SOUND_MIXER_PHONEIN},	/* SOUND_MIXER_PHONEOUT */
-	{UATT_PHONELINE, SOUND_MIXER_PHONEIN},	/* SOUND_MIXER_PHONEOUT */
-	{UATT_TELEPHONE, SOUND_MIXER_PHONEIN},	/* SOUND_MIXER_PHONEOUT */
-	{UATT_DOWNLINEPHONE, SOUND_MIXER_PHONEIN},	/* SOUND_MIXER_PHONEOUT */
-
 	{UATF_RADIORECV, SOUND_MIXER_RADIO},
 	{UATF_RADIOXMIT, SOUND_MIXER_RADIO},
 
-	{UAT_UNDEFINED, SOUND_MIXER_VOLUME},
-	{UAT_VENDOR, SOUND_MIXER_VOLUME},
-	{UATI_UNDEFINED, SOUND_MIXER_VOLUME},
-
-	/* output terminal types */
-	{UATO_UNDEFINED, SOUND_MIXER_VOLUME},
-	{UATO_DISPLAYAUDIO, SOUND_MIXER_VOLUME},
-	{UATO_SUBWOOFER, SOUND_MIXER_VOLUME},
-	{UATO_HEADPHONES, SOUND_MIXER_VOLUME},
-
-	/* bidir terminal types */
-	{UATB_UNDEFINED, SOUND_MIXER_VOLUME},
-	{UATB_HANDSET, SOUND_MIXER_VOLUME},
-	{UATB_HEADSET, SOUND_MIXER_VOLUME},
-	{UATB_SPEAKERPHONE, SOUND_MIXER_VOLUME},
-	{UATB_SPEAKERPHONEESUP, SOUND_MIXER_VOLUME},
-	{UATB_SPEAKERPHONEECANC, SOUND_MIXER_VOLUME},
-
-	/* external terminal types */
-	{UATE_UNDEFINED, SOUND_MIXER_VOLUME},
-
-	/* embedded function terminal types */
-	{UATF_UNDEFINED, SOUND_MIXER_VOLUME},
-	{UATF_CALIBNOISE, SOUND_MIXER_VOLUME},
-	{UATF_EQUNOISE, SOUND_MIXER_VOLUME},
-	{UATF_DAT, SOUND_MIXER_VOLUME},
-	{UATF_DCC, SOUND_MIXER_VOLUME},
-	{UATF_MINIDISK, SOUND_MIXER_VOLUME},
-	{UATF_ANALOGTAPE, SOUND_MIXER_VOLUME},
-	{UATF_PHONOGRAPH, SOUND_MIXER_VOLUME},
-	{UATF_VCRAUDIO, SOUND_MIXER_VOLUME},
-	{UATF_SATELLITE, SOUND_MIXER_VOLUME},
-	{UATF_CABLETUNER, SOUND_MIXER_VOLUME},
-	{UATF_DSS, SOUND_MIXER_VOLUME},
-	{UATF_MULTITRACK, SOUND_MIXER_VOLUME},
-	{0xffff, SOUND_MIXER_VOLUME},
-
-	/* end */
-	{}
+	{}	/* END */
 };
 
 static uint16_t
-uaudio_mixer_feature_name_sub(uint16_t terminal_type)
+uaudio_mixer_get_feature_by_tt(uint16_t terminal_type, uint16_t default_type)
 {
 	const struct uaudio_tt_to_feature *uat = uaudio_tt_to_feature;
 	uint16_t retval;
 
-	while (1) {
+	if (terminal_type == 0) {
+		retval = default_type;
+	} else while (1) {
 		if (uat->terminal_type == 0) {
 			switch (terminal_type >> 8) {
 			case UATI_UNDEFINED >> 8:
@@ -4530,8 +4417,11 @@ uaudio_mixer_feature_name_sub(uint16_t terminal_type)
 			case UATO_UNDEFINED >> 8:
 				retval = SOUND_MIXER_PCM;
 				goto done;
+			case UATT_UNDEFINED >> 8:
+				retval = SOUND_MIXER_PHONEIN;
+				goto done;
 			default:
-				retval = SOUND_MIXER_VOLUME;
+				retval = default_type;
 				goto done;
 			}
 		} else if (uat->terminal_type == terminal_type) {
@@ -4541,65 +4431,138 @@ uaudio_mixer_feature_name_sub(uint16_t terminal_type)
 		uat++;
 	}
 done:
-	DPRINTF("terminal_type=0x%04x -> %d\n",
-	    terminal_type, retval);
+	DPRINTF("terminal_type=0x%04x RET=%d DEF=%d\n",
+	    terminal_type, retval, default_type);
 	return (retval);
 }
 
 static uint16_t
-uaudio_mixer_feature_name(const struct uaudio_terminal_node *iot,
-    struct uaudio_mixer_node *mix)
+uaudio_mixer_determine_class(const struct uaudio_terminal_node *iot)
 {
-	uint16_t terminal_type = uaudio_mixer_determine_class(iot, mix);
+	const struct uaudio_terminal_node *ptr;
+	uint16_t terminal_type_input = 0;
+	uint16_t terminal_type_output = 0;
+	uint16_t temp;
+	uint8_t match = 0;
+	uint8_t i;
 
-	if (mix->class == UAC_RECORD && terminal_type == 0)
+	for (i = 0; uaudio_mixer_foreach_input(iot, &i); ) {
+		ptr = iot->root + i;
+		temp = UGETW(ptr->u.it_v1->wTerminalType);
+
+		if (temp == 0)
+			continue;
+		else if (temp == UAT_STREAM)
+			match |= 1;
+		else if ((temp & 0xFF00) != (UAT_UNDEFINED & 0xff00))
+			terminal_type_input = temp;
+	}
+
+	for (i = 0; uaudio_mixer_foreach_output(iot, &i); ) {
+		ptr = iot->root + i;
+		temp = UGETW(ptr->u.ot_v1->wTerminalType);
+
+		if (temp == 0)
+			continue;
+		else if (temp == UAT_STREAM)
+			match |= 2;
+		else if ((temp & 0xFF00) != (UAT_UNDEFINED & 0xff00))
+			terminal_type_output = temp;
+	}
+
+	DPRINTF("MATCH=%d IN=0x%04x OUT=0x%04x\n",
+	    match, terminal_type_input, terminal_type_output);
+
+	switch (match) {
+	case 0:	/* not connected to USB */
+		if (terminal_type_output != 0) {
+			return (uaudio_mixer_get_feature_by_tt(
+			    terminal_type_output, SOUND_MIXER_MONITOR));
+		} else {
+			return (uaudio_mixer_get_feature_by_tt(
+			    terminal_type_input, SOUND_MIXER_MONITOR));
+		}
+	case 3:	/* connected to both USB input and USB output */
 		return (SOUND_MIXER_IMIX);
-	return (uaudio_mixer_feature_name_sub(terminal_type));
+	case 2:	/* connected to USB output */
+		return (uaudio_mixer_get_feature_by_tt(
+		    terminal_type_input, SOUND_MIXER_RECLEV));
+	case 1: /* connected to USB input */
+		return (uaudio_mixer_get_feature_by_tt(
+		    terminal_type_output, SOUND_MIXER_PCM));
+	default:
+		return (SOUND_MIXER_NRDEVICES);
+	}
 }
 
 static uint16_t
-uaudio20_mixer_feature_name(const struct uaudio_terminal_node *iot,
-    struct uaudio_mixer_node *mix)
+uaudio20_mixer_determine_class(const struct uaudio_terminal_node *iot)
 {
-	uint16_t terminal_type = uaudio20_mixer_determine_class(iot, mix);
+	const struct uaudio_terminal_node *ptr;
+	uint16_t terminal_type_input = 0;
+	uint16_t terminal_type_output = 0;
+	uint16_t temp;
+	uint8_t match = 0;
+	uint8_t i;
 
-	if (mix->class == UAC_RECORD && terminal_type == 0)
-		return (SOUND_MIXER_IMIX);
-	return (uaudio_mixer_feature_name_sub(terminal_type));
-}
+	for (i = 0; uaudio_mixer_foreach_input(iot, &i); ) {
+		ptr = iot->root + i;
+		temp = UGETW(ptr->u.it_v2->wTerminalType);
 
-static const struct uaudio_terminal_node *
-uaudio_mixer_get_input(const struct uaudio_terminal_node *iot, uint8_t i)
-{
-	struct uaudio_terminal_node *root = iot->root;
-	uint8_t n;
+		if (temp == 0)
+			continue;
+		else if (temp == UAT_STREAM)
+			match |= 1;
+		else if ((temp & 0xFF00) != (UAT_UNDEFINED & 0xff00))
+			terminal_type_input = temp;
+	}
 
-	n = iot->usr.id_max;
-	do {
-		if (iot->usr.bit_input[n / 8] & (1 << (n % 8))) {
-			if (!i--)
-				return (root + n);
-		}
-	} while (n--);
+	for (i = 0; uaudio_mixer_foreach_output(iot, &i); ) {
+		ptr = iot->root + i;
+		temp = UGETW(ptr->u.ot_v2->wTerminalType);
 
-	return (NULL);
-}
+		if (temp == 0)
+			continue;
+		else if (temp == UAT_STREAM)
+			match |= 2;
+		else if ((temp & 0xFF00) != (UAT_UNDEFINED & 0xff00))
+			terminal_type_output = temp;
+	}
 
-static const struct uaudio_terminal_node *
-uaudio_mixer_get_output(const struct uaudio_terminal_node *iot, uint8_t i)
-{
-	struct uaudio_terminal_node *root = iot->root;
-	uint8_t n;
+	DPRINTF("MATCH=%d IN=0x%04x OUT=0x%04x\n",
+	    match, terminal_type_input, terminal_type_output);
 
-	n = iot->usr.id_max;
-	do {
-		if (iot->usr.bit_output[n / 8] & (1 << (n % 8))) {
-			if (!i--)
-				return (root + n);
+	switch (match) {
+	case 0:	/* not connected to USB */
+		if (terminal_type_output != 0) {
+			return (uaudio_mixer_get_feature_by_tt(
+			    terminal_type_output, SOUND_MIXER_MONITOR));
+		} else {
+			return (uaudio_mixer_get_feature_by_tt(
+			    terminal_type_input, SOUND_MIXER_MONITOR));
 		}
-	} while (n--);
+	case 3:	/* connected to both USB input and USB output */
+		return (SOUND_MIXER_IMIX);
+	case 2:	/* connected to USB output */
+		return (uaudio_mixer_get_feature_by_tt(
+		    terminal_type_input, SOUND_MIXER_RECLEV));
+	case 1: /* connected to USB input */
+		return (uaudio_mixer_get_feature_by_tt(
+		    terminal_type_output, SOUND_MIXER_PCM));
+	default:
+		return (SOUND_MIXER_NRDEVICES);
+	}
+}
 
-	return (NULL);
+static void
+uaudio_mixer_merge_outputs(struct uaudio_search_result *dst,
+    const struct uaudio_search_result *src)
+{
+	const uint8_t max = sizeof(src->bit_output) / sizeof(src->bit_output[0]);
+	uint8_t x;
+
+	for (x = 0; x != max; x++)
+		dst->bit_output[x] |= src->bit_output[x];
 }
 
 static void
@@ -4610,9 +4573,7 @@ uaudio_mixer_find_inputs_sub(struct uaudio_terminal_no
 	struct uaudio_terminal_node *iot;
 	uint8_t n;
 	uint8_t i;
-	uint8_t is_last;
 
-top:
 	for (n = 0; n < n_id; n++) {
 
 		i = p_id[n];
@@ -4629,72 +4590,48 @@ top:
 		if (iot->u.desc == NULL)
 			continue;
 
-		is_last = ((n + 1) == n_id);
-
 		switch (iot->u.desc->bDescriptorSubtype) {
 		case UDESCSUB_AC_INPUT:
+			uaudio_mixer_merge_outputs(&iot->usr, info);
 			info->bit_input[i / 8] |= (1 << (i % 8));
 			break;
 
 		case UDESCSUB_AC_FEATURE:
-			if (is_last) {
-				p_id = &iot->u.fu_v1->bSourceId;
-				n_id = 1;
-				goto top;
-			}
+			uaudio_mixer_merge_outputs(&iot->usr, info);
 			uaudio_mixer_find_inputs_sub(
 			    root, &iot->u.fu_v1->bSourceId, 1, info);
 			break;
 
 		case UDESCSUB_AC_OUTPUT:
-			if (is_last) {
-				p_id = &iot->u.ot_v1->bSourceId;
-				n_id = 1;
-				goto top;
-			}
+			info->bit_output[i / 8] |= (1 << (i % 8));
 			uaudio_mixer_find_inputs_sub(
 			    root, &iot->u.ot_v1->bSourceId, 1, info);
+			info->bit_output[i / 8] &= ~(1 << (i % 8));
 			break;
 
 		case UDESCSUB_AC_MIXER:
-			if (is_last) {
-				p_id = iot->u.mu_v1->baSourceId;
-				n_id = iot->u.mu_v1->bNrInPins;
-				goto top;
-			}
+			uaudio_mixer_merge_outputs(&iot->usr, info);
 			uaudio_mixer_find_inputs_sub(
 			    root, iot->u.mu_v1->baSourceId,
 			    iot->u.mu_v1->bNrInPins, info);
 			break;
 
 		case UDESCSUB_AC_SELECTOR:
-			if (is_last) {
-				p_id = iot->u.su_v1->baSourceId;
-				n_id = iot->u.su_v1->bNrInPins;
-				goto top;
-			}
+			uaudio_mixer_merge_outputs(&iot->usr, info);
 			uaudio_mixer_find_inputs_sub(
 			    root, iot->u.su_v1->baSourceId,
 			    iot->u.su_v1->bNrInPins, info);
 			break;
 
 		case UDESCSUB_AC_PROCESSING:
-			if (is_last) {
-				p_id = iot->u.pu_v1->baSourceId;
-				n_id = iot->u.pu_v1->bNrInPins;
-				goto top;
-			}
+			uaudio_mixer_merge_outputs(&iot->usr, info);
 			uaudio_mixer_find_inputs_sub(
 			    root, iot->u.pu_v1->baSourceId,
 			    iot->u.pu_v1->bNrInPins, info);
 			break;
 
 		case UDESCSUB_AC_EXTENSION:
-			if (is_last) {
-				p_id = iot->u.eu_v1->baSourceId;
-				n_id = iot->u.eu_v1->bNrInPins;
-				goto top;
-			}
+			uaudio_mixer_merge_outputs(&iot->usr, info);
 			uaudio_mixer_find_inputs_sub(
 			    root, iot->u.eu_v1->baSourceId,
 			    iot->u.eu_v1->bNrInPins, info);
@@ -4714,9 +4651,7 @@ uaudio20_mixer_find_inputs_sub(struct uaudio_terminal_
 	struct uaudio_terminal_node *iot;
 	uint8_t n;
 	uint8_t i;
-	uint8_t is_last;
 
-top:
 	for (n = 0; n < n_id; n++) {
 
 		i = p_id[n];
@@ -4733,94 +4668,62 @@ top:
 		if (iot->u.desc == NULL)
 			continue;
 
-		is_last = ((n + 1) == n_id);
-
 		switch (iot->u.desc->bDescriptorSubtype) {
 		case UDESCSUB_AC_INPUT:
+			uaudio_mixer_merge_outputs(&iot->usr, info);
 			info->bit_input[i / 8] |= (1 << (i % 8));
 			break;
 
 		case UDESCSUB_AC_OUTPUT:
-			if (is_last) {
-				p_id = &iot->u.ot_v2->bSourceId;
-				n_id = 1;
-				goto top;
-			}
+			info->bit_output[i / 8] |= (1 << (i % 8));
 			uaudio20_mixer_find_inputs_sub(
 			    root, &iot->u.ot_v2->bSourceId, 1, info);
+			info->bit_output[i / 8] &= ~(1 << (i % 8));
 			break;
 
 		case UDESCSUB_AC_MIXER:
-			if (is_last) {
-				p_id = iot->u.mu_v2->baSourceId;
-				n_id = iot->u.mu_v2->bNrInPins;
-				goto top;
-			}
+			uaudio_mixer_merge_outputs(&iot->usr, info);
 			uaudio20_mixer_find_inputs_sub(
 			    root, iot->u.mu_v2->baSourceId,
 			    iot->u.mu_v2->bNrInPins, info);
 			break;
 
 		case UDESCSUB_AC_SELECTOR:
-			if (is_last) {
-				p_id = iot->u.su_v2->baSourceId;
-				n_id = iot->u.su_v2->bNrInPins;
-				goto top;
-			}
+			uaudio_mixer_merge_outputs(&iot->usr, info);
 			uaudio20_mixer_find_inputs_sub(
 			    root, iot->u.su_v2->baSourceId,
 			    iot->u.su_v2->bNrInPins, info);
 			break;
 
 		case UDESCSUB_AC_SAMPLE_RT:
-			if (is_last) {
-				p_id = &iot->u.ru_v2->bSourceId;
-				n_id = 1;
-				goto top;
-			}
+			uaudio_mixer_merge_outputs(&iot->usr, info);
 			uaudio20_mixer_find_inputs_sub(
 			    root, &iot->u.ru_v2->bSourceId,
 			    1, info);
 			break;
 
 		case UDESCSUB_AC_EFFECT:
-			if (is_last) {
-				p_id = &iot->u.ef_v2->bSourceId;
-				n_id = 1;
-				goto top;
-			}
+			uaudio_mixer_merge_outputs(&iot->usr, info);
 			uaudio20_mixer_find_inputs_sub(
 			    root, &iot->u.ef_v2->bSourceId,
 			    1, info);
 			break;
 
 		case UDESCSUB_AC_FEATURE:
-			if (is_last) {
-				p_id = &iot->u.fu_v2->bSourceId;
-				n_id = 1;
-				goto top;
-			}
+			uaudio_mixer_merge_outputs(&iot->usr, info);
 			uaudio20_mixer_find_inputs_sub(
 			    root, &iot->u.fu_v2->bSourceId, 1, info);
 			break;
 
 		case UDESCSUB_AC_PROCESSING_V2:
-			if (is_last) {
-				p_id = iot->u.pu_v2->baSourceId;
-				n_id = iot->u.pu_v2->bNrInPins;
-				goto top;
-			}
+			uaudio_mixer_merge_outputs(&iot->usr, info);
 			uaudio20_mixer_find_inputs_sub(
 			    root, iot->u.pu_v2->baSourceId,
 			    iot->u.pu_v2->bNrInPins, info);
 			break;
 
 		case UDESCSUB_AC_EXTENSION_V2:
-			if (is_last) {
-				p_id = iot->u.eu_v2->baSourceId;
-				n_id = iot->u.eu_v2->bNrInPins;
-				goto top;
-			}
+			uaudio_mixer_merge_outputs(&iot->usr, info);
 			uaudio20_mixer_find_inputs_sub(
 			    root, iot->u.eu_v2->baSourceId,
 			    iot->u.eu_v2->bNrInPins, info);
@@ -4929,31 +4832,6 @@ top:
 }
 
 static void
-uaudio_mixer_find_outputs_sub(struct uaudio_terminal_node *root, uint8_t id,
-    uint8_t n_id, struct uaudio_search_result *info)
-{
-	struct uaudio_terminal_node *iot = (root + id);
-	uint8_t j;
-
-	j = n_id;
-	do {
-		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));
-			}
-		}
-	} while (j--);
-}
-
-static void
 uaudio_mixer_fill_info(struct uaudio_softc *sc,
     struct usb_device *udev, void *desc)
 {
@@ -5045,16 +4923,6 @@ uaudio_mixer_fill_info(struct uaudio_softc *sc,
 		}
 	} while (i--);
 
-	/*
-	 * determine outputs for
-	 * all nodes in the tree:
-	 */
-	i = ID_max;
-	do {
-		uaudio_mixer_find_outputs_sub(iot,
-		    i, ID_max, &((iot + i)->usr));
-	} while (i--);
-
 	/* set "id_max" and "root" */
 
 	i = ID_max;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



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