mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
ALSA: usb-audio: Fix invalid UAC2/3 mixer unit matrix evaluation
The bitmap matrix in the mixer unit descriptor for UAC2 and UAC3 has
rather the size of input-pins x output-pins, while the current
USB-audio driver code wrongly assumes the UAC1 bitmap matrix size,
which is input-channels x output-pins. That is, when input pins have
multiple channels, the column size differs and it leads to the
accesses at a wrong position.
This patch corrects the access of the bitmap matrix for UAC2/UAC3.
For making the code cleaner, split the parser to UAC1 and UAC2/3, too.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: 23caaf19b1 ("ALSA: usb-mixer: Add support for Audio Class v2.0")
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20261007172051.13240-5-tiwai@suse.de
This commit is contained in:
parent
27cee4141c
commit
c01fb2ed90
|
|
@ -2377,7 +2377,7 @@ static bool mixer_bitmap_overflow(struct uac_mixer_unit_descriptor *desc,
|
|||
*/
|
||||
static void build_mixer_unit_ctl(struct mixer_build *state,
|
||||
struct uac_mixer_unit_descriptor *desc,
|
||||
int in_pin, int in_ch, int num_outs,
|
||||
int in_ch, int num_outs,
|
||||
int unitid, struct usb_audio_term *iterm)
|
||||
{
|
||||
struct usb_mixer_elem_info *cval;
|
||||
|
|
@ -2472,34 +2472,13 @@ static int parse_audio_input_terminal(struct mixer_build *state, int unitid,
|
|||
/*
|
||||
* parse a mixer unit
|
||||
*/
|
||||
static int parse_audio_mixer_unit(struct mixer_build *state, int unitid,
|
||||
void *raw_desc)
|
||||
/* UAC1 mixer unit */
|
||||
static int parse_audio_mixer_unit_v1(struct mixer_build *state, int unitid,
|
||||
int input_pins, int num_outs,
|
||||
struct uac_mixer_unit_descriptor *desc)
|
||||
{
|
||||
struct uac_mixer_unit_descriptor *desc = raw_desc;
|
||||
struct usb_audio_term iterm;
|
||||
int input_pins, num_ins, num_outs;
|
||||
int pin, ich, err;
|
||||
|
||||
err = uac_mixer_unit_get_channels(state, desc);
|
||||
if (err < 0) {
|
||||
usb_audio_err(state->chip,
|
||||
"invalid MIXER UNIT descriptor %d\n",
|
||||
unitid);
|
||||
return err;
|
||||
}
|
||||
|
||||
num_outs = err;
|
||||
input_pins = desc->bNrInPins;
|
||||
|
||||
if (state->mixer->protocol == UAC_VERSION_2 ||
|
||||
state->mixer->protocol == UAC_VERSION_3) {
|
||||
if (input_pins * num_outs > 256) {
|
||||
usb_audio_err(state->chip,
|
||||
"invalid channels for MIXER UNIT %d: input=%d, output=%d\n",
|
||||
unitid, input_pins, num_outs);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
int num_ins, pin, ich, och, err;
|
||||
|
||||
num_ins = 0;
|
||||
ich = 0;
|
||||
|
|
@ -2518,25 +2497,90 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid,
|
|||
num_ins, num_outs))
|
||||
break;
|
||||
for (; ich < num_ins; ich++) {
|
||||
int och, ich_has_controls = 0;
|
||||
|
||||
for (och = 0; och < num_outs; och++) {
|
||||
__u8 *c = uac_mixer_unit_bmControls(desc,
|
||||
state->mixer->protocol);
|
||||
|
||||
if (check_matrix_bitmap(c, ich, och, num_outs)) {
|
||||
ich_has_controls = 1;
|
||||
if (check_matrix_bitmap(c, ich, och, num_outs))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ich_has_controls)
|
||||
build_mixer_unit_ctl(state, desc, pin, ich, num_outs,
|
||||
if (och < num_outs)
|
||||
build_mixer_unit_ctl(state, desc, ich, num_outs,
|
||||
unitid, &iterm);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* UAC2/UAC3 mixer unit */
|
||||
static int parse_audio_mixer_unit_v2(struct mixer_build *state, int unitid,
|
||||
int input_pins, int num_outs,
|
||||
struct uac_mixer_unit_descriptor *desc)
|
||||
{
|
||||
struct usb_audio_term iterm;
|
||||
int pin, och, err;
|
||||
|
||||
if (input_pins * num_outs > 256 ||
|
||||
mixer_bitmap_overflow(desc, state->mixer->protocol,
|
||||
input_pins, num_outs)) {
|
||||
usb_audio_err(state->chip,
|
||||
"invalid channels for MIXER UNIT %d: input=%d, output=%d\n",
|
||||
unitid, input_pins, num_outs);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (pin = 0; pin < input_pins; pin++) {
|
||||
err = parse_audio_unit(state, desc->baSourceID[pin]);
|
||||
if (err < 0)
|
||||
continue;
|
||||
if (!num_outs)
|
||||
continue;
|
||||
err = check_input_term(state, desc->baSourceID[pin], &iterm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (och = 0; och < num_outs; och++) {
|
||||
__u8 *c = uac_mixer_unit_bmControls(desc,
|
||||
state->mixer->protocol);
|
||||
|
||||
if (check_matrix_bitmap(c, pin, och, num_outs))
|
||||
break;
|
||||
}
|
||||
if (och < num_outs)
|
||||
build_mixer_unit_ctl(state, desc, pin, num_outs,
|
||||
unitid, &iterm);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_audio_mixer_unit(struct mixer_build *state, int unitid,
|
||||
void *raw_desc)
|
||||
{
|
||||
struct uac_mixer_unit_descriptor *desc = raw_desc;
|
||||
int num_outs;
|
||||
|
||||
num_outs = uac_mixer_unit_get_channels(state, desc);
|
||||
if (num_outs < 0) {
|
||||
usb_audio_err(state->chip,
|
||||
"invalid MIXER UNIT descriptor %d\n",
|
||||
unitid);
|
||||
return num_outs;
|
||||
}
|
||||
|
||||
switch (state->mixer->protocol) {
|
||||
case UAC_VERSION_1:
|
||||
default:
|
||||
return parse_audio_mixer_unit_v1(state, unitid,
|
||||
desc->bNrInPins, num_outs,
|
||||
desc);
|
||||
case UAC_VERSION_2:
|
||||
case UAC_VERSION_3:
|
||||
return parse_audio_mixer_unit_v2(state, unitid,
|
||||
desc->bNrInPins, num_outs,
|
||||
desc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Processing Unit / Extension Unit
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user