From 3c849c59221aec4c3bff5503d3a19dc186f2dfbc Mon Sep 17 00:00:00 2001 From: hselasky Date: Mon, 13 Apr 2020 16:28:15 +0000 Subject: [PATCH] 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 Sponsored by: Mellanox Technologies git-svn-id: svn://svn.freebsd.org/base/stable/10@359881 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/dev/sound/usb/uaudio.c | 643 +++++++++++++++---------------------- 1 file changed, 254 insertions(+), 389 deletions(-) diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c index 03c518698..a4bae3653 100644 --- a/sys/dev/sound/usb/uaudio.c +++ b/sys/dev/sound/usb/uaudio.c @@ -198,7 +198,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]; @@ -459,19 +458,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; @@ -515,10 +501,7 @@ static void uaudio_mixer_add_extension(struct uaudio_softc *, 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); @@ -536,10 +519,7 @@ static void uaudio20_mixer_add_feature(struct uaudio_softc *, 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); @@ -560,12 +540,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 *); @@ -1142,7 +1116,8 @@ uaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_clas 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"); @@ -2966,7 +2941,6 @@ uaudio_mixer_controls_create_ftu(struct uaudio_softc *sc) 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"; @@ -3013,7 +2987,6 @@ uaudio_mixer_controls_create_ftu(struct uaudio_softc *sc) 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"; @@ -3030,7 +3003,6 @@ uaudio_mixer_controls_create_ftu(struct uaudio_softc *sc) 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"; @@ -3047,7 +3019,6 @@ uaudio_mixer_controls_create_ftu(struct uaudio_softc *sc) 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"; @@ -3169,12 +3140,7 @@ uaudio_mixer_add_ctl(struct uaudio_softc *sc, struct uaudio_mixer_node *mc) { 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; @@ -3266,7 +3232,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) @@ -3345,7 +3310,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) @@ -3384,6 +3348,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) @@ -3401,7 +3417,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; @@ -3416,21 +3431,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)); } @@ -3451,7 +3464,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; @@ -3469,17 +3481,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)); } @@ -3540,9 +3551,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]; @@ -3574,7 +3585,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: @@ -3689,7 +3700,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): @@ -3812,7 +3823,6 @@ uaudio_mixer_add_processing_updown(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(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++) { @@ -3846,7 +3856,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)); } @@ -3891,7 +3900,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)); @@ -4321,114 +4329,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]; - - input[0] = uaudio_mixer_get_input(iot, 0); - input[1] = uaudio_mixer_get_input(iot, 1); + uint8_t n; - output[0] = uaudio_mixer_get_output(iot, 0); - output[1] = uaudio_mixer_get_output(iot, 1); + n = *pindex; - /* - * check if there is only - * one output terminal: - */ - if (output[0] && (!output[1])) { - terminal_type = - UGETW(output[0]->u.ot_v1->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_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; + 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; } - /* - * 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]; - - input[0] = uaudio_mixer_get_input(iot, 0); - input[1] = uaudio_mixer_get_input(iot, 1); - - output[0] = uaudio_mixer_get_output(iot, 0); - output[1] = uaudio_mixer_get_output(iot, 1); + uint8_t n; - /* - * 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)) { + n = *pindex; - mix->class = UAC_RECORD; - if (input[0] && (!input[1])) { - terminal_type = - UGETW(input[0]->u.it_v2->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_v2->wTerminalType); - 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; } - /* - * Otherwise, the class is UAC_OUTPUT. - */ - mix->class = UAC_OUTPUT; -done: - return (terminal_type); + *pindex = n; + return (true); } struct uaudio_tt_to_feature { @@ -4438,8 +4374,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}, @@ -4447,11 +4381,6 @@ static const struct uaudio_tt_to_feature uaudio_tt_to_feature[] = { {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}, @@ -4469,63 +4398,21 @@ static const struct uaudio_tt_to_feature uaudio_tt_to_feature[] = { {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: @@ -4534,8 +4421,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) { @@ -4545,65 +4435,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; + + for (i = 0; uaudio_mixer_foreach_input(iot, &i); ) { + ptr = iot->root + i; + temp = UGETW(ptr->u.it_v1->wTerminalType); - if (mix->class == UAC_RECORD && terminal_type == 0) + 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 @@ -4614,9 +4577,7 @@ uaudio_mixer_find_inputs_sub(struct uaudio_terminal_node *root, 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]; @@ -4633,72 +4594,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); @@ -4718,9 +4655,7 @@ uaudio20_mixer_find_inputs_sub(struct uaudio_terminal_node *root, 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]; @@ -4737,94 +4672,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); @@ -4932,31 +4835,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) @@ -5049,16 +4927,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; @@ -5428,24 +5296,22 @@ uaudio_mixer_init(struct uaudio_softc *sc) struct uaudio_mixer_node *mc; int32_t i; - for (mc = sc->sc_mixer_root; mc; - mc = mc->next) { + for (mc = sc->sc_mixer_root; mc; mc = mc->next) { if (mc->ctl != SOUND_MIXER_NRDEVICES) { /* * Set device mask bits. See * /usr/include/machine/soundcard.h */ - sc->sc_mix_info |= (1 << mc->ctl); + sc->sc_mix_info |= 1U << mc->ctl; } if ((mc->ctl == SOUND_MIXER_NRDEVICES) && (mc->type == MIX_SELECTOR)) { for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { - if (mc->slctrtype[i - 1] == SOUND_MIXER_NRDEVICES) { + if (mc->slctrtype[i - 1] == SOUND_MIXER_NRDEVICES) continue; - } - sc->sc_recsrc_info |= 1 << mc->slctrtype[i - 1]; + sc->sc_recsrc_info |= 1U << mc->slctrtype[i - 1]; } } } @@ -5466,7 +5332,9 @@ uaudio_mixer_init_sub(struct uaudio_softc *sc, struct snd_mixer *m) "transfer for audio mixer!\n"); return (ENOMEM); } - if (!(sc->sc_mix_info & SOUND_MASK_VOLUME)) { + + if (sc->sc_play_chan.num_alt > 0 && + (sc->sc_mix_info & SOUND_MASK_VOLUME) == 0) { mix_setparentchild(m, SOUND_MIXER_VOLUME, SOUND_MASK_PCM); mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE); } @@ -5513,8 +5381,7 @@ uaudio_mixer_setrecsrc(struct uaudio_softc *sc, uint32_t src) uint32_t temp; int32_t i; - for (mc = sc->sc_mixer_root; mc; - mc = mc->next) { + for (mc = sc->sc_mixer_root; mc; mc = mc->next) { if ((mc->ctl == SOUND_MIXER_NRDEVICES) && (mc->type == MIX_SELECTOR)) { @@ -5522,14 +5389,13 @@ uaudio_mixer_setrecsrc(struct uaudio_softc *sc, uint32_t src) /* compute selector mask */ mask = 0; - for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { - mask |= (1 << mc->slctrtype[i - 1]); - } + for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) + mask |= 1U << mc->slctrtype[i - 1]; temp = mask & src; - if (temp == 0) { + if (temp == 0) continue; - } + /* find the first set bit */ temp = (-temp) & temp; @@ -5538,9 +5404,8 @@ uaudio_mixer_setrecsrc(struct uaudio_softc *sc, uint32_t src) src |= temp; for (i = mc->minval; (i > 0) && (i <= mc->maxval); i++) { - if (temp != (1 << mc->slctrtype[i - 1])) { + if (temp != (1U << mc->slctrtype[i - 1])) continue; - } uaudio_mixer_ctl_set(sc, mc, 0, i); break; } -- 2.42.0