Commit 58ff603b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'sound-3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound fixes from Takashi Iwai:

 - A collection of small ASoC driver fixes (error path fixes, register
   correction, regulator bypass mode fix, etc)

 - A few regression fixes and quirks of HD-audio (wrong page attributes
   for SG-buffer, Poulsbo/Oaktrail controller fix, digital mic fix for
   Acer, etc)

 - A fix for USB-audio UAC2 devices wrt FU length check

* tag 'sound-3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: hda - Fix non-snoop page handling
  ALSA: hda - Enable LPIB delay count for Poulsbo / Oaktrail
  ALSA: hda - fix inverted internal mic on Acer AOA150/ZG5
  ALSA: usb-audio: fix invalid length check for RME and other UAC 2 devices
  ALSA: hda - Add a fixup for Packard-Bell desktop with ALC880
  ASoC: wm_adsp: Release firmware on error
  ASoC: wm_adsp: Use GFP_DMA for things that may be DMAed
  ASoC: arizona: Use actual rather than desired BCLK when calculating LRCLK
  ASoC: wm2200: correct mixer values and text
  ASoC: MAINTAINERS: Update email address.
  ASoC: wm5110: Correct AEC loopback mask
  ASoC: wm5102: Correct AEC loopback mask
  ASoC: dapm: Fix sense of regulator bypass mode
  ASoC: fsl: fix multiple definition of init_module
  ASoC: arizona: Disable free-running mode on FLL1
parents 2e51b231 9ddf1aeb
...@@ -656,29 +656,43 @@ static char *driver_short_names[] = { ...@@ -656,29 +656,43 @@ static char *driver_short_names[] = {
#define get_azx_dev(substream) (substream->runtime->private_data) #define get_azx_dev(substream) (substream->runtime->private_data)
#ifdef CONFIG_X86 #ifdef CONFIG_X86
static void __mark_pages_wc(struct azx *chip, void *addr, size_t size, bool on) static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
{ {
int pages;
if (azx_snoop(chip)) if (azx_snoop(chip))
return; return;
if (addr && size) { if (!dmab || !dmab->area || !dmab->bytes)
int pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; return;
#ifdef CONFIG_SND_DMA_SGBUF
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) {
struct snd_sg_buf *sgbuf = dmab->private_data;
if (on) if (on)
set_memory_wc((unsigned long)addr, pages); set_pages_array_wc(sgbuf->page_table, sgbuf->pages);
else else
set_memory_wb((unsigned long)addr, pages); set_pages_array_wb(sgbuf->page_table, sgbuf->pages);
return;
} }
#endif
pages = (dmab->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
if (on)
set_memory_wc((unsigned long)dmab->area, pages);
else
set_memory_wb((unsigned long)dmab->area, pages);
} }
static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf, static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
bool on) bool on)
{ {
__mark_pages_wc(chip, buf->area, buf->bytes, on); __mark_pages_wc(chip, buf, on);
} }
static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev, static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
struct snd_pcm_runtime *runtime, bool on) struct snd_pcm_substream *substream, bool on)
{ {
if (azx_dev->wc_marked != on) { if (azx_dev->wc_marked != on) {
__mark_pages_wc(chip, runtime->dma_area, runtime->dma_bytes, on); __mark_pages_wc(chip, snd_pcm_get_dma_buf(substream), on);
azx_dev->wc_marked = on; azx_dev->wc_marked = on;
} }
} }
...@@ -689,7 +703,7 @@ static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf, ...@@ -689,7 +703,7 @@ static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
{ {
} }
static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev, static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
struct snd_pcm_runtime *runtime, bool on) struct snd_pcm_substream *substream, bool on)
{ {
} }
#endif #endif
...@@ -1968,11 +1982,10 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -1968,11 +1982,10 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
{ {
struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx *chip = apcm->chip; struct azx *chip = apcm->chip;
struct snd_pcm_runtime *runtime = substream->runtime;
struct azx_dev *azx_dev = get_azx_dev(substream); struct azx_dev *azx_dev = get_azx_dev(substream);
int ret; int ret;
mark_runtime_wc(chip, azx_dev, runtime, false); mark_runtime_wc(chip, azx_dev, substream, false);
azx_dev->bufsize = 0; azx_dev->bufsize = 0;
azx_dev->period_bytes = 0; azx_dev->period_bytes = 0;
azx_dev->format_val = 0; azx_dev->format_val = 0;
...@@ -1980,7 +1993,7 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -1980,7 +1993,7 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
params_buffer_bytes(hw_params)); params_buffer_bytes(hw_params));
if (ret < 0) if (ret < 0)
return ret; return ret;
mark_runtime_wc(chip, azx_dev, runtime, true); mark_runtime_wc(chip, azx_dev, substream, true);
return ret; return ret;
} }
...@@ -1989,7 +2002,6 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) ...@@ -1989,7 +2002,6 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx_dev *azx_dev = get_azx_dev(substream); struct azx_dev *azx_dev = get_azx_dev(substream);
struct azx *chip = apcm->chip; struct azx *chip = apcm->chip;
struct snd_pcm_runtime *runtime = substream->runtime;
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
/* reset BDL address */ /* reset BDL address */
...@@ -2002,7 +2014,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) ...@@ -2002,7 +2014,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
snd_hda_codec_cleanup(apcm->codec, hinfo, substream); snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
mark_runtime_wc(chip, azx_dev, runtime, false); mark_runtime_wc(chip, azx_dev, substream, false);
return snd_pcm_lib_free_pages(substream); return snd_pcm_lib_free_pages(substream);
} }
...@@ -3613,13 +3625,12 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { ...@@ -3613,13 +3625,12 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
/* 5 Series/3400 */ /* 5 Series/3400 */
{ PCI_DEVICE(0x8086, 0x3b56), { PCI_DEVICE(0x8086, 0x3b56),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH }, .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
/* SCH */ /* Poulsbo */
{ PCI_DEVICE(0x8086, 0x811b), { PCI_DEVICE(0x8086, 0x811b),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_LPIB }, /* Poulsbo */ /* Oaktrail */
{ PCI_DEVICE(0x8086, 0x080a), { PCI_DEVICE(0x8086, 0x080a),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_LPIB }, /* Oaktrail */
/* ICH */ /* ICH */
{ PCI_DEVICE(0x8086, 0x2668), { PCI_DEVICE(0x8086, 0x2668),
.driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
......
...@@ -4694,6 +4694,7 @@ static const struct snd_pci_quirk alc880_fixup_tbl[] = { ...@@ -4694,6 +4694,7 @@ static const struct snd_pci_quirk alc880_fixup_tbl[] = {
SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB), SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB),
SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810), SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810),
SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM), SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST),
SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_FIXUP_F1734), SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_FIXUP_F1734),
SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU), SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU),
SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734), SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734),
...@@ -5708,6 +5709,7 @@ static const struct alc_model_fixup alc268_fixup_models[] = { ...@@ -5708,6 +5709,7 @@ static const struct alc_model_fixup alc268_fixup_models[] = {
}; };
static const struct snd_pci_quirk alc268_fixup_tbl[] = { static const struct snd_pci_quirk alc268_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC),
/* below is codec SSID since multiple Toshiba laptops have the /* below is codec SSID since multiple Toshiba laptops have the
* same PCI SSID 1179:ff00 * same PCI SSID 1179:ff00
*/ */
......
...@@ -685,7 +685,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, ...@@ -685,7 +685,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
} }
sr_val = i; sr_val = i;
lrclk = snd_soc_params_to_bclk(params) / params_rate(params); lrclk = rates[bclk] / params_rate(params);
arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n", arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
rates[bclk], rates[bclk] / lrclk); rates[bclk], rates[bclk] / lrclk);
...@@ -1082,6 +1082,9 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, ...@@ -1082,6 +1082,9 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
id, ret); id, ret);
} }
regmap_update_bits(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_FREERUN, 0);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(arizona_init_fll); EXPORT_SYMBOL_GPL(arizona_init_fll);
......
...@@ -1019,8 +1019,6 @@ static const char *wm2200_mixer_texts[] = { ...@@ -1019,8 +1019,6 @@ static const char *wm2200_mixer_texts[] = {
"EQR", "EQR",
"LHPF1", "LHPF1",
"LHPF2", "LHPF2",
"LHPF3",
"LHPF4",
"DSP1.1", "DSP1.1",
"DSP1.2", "DSP1.2",
"DSP1.3", "DSP1.3",
...@@ -1053,7 +1051,6 @@ static int wm2200_mixer_values[] = { ...@@ -1053,7 +1051,6 @@ static int wm2200_mixer_values[] = {
0x25, 0x25,
0x50, /* EQ */ 0x50, /* EQ */
0x51, 0x51,
0x52,
0x60, /* LHPF1 */ 0x60, /* LHPF1 */
0x61, /* LHPF2 */ 0x61, /* LHPF2 */
0x68, /* DSP1 */ 0x68, /* DSP1 */
......
...@@ -896,8 +896,7 @@ static const unsigned int wm5102_aec_loopback_values[] = { ...@@ -896,8 +896,7 @@ static const unsigned int wm5102_aec_loopback_values[] = {
static const struct soc_enum wm5102_aec_loopback = static const struct soc_enum wm5102_aec_loopback =
SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1, SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_SRC_SHIFT, ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
ARIZONA_AEC_LOOPBACK_SRC_MASK,
ARRAY_SIZE(wm5102_aec_loopback_texts), ARRAY_SIZE(wm5102_aec_loopback_texts),
wm5102_aec_loopback_texts, wm5102_aec_loopback_texts,
wm5102_aec_loopback_values); wm5102_aec_loopback_values);
......
...@@ -344,8 +344,7 @@ static const unsigned int wm5110_aec_loopback_values[] = { ...@@ -344,8 +344,7 @@ static const unsigned int wm5110_aec_loopback_values[] = {
static const struct soc_enum wm5110_aec_loopback = static const struct soc_enum wm5110_aec_loopback =
SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1, SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_SRC_SHIFT, ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
ARIZONA_AEC_LOOPBACK_SRC_MASK,
ARRAY_SIZE(wm5110_aec_loopback_texts), ARRAY_SIZE(wm5110_aec_loopback_texts),
wm5110_aec_loopback_texts, wm5110_aec_loopback_texts,
wm5110_aec_loopback_values); wm5110_aec_loopback_values);
......
...@@ -324,7 +324,7 @@ static int wm_adsp_load(struct wm_adsp *dsp) ...@@ -324,7 +324,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
if (reg) { if (reg) {
buf = kmemdup(region->data, le32_to_cpu(region->len), buf = kmemdup(region->data, le32_to_cpu(region->len),
GFP_KERNEL); GFP_KERNEL | GFP_DMA);
if (!buf) { if (!buf) {
adsp_err(dsp, "Out of memory\n"); adsp_err(dsp, "Out of memory\n");
return -ENOMEM; return -ENOMEM;
...@@ -396,7 +396,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) ...@@ -396,7 +396,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
hdr = (void*)&firmware->data[0]; hdr = (void*)&firmware->data[0];
if (memcmp(hdr->magic, "WMDR", 4) != 0) { if (memcmp(hdr->magic, "WMDR", 4) != 0) {
adsp_err(dsp, "%s: invalid magic\n", file); adsp_err(dsp, "%s: invalid magic\n", file);
return -EINVAL; goto out_fw;
} }
adsp_dbg(dsp, "%s: v%d.%d.%d\n", file, adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
...@@ -439,7 +439,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) ...@@ -439,7 +439,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
if (reg) { if (reg) {
buf = kmemdup(blk->data, le32_to_cpu(blk->len), buf = kmemdup(blk->data, le32_to_cpu(blk->len),
GFP_KERNEL); GFP_KERNEL | GFP_DMA);
if (!buf) { if (!buf) {
adsp_err(dsp, "Out of memory\n"); adsp_err(dsp, "Out of memory\n");
return -ENOMEM; return -ENOMEM;
......
...@@ -108,18 +108,13 @@ if SND_IMX_SOC ...@@ -108,18 +108,13 @@ if SND_IMX_SOC
config SND_SOC_IMX_SSI config SND_SOC_IMX_SSI
tristate tristate
config SND_SOC_IMX_PCM
tristate
config SND_SOC_IMX_PCM_FIQ config SND_SOC_IMX_PCM_FIQ
bool tristate
select FIQ select FIQ
select SND_SOC_IMX_PCM
config SND_SOC_IMX_PCM_DMA config SND_SOC_IMX_PCM_DMA
bool tristate
select SND_SOC_DMAENGINE_PCM select SND_SOC_DMAENGINE_PCM
select SND_SOC_IMX_PCM
config SND_SOC_IMX_AUDMUX config SND_SOC_IMX_AUDMUX
tristate tristate
......
...@@ -41,7 +41,10 @@ endif ...@@ -41,7 +41,10 @@ endif
obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o obj-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += snd-soc-imx-pcm-fiq.o
snd-soc-imx-pcm-fiq-y := imx-pcm-fiq.o imx-pcm.o
obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += snd-soc-imx-pcm-dma.o
snd-soc-imx-pcm-dma-y := imx-pcm-dma.o imx-pcm.o
# i.MX Machine Support # i.MX Machine Support
snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
......
...@@ -31,7 +31,6 @@ int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, ...@@ -31,7 +31,6 @@ int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
runtime->dma_bytes); runtime->dma_bytes);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap);
static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{ {
...@@ -80,7 +79,6 @@ int imx_pcm_new(struct snd_soc_pcm_runtime *rtd) ...@@ -80,7 +79,6 @@ int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
out: out:
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(imx_pcm_new);
void imx_pcm_free(struct snd_pcm *pcm) void imx_pcm_free(struct snd_pcm *pcm)
{ {
...@@ -102,7 +100,6 @@ void imx_pcm_free(struct snd_pcm *pcm) ...@@ -102,7 +100,6 @@ void imx_pcm_free(struct snd_pcm *pcm)
buf->area = NULL; buf->area = NULL;
} }
} }
EXPORT_SYMBOL_GPL(imx_pcm_free);
MODULE_DESCRIPTION("Freescale i.MX PCM driver"); MODULE_DESCRIPTION("Freescale i.MX PCM driver");
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
......
...@@ -1023,7 +1023,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, ...@@ -1023,7 +1023,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
if (SND_SOC_DAPM_EVENT_ON(event)) { if (SND_SOC_DAPM_EVENT_ON(event)) {
if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
ret = regulator_allow_bypass(w->regulator, true); ret = regulator_allow_bypass(w->regulator, false);
if (ret != 0) if (ret != 0)
dev_warn(w->dapm->dev, dev_warn(w->dapm->dev,
"ASoC: Failed to bypass %s: %d\n", "ASoC: Failed to bypass %s: %d\n",
...@@ -1033,7 +1033,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, ...@@ -1033,7 +1033,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
return regulator_enable(w->regulator); return regulator_enable(w->regulator);
} else { } else {
if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
ret = regulator_allow_bypass(w->regulator, false); ret = regulator_allow_bypass(w->regulator, true);
if (ret != 0) if (ret != 0)
dev_warn(w->dapm->dev, dev_warn(w->dapm->dev,
"ASoC: Failed to unbypass %s: %d\n", "ASoC: Failed to unbypass %s: %d\n",
...@@ -3039,6 +3039,14 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, ...@@ -3039,6 +3039,14 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
w->name, ret); w->name, ret);
return NULL; return NULL;
} }
if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
ret = regulator_allow_bypass(w->regulator, true);
if (ret != 0)
dev_warn(w->dapm->dev,
"ASoC: Failed to unbypass %s: %d\n",
w->name, ret);
}
break; break;
case snd_soc_dapm_clock_supply: case snd_soc_dapm_clock_supply:
#ifdef CONFIG_CLKDEV_LOOKUP #ifdef CONFIG_CLKDEV_LOOKUP
......
...@@ -1331,16 +1331,23 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void ...@@ -1331,16 +1331,23 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
} }
channels = (hdr->bLength - 7) / csize - 1; channels = (hdr->bLength - 7) / csize - 1;
bmaControls = hdr->bmaControls; bmaControls = hdr->bmaControls;
if (hdr->bLength < 7 + csize) {
snd_printk(KERN_ERR "usbaudio: unit %u: "
"invalid UAC_FEATURE_UNIT descriptor\n",
unitid);
return -EINVAL;
}
} else { } else {
struct uac2_feature_unit_descriptor *ftr = _ftr; struct uac2_feature_unit_descriptor *ftr = _ftr;
csize = 4; csize = 4;
channels = (hdr->bLength - 6) / 4 - 1; channels = (hdr->bLength - 6) / 4 - 1;
bmaControls = ftr->bmaControls; bmaControls = ftr->bmaControls;
} if (hdr->bLength < 6 + csize) {
snd_printk(KERN_ERR "usbaudio: unit %u: "
if (hdr->bLength < 7 || !csize || hdr->bLength < 7 + csize) { "invalid UAC_FEATURE_UNIT descriptor\n",
snd_printk(KERN_ERR "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n", unitid); unitid);
return -EINVAL; return -EINVAL;
}
} }
/* parse the source unit */ /* parse the source unit */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment