Prev: DMAENGINE: driver for the ARM PL080/PL081 PrimeCells
Next: smatch stuff: range checking issues 2.6.35-rc3
From: Takashi Iwai on 15 Jun 2010 07:20 Linus, please pull sound fixes for v2.6.35-rc4 from: git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git for-linus So far, little surprises came for 2.6.35 in the sound area. This one includes only a few USB audio v2-specific fixes, a regression (Oops) fix on 2.6.34, and a quirk fix for Intel Mac. Thanks! Takashi === Alex Murray (1): ALSA: hda - Fix line-in for mb5 model MacBook (Pro) 5,1 / 5,2 Daniel Mack (4): ALSA: usb-audio: add check for faulty clock in parse_audio_format_rates_v2() ALSA: usb-audio: fix control messages for USB_RECIP_INTERFACE ALSA: usb-audio: parse UAC2 sample rate ranges correctly ALSA: usb-audio: fix UAC2 control value queries Takashi Iwai (1): ALSA: hda - Don't check capture source mixer if no ADC is available --- sound/pci/hda/patch_realtek.c | 35 +++++++------- sound/usb/clock.c | 12 +++-- sound/usb/format.c | 104 +++++++++++++++++++++++++++++++++-------- sound/usb/helper.h | 4 ++ sound/usb/mixer.c | 19 ++++++-- 5 files changed, 128 insertions(+), 46 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index fc767b6..f1ce7d7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2619,16 +2619,18 @@ static int alc_build_controls(struct hda_codec *codec) } /* assign Capture Source enums to NID */ - kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); - if (!kctl) - kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); - for (i = 0; kctl && i < kctl->count; i++) { - hda_nid_t *nids = spec->capsrc_nids; - if (!nids) - nids = spec->adc_nids; - err = snd_hda_add_nid(codec, kctl, i, nids[i]); - if (err < 0) - return err; + if (spec->capsrc_nids || spec->adc_nids) { + kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); + if (!kctl) + kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); + for (i = 0; kctl && i < kctl->count; i++) { + hda_nid_t *nids = spec->capsrc_nids; + if (!nids) + nids = spec->adc_nids; + err = snd_hda_add_nid(codec, kctl, i, nids[i]); + if (err < 0) + return err; + } } if (spec->cap_mixer) { const char *kname = kctl ? kctl->id.name : NULL; @@ -6948,7 +6950,7 @@ static struct hda_input_mux mb5_capture_source = { .num_items = 3, .items = { { "Mic", 0x1 }, - { "Line", 0x2 }, + { "Line", 0x7 }, { "CD", 0x4 }, }, }; @@ -7469,8 +7471,8 @@ static struct snd_kcontrol_new alc885_mb5_mixer[] = { HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT), HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT), + HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT), @@ -7853,10 +7855,9 @@ static struct hda_verb alc885_mb5_init_verbs[] = { {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)}, { } }; diff --git a/sound/usb/clock.c b/sound/usb/clock.c index b7aadd6..b585511 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -103,7 +103,8 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), UAC2_CS_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - UAC2_CX_CLOCK_SELECTOR << 8, selector_id << 8, + UAC2_CX_CLOCK_SELECTOR << 8, + snd_usb_ctrl_intf(chip) | (selector_id << 8), &buf, sizeof(buf), 1000); if (ret < 0) @@ -120,7 +121,8 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - UAC2_CS_CONTROL_CLOCK_VALID << 8, source_id << 8, + UAC2_CS_CONTROL_CLOCK_VALID << 8, + snd_usb_ctrl_intf(chip) | (source_id << 8), &data, sizeof(data), 1000); if (err < 0) { @@ -269,7 +271,8 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, data[3] = rate >> 24; if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, - UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8, + UAC2_CS_CONTROL_SAM_FREQ << 8, + snd_usb_ctrl_intf(chip) | (clock << 8), data, sizeof(data), 1000)) < 0) { snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n", dev->devnum, iface, fmt->altsetting, rate); @@ -278,7 +281,8 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8, + UAC2_CS_CONTROL_SAM_FREQ << 8, + snd_usb_ctrl_intf(chip) | (clock << 8), data, sizeof(data), 1000)) < 0) { snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", dev->devnum, iface, fmt->altsetting); diff --git a/sound/usb/format.c b/sound/usb/format.c index 5367cd1..30364ab 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -206,6 +206,60 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof } /* + * Helper function to walk the array of sample rate triplets reported by + * the device. The problem is that we need to parse whole array first to + * get to know how many sample rates we have to expect. + * Then fp->rate_table can be allocated and filled. + */ +static int parse_uac2_sample_rate_range(struct audioformat *fp, int nr_triplets, + const unsigned char *data) +{ + int i, nr_rates = 0; + + fp->rates = fp->rate_min = fp->rate_max = 0; + + for (i = 0; i < nr_triplets; i++) { + int min = combine_quad(&data[2 + 12 * i]); + int max = combine_quad(&data[6 + 12 * i]); + int res = combine_quad(&data[10 + 12 * i]); + int rate; + + if ((max < 0) || (min < 0) || (res < 0) || (max < min)) + continue; + + /* + * for ranges with res == 1, we announce a continuous sample + * rate range, and this function should return 0 for no further + * parsing. + */ + if (res == 1) { + fp->rate_min = min; + fp->rate_max = max; + fp->rates = SNDRV_PCM_RATE_CONTINUOUS; + return 0; + } + + for (rate = min; rate <= max; rate += res) { + if (fp->rate_table) + fp->rate_table[nr_rates] = rate; + if (!fp->rate_min || rate < fp->rate_min) + fp->rate_min = rate; + if (!fp->rate_max || rate > fp->rate_max) + fp->rate_max = rate; + fp->rates |= snd_pcm_rate_to_rate_bit(rate); + + nr_rates++; + + /* avoid endless loop */ + if (res == 0) + break; + } + } + + return nr_rates; +} + +/* * parse the format descriptor and stores the possible sample rates * on the audioformat table (audio class v2). */ @@ -215,13 +269,20 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, { struct usb_device *dev = chip->dev; unsigned char tmp[2], *data; - int i, nr_rates, data_size, ret = 0; + int nr_triplets, data_size, ret = 0; int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fp->clock); + if (clock < 0) { + snd_printk(KERN_ERR "%s(): unable to find clock source (clock %d)\n", + __func__, clock); + goto err; + } + /* get the number of sample rates first by only fetching 2 bytes */ ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8, + UAC2_CS_CONTROL_SAM_FREQ << 8, + snd_usb_ctrl_intf(chip) | (clock << 8), tmp, sizeof(tmp), 1000); if (ret < 0) { @@ -230,8 +291,8 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, goto err; } - nr_rates = (tmp[1] << 8) | tmp[0]; - data_size = 2 + 12 * nr_rates; + nr_triplets = (tmp[1] << 8) | tmp[0]; + data_size = 2 + 12 * nr_triplets; data = kzalloc(data_size, GFP_KERNEL); if (!data) { ret = -ENOMEM; @@ -241,7 +302,8 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, /* now get the full information */ ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8, + UAC2_CS_CONTROL_SAM_FREQ << 8, + snd_usb_ctrl_intf(chip) | (clock << 8), data, data_size, 1000); if (ret < 0) { @@ -251,26 +313,28 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, goto err_free; } - fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); + /* Call the triplet parser, and make sure fp->rate_table is NULL. + * We just use the return value to know how many sample rates we + * will have to deal with. */ + kfree(fp->rate_table); + fp->rate_table = NULL; + fp->nr_rates = parse_uac2_sample_rate_range(fp, nr_triplets, data); + + if (fp->nr_rates == 0) { + /* SNDRV_PCM_RATE_CONTINUOUS */ + ret = 0; + goto err_free; + } + + fp->rate_table = kmalloc(sizeof(int) * fp->nr_rates, GFP_KERNEL); if (!fp->rate_table) { ret = -ENOMEM; goto err_free; } - fp->nr_rates = 0; - fp->rate_min = fp->rate_max = 0; - - for (i = 0; i < nr_rates; i++) { - int rate = combine_quad(&data[2 + 12 * i]); - - fp->rate_table[fp->nr_rates] = rate; - if (!fp->rate_min || rate < fp->rate_min) - fp->rate_min = rate; - if (!fp->rate_max || rate > fp->rate_max) - fp->rate_max = rate; - fp->rates |= snd_pcm_rate_to_rate_bit(rate); - fp->nr_rates++; - } + /* Call the triplet parser again, but this time, fp->rate_table is + * allocated, so the rates will be stored */ + parse_uac2_sample_rate_range(fp, nr_triplets, data); err_free: kfree(data); diff --git a/sound/usb/helper.h b/sound/usb/helper.h index a6b0e51..09bd943 100644 --- a/sound/usb/helper.h +++ b/sound/usb/helper.h @@ -28,5 +28,9 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, #define snd_usb_get_speed(dev) ((dev)->speed) #endif +static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip) +{ + return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber; +} #endif /* __USBAUDIO_HELPER_H */ diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index a060d00..6939d0f 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -297,20 +297,27 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) { - unsigned char buf[14]; /* enough space for one range of 4 bytes */ + unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */ unsigned char *val; - int ret; + int ret, size; __u8 bRequest; - bRequest = (request == UAC_GET_CUR) ? - UAC2_CS_CUR : UAC2_CS_RANGE; + if (request == UAC_GET_CUR) { + bRequest = UAC2_CS_CUR; + size = sizeof(__u16); + } else { + bRequest = UAC2_CS_RANGE; + size = sizeof(buf); + } + + memset(buf, 0, sizeof(buf)); ret = snd_usb_ctl_msg(cval->mixer->chip->dev, usb_rcvctrlpipe(cval->mixer->chip->dev, 0), bRequest, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, cval->mixer->ctrlif | (cval->id << 8), - buf, sizeof(buf), 1000); + buf, size, 1000); if (ret < 0) { snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", @@ -318,6 +325,8 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v return ret; } + /* FIXME: how should we handle multiple triplets here? */ + switch (request) { case UAC_GET_CUR: val = buf; -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo(a)vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/ |