ALSA: usb-audio: Add support for Selector Units in UAC3

This patch add support for Selector Units and Clock Selector Units
defined in the new UAC3 spec.

Selector Units play a really important role in the new UAC3 spec as
Processing Units do not define an on/off switch control anymore.
This forces topology designers to add bypass paths in the topology
to enable/dissable the Processing Units.

Signed-off-by: Jorge Sanjuan <jorge.sanjuan@codethink.co.uk>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Jorge Sanjuan 2018-07-11 13:37:51 +01:00 committed by Takashi Iwai
parent d6e08c7eab
commit c77e1ef1cd

View File

@ -940,6 +940,19 @@ static int check_input_term(struct mixer_build *state, int id,
return 0; return 0;
} }
case UAC3_SELECTOR_UNIT:
case UAC3_CLOCK_SELECTOR: {
struct uac_selector_unit_descriptor *d = p1;
/* call recursively to retrieve the channel info */
err = check_input_term(state, d->baSourceID[0], term);
if (err < 0)
return err;
term->type = d->bDescriptorSubtype << 16; /* virtual type */
term->id = id;
term->name = 0; /* TODO: UAC3 Class-specific strings */
return 0;
}
default: default:
return -ENODEV; return -ENODEV;
} }
@ -2509,11 +2522,20 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
cval->res = 1; cval->res = 1;
cval->initialized = 1; cval->initialized = 1;
if (state->mixer->protocol == UAC_VERSION_1) switch (state->mixer->protocol) {
case UAC_VERSION_1:
default:
cval->control = 0; cval->control = 0;
else /* UAC_VERSION_2 */ break;
cval->control = (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) ? case UAC_VERSION_2:
UAC2_CX_CLOCK_SELECTOR : UAC2_SU_SELECTOR; case UAC_VERSION_3:
if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR ||
desc->bDescriptorSubtype == UAC3_CLOCK_SELECTOR)
cval->control = UAC2_CX_CLOCK_SELECTOR;
else /* UAC2/3_SELECTOR_UNIT */
cval->control = UAC2_SU_SELECTOR;
break;
}
namelist = kmalloc_array(desc->bNrInPins, sizeof(char *), GFP_KERNEL); namelist = kmalloc_array(desc->bNrInPins, sizeof(char *), GFP_KERNEL);
if (!namelist) { if (!namelist) {
@ -2555,12 +2577,22 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
if (!len) { if (!len) {
/* no mapping ? */ /* no mapping ? */
switch (state->mixer->protocol) {
case UAC_VERSION_1:
case UAC_VERSION_2:
default:
/* if iSelector is given, use it */ /* if iSelector is given, use it */
nameid = uac_selector_unit_iSelector(desc); nameid = uac_selector_unit_iSelector(desc);
if (nameid) if (nameid)
len = snd_usb_copy_string_desc(state->chip, nameid, len = snd_usb_copy_string_desc(state->chip,
kctl->id.name, nameid, kctl->id.name,
sizeof(kctl->id.name)); sizeof(kctl->id.name));
break;
case UAC_VERSION_3:
/* TODO: Class-Specific strings not yet supported */
break;
}
/* ... or pick up the terminal name at next */ /* ... or pick up the terminal name at next */
if (!len) if (!len)
len = get_term_name(state->chip, &state->oterm, len = get_term_name(state->chip, &state->oterm,
@ -2570,7 +2602,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));
/* and add the proper suffix */ /* and add the proper suffix */
if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR ||
desc->bDescriptorSubtype == UAC3_CLOCK_SELECTOR)
append_ctl_name(kctl, " Clock Source"); append_ctl_name(kctl, " Clock Source");
else if ((state->oterm.type & 0xff00) == 0x0100) else if ((state->oterm.type & 0xff00) == 0x0100)
append_ctl_name(kctl, " Capture Source"); append_ctl_name(kctl, " Capture Source");
@ -2641,6 +2674,7 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
return parse_audio_mixer_unit(state, unitid, p1); return parse_audio_mixer_unit(state, unitid, p1);
case UAC3_CLOCK_SOURCE: case UAC3_CLOCK_SOURCE:
return parse_clock_source_unit(state, unitid, p1); return parse_clock_source_unit(state, unitid, p1);
case UAC3_SELECTOR_UNIT:
case UAC3_CLOCK_SELECTOR: case UAC3_CLOCK_SELECTOR:
return parse_audio_selector_unit(state, unitid, p1); return parse_audio_selector_unit(state, unitid, p1);
case UAC3_FEATURE_UNIT: case UAC3_FEATURE_UNIT: