[alsa-devel] [PATCH 0/5] UAC3: Add Selectors and Processing Units.
This patchset is motivated by the addition of Multi Function Processing Units (MFPU) to an UAC3 topology where there could be signal processing algorithims applied to the audio signal.
The MFPUs themself don't provide any useful control, they offer a description of what algorithims it supports and it is for Selector Units to take the bypass control of the dry (unprocessed) signal and the modified one. Moreover, Up/Down mixers may be needed in this topologies to control which outputs of the logical output cluster from the MFPU are to be passed as the final modified audio signal.
These patches add support for Selector Units and Processing units for UAC3 and adds a couple fixes that I found while implemeting them:
1) Defualt naming of the virtual terminals was not accurate due to codes overlap between the three UAC standards. 2) UAC2 parsing of processing units was using UAC1 controls bitmap.
Based on: next-20180711
Jorge Sanjuan (5): ALSA: usb-audio: Add support for Selector Units in UAC3 ALSA: usb-audio: Processing Unit controls parsing in UAC2 ALSA: usb-audio: Add support for Processing Units in UAC3 ALSA: usb-audio: Unify virtual type units type to UAC3 values ALSA: usb-audio: Tidy up logic for Processing Unit min/max values
include/linux/usb/audio-v3.h | 15 +++ include/uapi/linux/usb/audio.h | 49 ++++++++-- sound/usb/mixer.c | 212 +++++++++++++++++++++++++++++++++-------- 3 files changed, 225 insertions(+), 51 deletions(-)
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 --- sound/usb/mixer.c | 54 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 10 deletions(-)
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index ca963e94ec03..a51f2320a3dd 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -940,6 +940,19 @@ static int check_input_term(struct mixer_build *state, int id,
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: return -ENODEV; } @@ -2509,11 +2522,20 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, cval->res = 1; cval->initialized = 1;
- if (state->mixer->protocol == UAC_VERSION_1) + switch (state->mixer->protocol) { + case UAC_VERSION_1: + default: cval->control = 0; - else /* UAC_VERSION_2 */ - cval->control = (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) ? - UAC2_CX_CLOCK_SELECTOR : UAC2_SU_SELECTOR; + break; + case UAC_VERSION_2: + 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); 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)); if (!len) { /* no mapping ? */ + switch (state->mixer->protocol) { + case UAC_VERSION_1: + case UAC_VERSION_2: + default: /* if iSelector is given, use it */ - nameid = uac_selector_unit_iSelector(desc); - if (nameid) - len = snd_usb_copy_string_desc(state->chip, nameid, - kctl->id.name, - sizeof(kctl->id.name)); + nameid = uac_selector_unit_iSelector(desc); + if (nameid) + len = snd_usb_copy_string_desc(state->chip, + nameid, 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 */ if (!len) 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));
/* 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"); else if ((state->oterm.type & 0xff00) == 0x0100) 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); case UAC3_CLOCK_SOURCE: return parse_clock_source_unit(state, unitid, p1); + case UAC3_SELECTOR_UNIT: case UAC3_CLOCK_SELECTOR: return parse_audio_selector_unit(state, unitid, p1); case UAC3_FEATURE_UNIT:
Current support for UAC2 Processing Units does the parsing as one control per bit in the bitmap. However, the UAC2 spec defines the controls as bit pairs where b01 means read-only and b11 means read/write control.
This patch fixes that and uses the helper functions for checking controls readability/writability when the control is defined as bit pairs (UAC2 and UAC3).
Signed-off-by: Jorge Sanjuan jorge.sanjuan@codethink.co.uk --- sound/usb/mixer.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index a51f2320a3dd..bfb3484096a6 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2300,8 +2300,16 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, for (valinfo = info->values; valinfo->control; valinfo++) { __u8 *controls = uac_processing_unit_bmControls(desc, state->mixer->protocol);
- if (!(controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1)))) - continue; + if (state->mixer->protocol == UAC_VERSION_1) { + if (!(controls[valinfo->control / 8] & + (1 << ((valinfo->control % 8) - 1)))) + continue; + } else { /* UAC_VERSION_2/3 */ + if (!uac_v2v3_control_is_readable(controls[valinfo->control / 8], + valinfo->control)) + continue; + } + map = find_map(state->map, unitid, valinfo->control); if (check_ignored_ctl(map)) continue; @@ -2313,6 +2321,11 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, cval->val_type = valinfo->val_type; cval->channels = 1;
+ if (state->mixer->protocol > UAC_VERSION_1 && + !uac_v2v3_control_is_writeable(controls[valinfo->control / 8], + valinfo->control)) + cval->master_readonly = 1; + /* get min/max values */ if (type == UAC_PROCESS_UP_DOWNMIX && cval->control == UAC_UD_MODE_SELECT) { __u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol);
This patch adds support for the Processig Units defined in the UAC3 spec. The main difference with the previous specs is the lack of on/off switches in the controls for these units and the addiction of the new Multi Function Processing Unit.
The current version of the UAC3 spec doesn't define any useful controls for the new Multi Function Processing Unit so no control will get created once this unit is parsed.
Signed-off-by: Jorge Sanjuan jorge.sanjuan@codethink.co.uk --- include/linux/usb/audio-v3.h | 15 +++++++++++++ include/uapi/linux/usb/audio.h | 49 ++++++++++++++++++++++++++++++++-------- sound/usb/mixer.c | 51 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 104 insertions(+), 11 deletions(-)
diff --git a/include/linux/usb/audio-v3.h b/include/linux/usb/audio-v3.h index a710e28b5215..334bfa6dfb47 100644 --- a/include/linux/usb/audio-v3.h +++ b/include/linux/usb/audio-v3.h @@ -387,6 +387,12 @@ struct uac3_interrupt_data_msg { #define UAC3_CONNECTORS 0x0f #define UAC3_POWER_DOMAIN 0x10
+/* A.20 PROCESSING UNIT PROCESS TYPES */ +#define UAC3_PROCESS_UNDEFINED 0x00 +#define UAC3_PROCESS_UP_DOWNMIX 0x01 +#define UAC3_PROCESS_STEREO_EXTENDER 0x02 +#define UAC3_PROCESS_MULTI_FUNCTION 0x03 + /* A.22 AUDIO CLASS-SPECIFIC REQUEST CODES */ /* see audio-v2.h for the rest, which is identical to v2 */ #define UAC3_CS_REQ_INTEN 0x04 @@ -406,6 +412,15 @@ struct uac3_interrupt_data_msg { #define UAC3_TE_OVERFLOW 0x04 #define UAC3_TE_LATENCY 0x05
+/* A.23.10 PROCESSING UNITS CONTROL SELECTROS */ + +/* Up/Down Mixer */ +#define UAC3_UD_MODE_SELECT 0x01 + +/* Stereo Extender */ +#define UAC3_EXT_WIDTH_CONTROL 0x01 + + /* BADD predefined Unit/Terminal values */ #define UAC3_BADD_IT_ID1 1 /* Input Terminal ID1: bTerminalID = 1 */ #define UAC3_BADD_FU_ID2 2 /* Feature Unit ID2: bUnitID = 2 */ diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h index 74e520fb944f..ddc5396800aa 100644 --- a/include/uapi/linux/usb/audio.h +++ b/include/uapi/linux/usb/audio.h @@ -390,33 +390,64 @@ static inline __u8 uac_processing_unit_iChannelNames(struct uac_processing_unit_ static inline __u8 uac_processing_unit_bControlSize(struct uac_processing_unit_descriptor *desc, int protocol) { - return (protocol == UAC_VERSION_1) ? - desc->baSourceID[desc->bNrInPins + 4] : - 2; /* in UAC2, this value is constant */ + switch (protocol) { + case UAC_VERSION_1: + return desc->baSourceID[desc->bNrInPins + 4]; + case UAC_VERSION_2: + return 2; /* in UAC2, this value is constant */ + case UAC_VERSION_3: + return 4; /* in UAC3, this value is constant */ + default: + return 1; + } }
static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_descriptor *desc, int protocol) { - return (protocol == UAC_VERSION_1) ? - &desc->baSourceID[desc->bNrInPins + 5] : - &desc->baSourceID[desc->bNrInPins + 6]; + switch (protocol) { + case UAC_VERSION_1: + return &desc->baSourceID[desc->bNrInPins + 5]; + case UAC_VERSION_2: + return &desc->baSourceID[desc->bNrInPins + 6]; + case UAC_VERSION_3: + return &desc->baSourceID[desc->bNrInPins + 2]; + default: + return NULL; + } }
static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_descriptor *desc, int protocol) { __u8 control_size = uac_processing_unit_bControlSize(desc, protocol); - return *(uac_processing_unit_bmControls(desc, protocol) - + control_size); + + switch (protocol) { + case UAC_VERSION_1: + case UAC_VERSION_2: + default: + return *(uac_processing_unit_bmControls(desc, protocol) + + control_size); + case UAC_VERSION_3: + return 0; /* UAC3 does not have this field */ + } }
static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_descriptor *desc, int protocol) { __u8 control_size = uac_processing_unit_bControlSize(desc, protocol); - return uac_processing_unit_bmControls(desc, protocol) + + switch (protocol) { + case UAC_VERSION_1: + case UAC_VERSION_2: + default: + return uac_processing_unit_bmControls(desc, protocol) + control_size + 1; + case UAC_VERSION_3: + return uac_processing_unit_bmControls(desc, protocol) + + control_size; + } }
/* 4.5.2 Class-Specific AS Interface Descriptor */ diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index bfb3484096a6..39fde49e8749 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -953,6 +953,23 @@ static int check_input_term(struct mixer_build *state, int id,
return 0; } + case UAC3_PROCESSING_UNIT: { + struct uac_processing_unit_descriptor *d = p1; + + if (!d->bNrInPins) + return -EINVAL; + + /* 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: return -ENODEV; } @@ -2180,6 +2197,11 @@ struct procunit_info { struct procunit_value_info *values; };
+static struct procunit_value_info undefined_proc_info[] = { + { 0x00, "Control Undefined", 0 }, + { 0 } +}; + static struct procunit_value_info updown_proc_info[] = { { UAC_UD_ENABLE, "Switch", USB_MIXER_BOOLEAN }, { UAC_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 }, @@ -2228,6 +2250,23 @@ static struct procunit_info procunits[] = { { UAC_PROCESS_DYN_RANGE_COMP, "DCR", dcr_proc_info }, { 0 }, }; + +static struct procunit_value_info uac3_updown_proc_info[] = { + { UAC3_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 }, + { 0 } +}; +static struct procunit_value_info uac3_stereo_ext_proc_info[] = { + { UAC3_EXT_WIDTH_CONTROL, "Width Control", USB_MIXER_U8 }, + { 0 } +}; + +static struct procunit_info uac3_procunits[] = { + { UAC3_PROCESS_UP_DOWNMIX, "Up Down", uac3_updown_proc_info }, + { UAC3_PROCESS_STEREO_EXTENDER, "3D Stereo Extender", uac3_stereo_ext_proc_info }, + { UAC3_PROCESS_MULTI_FUNCTION, "Multi-Function", undefined_proc_info }, + { 0 }, +}; + /* * predefined data for extension units */ @@ -2388,8 +2427,16 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, static int parse_audio_processing_unit(struct mixer_build *state, int unitid, void *raw_desc) { - return build_audio_procunit(state, unitid, raw_desc, - procunits, "Processing Unit"); + switch (state->mixer->protocol) { + case UAC_VERSION_1: + case UAC_VERSION_2: + default: + return build_audio_procunit(state, unitid, raw_desc, + procunits, "Processing Unit"); + case UAC_VERSION_3: + return build_audio_procunit(state, unitid, raw_desc, + uac3_procunits, "Processing Unit"); + } }
static int parse_audio_extension_unit(struct mixer_build *state, int unitid,
The Audio Control interface descriptor subtypes do not match across all the UAC versions. That makes reusability of the "virtual type" (Mixer, Processors, Selectors, etc) terminals difficult. It also makes the mixer get the default names for the virtual terminals wrong due to the overlap.
This patch proposes an unified approach by always using the most comprehensive spec version to define them all (in this case UAC3).
Signed-off-by: Jorge Sanjuan jorge.sanjuan@codethink.co.uk --- sound/usb/mixer.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-)
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 39fde49e8749..87f18cb74ca3 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -675,16 +675,16 @@ static int get_term_name(struct snd_usb_audio *chip, struct usb_audio_term *iter if (term_only) return 0; switch (iterm->type >> 16) { - case UAC_SELECTOR_UNIT: + case UAC3_SELECTOR_UNIT: strcpy(name, "Selector"); return 8; - case UAC1_PROCESSING_UNIT: + case UAC3_PROCESSING_UNIT: strcpy(name, "Process Unit"); return 12; - case UAC1_EXTENSION_UNIT: + case UAC3_EXTENSION_UNIT: strcpy(name, "Ext Unit"); return 8; - case UAC_MIXER_UNIT: + case UAC3_MIXER_UNIT: strcpy(name, "Mixer"); return 5; default: @@ -832,7 +832,7 @@ static int check_input_term(struct mixer_build *state, int id, case UAC_MIXER_UNIT: { struct uac_mixer_unit_descriptor *d = p1;
- term->type = d->bDescriptorSubtype << 16; /* virtual type */ + term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ term->channels = uac_mixer_unit_bNrChannels(d); term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol); term->name = uac_mixer_unit_iMixer(d); @@ -845,15 +845,23 @@ static int check_input_term(struct mixer_build *state, int id, err = check_input_term(state, d->baSourceID[0], term); if (err < 0) return err; - term->type = d->bDescriptorSubtype << 16; /* virtual type */ + term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ term->id = id; term->name = uac_selector_unit_iSelector(d); return 0; } case UAC1_PROCESSING_UNIT: + /* UAC2_EFFECT_UNIT */ + if (protocol == UAC_VERSION_1) + term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ + else /* UAC_VERSION_2 */ + term->type = UAC3_EFFECT_UNIT << 16; /* virtual type */ case UAC1_EXTENSION_UNIT: /* UAC2_PROCESSING_UNIT_V2 */ - /* UAC2_EFFECT_UNIT */ + if (protocol == UAC_VERSION_1 && !term->type) + term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */ + else if (protocol == UAC_VERSION_2 && !term->type) + term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ case UAC2_EXTENSION_UNIT_V2: { struct uac_processing_unit_descriptor *d = p1;
@@ -869,7 +877,9 @@ static int check_input_term(struct mixer_build *state, int id, id = d->baSourceID[0]; break; /* continue to parse */ } - term->type = d->bDescriptorSubtype << 16; /* virtual type */ + if (!term->type) + term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */ + term->channels = uac_processing_unit_bNrChannels(d); term->chconfig = uac_processing_unit_wChannelConfig(d, protocol); term->name = uac_processing_unit_iProcessing(d, protocol); @@ -878,7 +888,7 @@ static int check_input_term(struct mixer_build *state, int id, case UAC2_CLOCK_SOURCE: { struct uac_clock_source_descriptor *d = p1;
- term->type = d->bDescriptorSubtype << 16; /* virtual type */ + term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ term->id = id; term->name = d->iClockSource; return 0; @@ -923,7 +933,7 @@ static int check_input_term(struct mixer_build *state, int id, case UAC3_CLOCK_SOURCE: { struct uac3_clock_source_descriptor *d = p1;
- term->type = d->bDescriptorSubtype << 16; /* virtual type */ + term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ term->id = id; term->name = le16_to_cpu(d->wClockSourceStr); return 0; @@ -936,7 +946,7 @@ static int check_input_term(struct mixer_build *state, int id, return err;
term->channels = err; - term->type = d->bDescriptorSubtype << 16; /* virtual type */ + term->type = UAC3_MIXER_UNIT << 16; /* virtual type */
return 0; } @@ -947,7 +957,7 @@ static int check_input_term(struct mixer_build *state, int id, err = check_input_term(state, d->baSourceID[0], term); if (err < 0) return err; - term->type = d->bDescriptorSubtype << 16; /* virtual type */ + term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ term->id = id; term->name = 0; /* TODO: UAC3 Class-specific strings */
@@ -964,7 +974,7 @@ static int check_input_term(struct mixer_build *state, int id, if (err < 0) return err;
- term->type = d->bDescriptorSubtype << 16; /* virtual type */ + term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ term->id = id; term->name = 0; /* TODO: UAC3 Class-specific strings */
This patch refactors the processing units min/max calculation logic for the mixer controls and fixes an issue where the Mode Select checking of the Up/Down mixers doesn't differentiate between the UAC1 and UAC2 Control Selector (0x02) and the UAC3 one which is different (0x01).
Signed-off-by: Jorge Sanjuan jorge.sanjuan@codethink.co.uk --- sound/usb/mixer.c | 58 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 17 deletions(-)
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 87f18cb74ca3..73e811f86a95 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2376,25 +2376,49 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, cval->master_readonly = 1;
/* get min/max values */ - if (type == UAC_PROCESS_UP_DOWNMIX && cval->control == UAC_UD_MODE_SELECT) { - __u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol); - /* FIXME: hard-coded */ - cval->min = 1; - cval->max = control_spec[0]; - cval->res = 1; - cval->initialized = 1; - } else { - if (type == USB_XU_CLOCK_RATE) { - /* - * E-Mu USB 0404/0202/TrackerPre/0204 - * samplerate control quirk - */ - cval->min = 0; - cval->max = 5; + switch (type) { + case UAC_PROCESS_UP_DOWNMIX: { + bool mode_sel = false; + + switch (state->mixer->protocol) { + case UAC_VERSION_1: + case UAC_VERSION_2: + default: + if (cval->control == UAC_UD_MODE_SELECT) + mode_sel = true; + break; + case UAC_VERSION_3: + if (cval->control == UAC3_UD_MODE_SELECT) + mode_sel = true; + break; + } + + if (mode_sel) { + __u8 *control_spec = uac_processing_unit_specific(desc, + state->mixer->protocol); + cval->min = 1; + cval->max = control_spec[0]; cval->res = 1; cval->initialized = 1; - } else - get_min_max(cval, valinfo->min_value); + break; + } + + get_min_max(cval, valinfo->min_value); + break; + } + case USB_XU_CLOCK_RATE: + /* + * E-Mu USB 0404/0202/TrackerPre/0204 + * samplerate control quirk + */ + cval->min = 0; + cval->max = 5; + cval->res = 1; + cval->initialized = 1; + break; + default: + get_min_max(cval, valinfo->min_value); + break; }
kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
On Wed, 11 Jul 2018 14:37:50 +0200, Jorge Sanjuan wrote:
This patchset is motivated by the addition of Multi Function Processing Units (MFPU) to an UAC3 topology where there could be signal processing algorithims applied to the audio signal.
The MFPUs themself don't provide any useful control, they offer a description of what algorithims it supports and it is for Selector Units to take the bypass control of the dry (unprocessed) signal and the modified one. Moreover, Up/Down mixers may be needed in this topologies to control which outputs of the logical output cluster from the MFPU are to be passed as the final modified audio signal.
These patches add support for Selector Units and Processing units for UAC3 and adds a couple fixes that I found while implemeting them:
- Defualt naming of the virtual terminals was not accurate due to codes overlap between the three UAC standards.
- UAC2 parsing of processing units was using UAC1 controls bitmap.
Based on: next-20180711
Jorge Sanjuan (5): ALSA: usb-audio: Add support for Selector Units in UAC3 ALSA: usb-audio: Processing Unit controls parsing in UAC2 ALSA: usb-audio: Add support for Processing Units in UAC3 ALSA: usb-audio: Unify virtual type units type to UAC3 values ALSA: usb-audio: Tidy up logic for Processing Unit min/max values
Applied all five patches now. Thanks.
Takashi
participants (2)
-
Jorge Sanjuan
-
Takashi Iwai