Author: hselasky
Date: Mon Apr 13 16:27:40 2020
New Revision: 359880
URL: https://svnweb.freebsd.org/changeset/base/359880

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...@dell.com>
  Sponsored by: Mellanox Technologies

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

Modified: stable/11/sys/dev/sound/usb/uaudio.c
==============================================================================
--- stable/11/sys/dev/sound/usb/uaudio.c        Mon Apr 13 16:27:05 2020        
(r359879)
+++ stable/11/sys/dev/sound/usb/uaudio.c        Mon Apr 13 16:27:40 2020        
(r359880)
@@ -192,7 +192,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];
@@ -453,19 +452,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;
@@ -509,10 +495,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);
@@ -530,10 +513,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);
@@ -554,12 +534,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 *);
@@ -1136,7 +1110,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");
 
@@ -2960,7 +2935,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";
@@ -3007,7 +2981,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";
@@ -3024,7 +2997,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";
@@ -3041,7 +3013,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";
@@ -3163,12 +3134,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;
@@ -3260,7 +3226,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)
@@ -3339,7 +3304,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)
@@ -3379,6 +3343,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)
 {
@@ -3395,7 +3411,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;
@@ -3410,21 +3425,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));
 }
 
@@ -3445,7 +3458,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;
@@ -3463,17 +3475,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));
 }
 
@@ -3534,9 +3545,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];
@@ -3568,7 +3579,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:
@@ -3683,7 +3694,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):
@@ -3806,7 +3817,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++) {
@@ -3840,7 +3850,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));
        }
@@ -3885,7 +3894,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));
@@ -4315,114 +4323,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 {
@@ -4432,8 +4368,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},
@@ -4441,11 +4375,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},
@@ -4463,63 +4392,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:
@@ -4528,8 +4415,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) {
@@ -4539,65 +4429,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
@@ -4608,9 +4571,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];
@@ -4627,72 +4588,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);
@@ -4712,9 +4649,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];
@@ -4731,94 +4666,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);
@@ -4927,31 +4830,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)
 {
@@ -5043,16 +4921,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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to