aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2020-04-13 16:28:15 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2020-04-13 16:28:15 +0000
commit9d29ca0cc06cb1ef8a03fc5b1033cb67505734be (patch)
treeaa7ab0f609eca43f48a632796711a5b62d7bcf48
parentd72d2a6419c79af8db2a67101cfe2f18bc8020cc (diff)
downloadsrc-9d29ca0cc06cb1ef8a03fc5b1033cb67505734be.tar.gz
src-9d29ca0cc06cb1ef8a03fc5b1033cb67505734be.zip
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
Notes
Notes: svn path=/stable/10/; revision=359881
-rw-r--r--sys/dev/sound/usb/uaudio.c643
1 files changed, 254 insertions, 389 deletions
diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c
index 03c518698a51..a4bae3653b3c 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)
@@ -3385,6 +3349,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);
@@ -4933,31 +4836,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;
}