aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@suse.cz>2004-11-11 13:51:08 +0100
committerJaroslav Kysela <perex@suse.cz>2004-11-11 13:51:08 +0100
commit55fb6aae9066209c9027edfff4868c6af901fe1b (patch)
tree36b19ddb032f74420d6c0b7c49e0f337c59f17cb /sound
parentdcd3942f498a6e4338109da123ee79be6b5a4ced (diff)
downloadhistory-55fb6aae9066209c9027edfff4868c6af901fe1b.tar.gz
[ALSA] fix parsing of mixer unit descriptors
USB generic driver MU descriptor parsing code completely rewritten; the old code confused the number of input audio channel clusters and the number of input channels. Furthermore, check all bmControls bits so that mixer controls are created even if the first output channel doesn't have a control. Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/usb/usbmixer.c59
1 files changed, 40 insertions, 19 deletions
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index 2155a25ad08d5c..f554be7b828f62 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -931,14 +931,14 @@ static int parse_audio_feature_unit(mixer_build_t *state, int unitid, unsigned c
*/
static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc,
- int in_ch, int unitid)
+ int in_pin, int in_ch, int unitid,
+ usb_audio_term_t *iterm)
{
usb_mixer_elem_info_t *cval;
- unsigned int num_ins = desc[4];
- unsigned int num_outs = desc[5 + num_ins];
+ unsigned int input_pins = desc[4];
+ unsigned int num_outs = desc[5 + input_pins];
unsigned int i, len;
snd_kcontrol_t *kctl;
- usb_audio_term_t iterm;
if (check_ignored_ctl(state, unitid, 0))
return;
@@ -947,16 +947,13 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc,
if (! cval)
return;
- if (check_input_term(state, desc[5 + in_ch], &iterm) < 0)
- return;
-
cval->chip = state->chip;
cval->ctrlif = state->ctrlif;
cval->id = unitid;
cval->control = in_ch + 1; /* based on 1 */
cval->val_type = USB_MIXER_S16;
for (i = 0; i < num_outs; i++) {
- if (check_matrix_bitmap(desc + 9 + num_ins, in_ch, i, num_outs)) {
+ if (check_matrix_bitmap(desc + 9 + input_pins, in_ch, i, num_outs)) {
cval->cmask |= (1 << i);
cval->channels++;
}
@@ -975,9 +972,9 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc,
len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name));
if (! len)
- len = get_term_name(state, &iterm, kctl->id.name, sizeof(kctl->id.name), 0);
+ len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0);
if (! len)
- len = sprintf(kctl->id.name, "Mixer Source %d", in_ch);
+ len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1);
strlcat(kctl->id.name + len, " Volume", sizeof(kctl->id.name));
snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n",
@@ -991,20 +988,44 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc,
*/
static int parse_audio_mixer_unit(mixer_build_t *state, int unitid, unsigned char *desc)
{
- int num_ins, num_outs;
- int i, err;
+ usb_audio_term_t iterm;
+ int input_pins, num_ins, num_outs;
+ int pin, ich, err;
- if (desc[0] < 11 || ! (num_ins = desc[4]) || ! (num_outs = desc[5 + num_ins]))
+ if (desc[0] < 11 || ! (input_pins = desc[4]) || ! (num_outs = desc[5 + input_pins])) {
+ snd_printk(KERN_ERR "invalid MIXER UNIT descriptor %d\n", unitid);
return -EINVAL;
+ }
+ /* no bmControls field (e.g. Maya44) -> ignore */
+ if (desc[0] <= 10 + input_pins) {
+ snd_printdd(KERN_INFO "MU %d has no bmControls field\n", unitid);
+ return 0;
+ }
- for (i = 0; i < num_ins; i++) {
- err = parse_audio_unit(state, desc[5 + i]);
+ num_ins = 0;
+ ich = 0;
+ for (pin = 0; pin < input_pins; pin++) {
+ err = parse_audio_unit(state, desc[5 + pin]);
+ if (err < 0)
+ return err;
+ err = check_input_term(state, desc[5 + pin], &iterm);
if (err < 0)
return err;
- /* some devices (e.g. Maya44) omit the bitmap */
- if (desc[0] > 11 &&
- check_matrix_bitmap(desc + 9 + num_ins, i, 0, num_outs))
- build_mixer_unit_ctl(state, desc, i, unitid);
+ num_ins += iterm.channels;
+ for (; ich < num_ins; ++ich) {
+ int och, ich_has_controls = 0;
+
+ for (och = 0; och < num_outs; ++och) {
+ if (check_matrix_bitmap(desc + 9 + input_pins,
+ ich, och, num_outs)) {
+ ich_has_controls = 1;
+ break;
+ }
+ }
+ if (ich_has_controls)
+ build_mixer_unit_ctl(state, desc, pin, ich,
+ unitid, &iterm);
+ }
}
return 0;
}