From 07ac2296fb24e40ba8271a08167b588f4bbbe90c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 4 Oct 2012 14:15:02 +0300 Subject: ASoC: twl6040: Fix Stream DAPM mapping Fixes commit: 805238b ASoC: twl6040: Convert to use DAI DAPM widgets where the connection between the stream widgets and the ADC widgets was reversed and because of this on capture the DAPM is not powering up the codec. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl6040.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index e8f97af75928..00b85cc1b9a3 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -820,10 +820,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"VIBRA DAC", NULL, "Vibra Playback"}, /* ADC -> Stream mapping */ - {"ADC Left", NULL, "Legacy Capture"}, - {"ADC Left", NULL, "Capture"}, - {"ADC Right", NULL, "Legacy Capture"}, - {"ADC Right", NULL, "Capture"}, + {"Legacy Capture" , NULL, "ADC Left"}, + {"Capture", NULL, "ADC Left"}, + {"Legacy Capture", NULL, "ADC Right"}, + {"Capture" , NULL, "ADC Right"}, /* Capture path */ {"Analog Left Capture Route", "Headset Mic", "HSMIC"}, -- cgit v1.2.3 From 034940a6b3afbe79022ab6922dd9d2982b78e6d5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Oct 2012 15:31:16 +0300 Subject: ASoC: omap-abe-twl6040: Fix typo of Vibrator It is not Vinrator but Vibrator. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-abe-twl6040.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index be525dfe9faa..750d595d01d7 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -220,7 +220,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); - twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator"); + twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vibrator"); twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); -- cgit v1.2.3 From 07b706dc9e92f030cfca330879aa8b7ecbb7b79a Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 4 Oct 2012 11:27:15 +0300 Subject: ASoC: Fix wrong include for McPDM McPDM needs platt/cpu.h for omap_rev and not omap_hwmod.h. Drivers must not include omap_hwmod.h at, it will be private to mach-omap2 soon. Fix the problem before other drivers will also start including omap_hwmod.h. Note that also plat/cpu.h will be going away, so the omap_rev check needs to be replaced with mcpdm-watchdog flag from platform_data or DT. Signed-off-by: Tony Lindgren Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcpdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 775565032ce3..fdf655e3f1b3 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -40,7 +40,7 @@ #include #include -#include +#include #include "omap-mcpdm.h" #include "omap-pcm.h" -- cgit v1.2.3 From 68214d998a2e3102854cf10ebe505243035702fc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 4 Oct 2012 11:27:16 +0300 Subject: ASoC: omap-mcpdm: Remove OMAP revision check The OMAP revision check is not needed since the watchdog bit is not in use on 4430 ES1.0 and have no effect when we set the bit. The watchdog need to be enabled on all other revisions. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcpdm.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index fdf655e3f1b3..e134b271a70a 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -40,7 +40,6 @@ #include #include -#include #include "omap-mcpdm.h" #include "omap-pcm.h" @@ -258,13 +257,9 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream, mutex_lock(&mcpdm->mutex); if (!dai->active) { - /* Enable watch dog for ES above ES 1.0 to avoid saturation */ - if (omap_rev() != OMAP4430_REV_ES1_0) { - u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); + u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); - omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, - ctrl | MCPDM_WD_EN); - } + omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN); omap_mcpdm_open_streams(mcpdm); } mutex_unlock(&mcpdm->mutex); -- cgit v1.2.3 From b764de2d8bafff3a52aa6ee66cedf435486974f4 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Wed, 3 Oct 2012 12:46:57 +0200 Subject: ASoC: ams-delta: Convert to use snd_soc_register_card() The old method of registering with the ASoC core by creating a "soc-audio" platform device no longer works for Amstrad Delta sound card after recent changes to drvdata handling (commit 0998d0631001288a5974afc0b2a5f568bcdecb4d, 'device-core: Ensure drvdata = NULL when no driver is bound'. Use snd_soc_register_card() method instead, as suggested by the ASoC core generated warning message, and move both the card and codec platform device registration to the arch board file where those belong. Created and tested against linux-3.6-rc5. Signed-off-by: Janusz Krzysztofik Acked-by: Tony Lindgren Signed-off-by: Mark Brown --- sound/soc/omap/ams-delta.c | 63 ++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 7d4fa8ed6699..7b18b748c177 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -575,56 +575,53 @@ static struct snd_soc_card ams_delta_audio_card = { }; /* Module init/exit */ -static struct platform_device *ams_delta_audio_platform_device; -static struct platform_device *cx20442_platform_device; - -static int __init ams_delta_module_init(void) +static __devinit int ams_delta_probe(struct platform_device *pdev) { + struct snd_soc_card *card = &ams_delta_audio_card; int ret; - if (!(machine_is_ams_delta())) - return -ENODEV; - - ams_delta_audio_platform_device = - platform_device_alloc("soc-audio", -1); - if (!ams_delta_audio_platform_device) - return -ENOMEM; + card->dev = &pdev->dev; - platform_set_drvdata(ams_delta_audio_platform_device, - &ams_delta_audio_card); - - ret = platform_device_add(ams_delta_audio_platform_device); - if (ret) - goto err; - - /* - * Codec platform device could be registered from elsewhere (board?), - * but I do it here as it makes sense only if used with the card. - */ - cx20442_platform_device = - platform_device_register_simple("cx20442-codec", -1, NULL, 0); + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + card->dev = NULL; + return ret; + } return 0; -err: - platform_device_put(ams_delta_audio_platform_device); - return ret; } -late_initcall(ams_delta_module_init); -static void __exit ams_delta_module_exit(void) +static int __devexit ams_delta_remove(struct platform_device *pdev) { + struct snd_soc_card *card = platform_get_drvdata(pdev); + if (tty_unregister_ldisc(N_V253) != 0) - dev_warn(&ams_delta_audio_platform_device->dev, + dev_warn(&pdev->dev, "failed to unregister V253 line discipline\n"); snd_soc_jack_free_gpios(&ams_delta_hook_switch, ARRAY_SIZE(ams_delta_hook_switch_gpios), ams_delta_hook_switch_gpios); - platform_device_unregister(cx20442_platform_device); - platform_device_unregister(ams_delta_audio_platform_device); + snd_soc_unregister_card(card); + card->dev = NULL; + return 0; } -module_exit(ams_delta_module_exit); + +#define DRV_NAME "ams-delta-audio" + +static struct platform_driver ams_delta_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ams_delta_probe, + .remove = __devexit_p(ams_delta_remove), +}; + +module_platform_driver(ams_delta_driver); MODULE_AUTHOR("Janusz Krzysztofik "); MODULE_DESCRIPTION("ALSA SoC driver for Amstrad E3 (Delta) videophone"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); -- cgit v1.2.3 From eac77839f9707c4813344bef64e8b62d128236dd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 26 Sep 2012 16:22:32 +0100 Subject: ASoC: bells: Correct typo in sub speaker DAI name for WM5110 Signed-off-by: Mark Brown --- sound/soc/samsung/bells.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c index 5dc10dfc0d42..a2ca1567b9e4 100644 --- a/sound/soc/samsung/bells.c +++ b/sound/soc/samsung/bells.c @@ -247,7 +247,7 @@ static struct snd_soc_dai_link bells_dai_wm5110[] = { { .name = "Sub", .stream_name = "Sub", - .cpu_dai_name = "wm5102-aif3", + .cpu_dai_name = "wm5110-aif3", .codec_dai_name = "wm9081-hifi", .codec_name = "wm9081.1-006c", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF -- cgit v1.2.3 From 5ae9eb4cbdfd640269dbd66aa3c92ea8e11cc838 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Oct 2012 12:02:48 +0100 Subject: ASoC: wm2200: Use rev A register patches on rev B Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/wm2200.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index efa93dbb0191..2008b7b533bb 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2091,6 +2091,7 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, switch (wm2200->rev) { case 0: + case 1: ret = regmap_register_patch(wm2200->regmap, wm2200_reva_patch, ARRAY_SIZE(wm2200_reva_patch)); if (ret != 0) { -- cgit v1.2.3 From a1b98e12b7f8fad2f0aa3c08a3302bcac7ae1ec7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Oct 2012 19:10:43 +0100 Subject: ASoC: wm2200: Fix non-inverted OUT2 mute control Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/wm2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 2008b7b533bb..eab64a193989 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1028,7 +1028,7 @@ SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L, WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_VOL_SHIFT, 0x9f, 0, digital_tlv), SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT, - WM2200_SPK1R_MUTE_SHIFT, 1, 0), + WM2200_SPK1R_MUTE_SHIFT, 1, 1), }; WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE); -- cgit v1.2.3 From ca057410a8ea88ffb3ce6a581377cffa71ac01c6 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Sat, 6 Oct 2012 07:38:16 -0400 Subject: ARM: pxa: Fix build error caused by sram.h rename Commit 293b2da1b61 ("ARM: pxa: move platform_data definitions") renamed arch/arm/mach-mmp/include/mach/sram.h to include/linux/platform_data/dma-mmp_tdma.h, but didn't update mmp-pcm.c which uses the header. Fix the build error. Signed-off-by: Chris Ball Acked-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/pxa/mmp-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c index 73ac5463c9e4..e834faf859fd 100644 --- a/sound/soc/pxa/mmp-pcm.c +++ b/sound/soc/pxa/mmp-pcm.c @@ -15,13 +15,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include struct mmp_dma_data { -- cgit v1.2.3 From a92b078eab17d09ac600446954d8b0d7998c6168 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Tue, 2 Oct 2012 14:08:19 +0200 Subject: ASoC: fix documentation in soc-jack Signed-off-by: Peter Meerwald Signed-off-by: Mark Brown --- sound/soc/soc-jack.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index fa0fd8ddae90..1ab5fe04bfcc 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -22,7 +22,7 @@ /** * snd_soc_jack_new - Create a new jack - * @card: ASoC card + * @codec: ASoC codec * @id: an identifying string for this jack * @type: a bitmask of enum snd_jack_type values that can be detected by * this jack @@ -133,12 +133,13 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_add_zones); /** * snd_soc_jack_get_type - Based on the mic bias value, this function returns - * the type of jack from the zones delcared in the jack type + * the type of jack from the zones declared in the jack type * + * @jack: ASoC jack * @micbias_voltage: mic bias voltage at adc channel when jack is plugged in * * Based on the mic bias value passed, this function helps identify - * the type of jack from the already delcared jack zones + * the type of jack from the already declared jack zones */ int snd_soc_jack_get_type(struct snd_soc_jack *jack, int micbias_voltage) { -- cgit v1.2.3 From 57451e437796548d658d03c2c4aab659eafcd799 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 3 Oct 2012 14:33:50 +0200 Subject: ASoC: fsi: don't reschedule DMA from an atomic context shdma doesn't support transfer re-scheduling or triggering from callbacks or from atomic context. The fsi driver issues DMA transfers from a tasklet context, which is a bug. To fix it convert tasklet to a work. Reported-by: Do Q.Thang Tested-by: Do Q.Thang Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/sh/fsi.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 5328ae5539f1..9d7f30774a44 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -223,7 +224,7 @@ struct fsi_stream { */ struct dma_chan *chan; struct sh_dmae_slave slave; /* see fsi_handler_init() */ - struct tasklet_struct tasklet; + struct work_struct work; dma_addr_t dma; }; @@ -1085,9 +1086,9 @@ static void fsi_dma_complete(void *data) snd_pcm_period_elapsed(io->substream); } -static void fsi_dma_do_tasklet(unsigned long data) +static void fsi_dma_do_work(struct work_struct *work) { - struct fsi_stream *io = (struct fsi_stream *)data; + struct fsi_stream *io = container_of(work, struct fsi_stream, work); struct fsi_priv *fsi = fsi_stream_to_priv(io); struct snd_soc_dai *dai; struct dma_async_tx_descriptor *desc; @@ -1129,7 +1130,7 @@ static void fsi_dma_do_tasklet(unsigned long data) * FIXME * * In DMAEngine case, codec and FSI cannot be started simultaneously - * since FSI is using tasklet. + * since FSI is using the scheduler work queue. * Therefore, in capture case, probably FSI FIFO will have got * overflow error in this point. * in that case, DMA cannot start transfer until error was cleared. @@ -1153,7 +1154,7 @@ static bool fsi_dma_filter(struct dma_chan *chan, void *param) static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) { - tasklet_schedule(&io->tasklet); + schedule_work(&io->work); return 0; } @@ -1195,14 +1196,14 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct dev return fsi_stream_probe(fsi, dev); } - tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io); + INIT_WORK(&io->work, fsi_dma_do_work); return 0; } static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io) { - tasklet_kill(&io->tasklet); + cancel_work_sync(&io->work); fsi_stream_stop(fsi, io); -- cgit v1.2.3 From 961a7aeafab477f63d9eef26afde9cbb8badcd0f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 1 Oct 2012 12:29:26 +0300 Subject: ASoC: dmaengine: Correct Makefile when sound is built as module soc-dmaengine-pcm library need to be part of the snd-soc-core in order to be able to compile ASoC as modules when dmaengine is enabled on the platform. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/Makefile b/sound/soc/Makefile index bcbf1d00aa85..99f32f7c0692 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,8 +1,9 @@ snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o -snd-soc-dmaengine-pcm-objs := soc-dmaengine-pcm.o -obj-$(CONFIG_SND_SOC_DMAENGINE_PCM) += snd-soc-dmaengine-pcm.o +ifneq ($(CONFIG_SND_SOC_DMAENGINE_PCM),) +snd-soc-core-objs += soc-dmaengine-pcm.o +endif obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ -- cgit v1.2.3 From c7c0f2cdef1362c5fe301a1ffa8379824ee3f813 Mon Sep 17 00:00:00 2001 From: Ashish Chavan Date: Thu, 11 Oct 2012 14:04:37 +0530 Subject: ASoC: codecs: da9055: Minor improvement in ALC calibration process This patch slightly improves ALC calibration process of da9055 codec driver by muting Mic PGAs during calibration. Signed-off-by: Ashish Chavan Signed-off-by: David Dajun Chen Signed-off-by: Mark Brown --- sound/soc/codecs/da9055.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 185d8dd36399..f379b085c392 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -178,6 +178,12 @@ #define DA9055_AIF_WORD_S24_LE (2 << 2) #define DA9055_AIF_WORD_S32_LE (3 << 2) +/* MIC_L_CTRL bit fields */ +#define DA9055_MIC_L_MUTE_EN (1 << 6) + +/* MIC_R_CTRL bit fields */ +#define DA9055_MIC_R_MUTE_EN (1 << 6) + /* MIXIN_L_CTRL bit fields */ #define DA9055_MIXIN_L_MIX_EN (1 << 3) @@ -476,7 +482,7 @@ static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - u8 reg_val, adc_left, adc_right; + u8 reg_val, adc_left, adc_right, mic_left, mic_right; int avg_left_data, avg_right_data, offset_l, offset_r; if (ucontrol->value.integer.value[0]) { @@ -485,6 +491,16 @@ static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol, * offsets must be done first */ + /* Save current values from Mic control registers */ + mic_left = snd_soc_read(codec, DA9055_MIC_L_CTRL); + mic_right = snd_soc_read(codec, DA9055_MIC_R_CTRL); + + /* Mute Mic PGA Left and Right */ + snd_soc_update_bits(codec, DA9055_MIC_L_CTRL, + DA9055_MIC_L_MUTE_EN, DA9055_MIC_L_MUTE_EN); + snd_soc_update_bits(codec, DA9055_MIC_R_CTRL, + DA9055_MIC_R_MUTE_EN, DA9055_MIC_R_MUTE_EN); + /* Save current values from ADC control registers */ adc_left = snd_soc_read(codec, DA9055_ADC_L_CTRL); adc_right = snd_soc_read(codec, DA9055_ADC_R_CTRL); @@ -520,6 +536,10 @@ static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol, /* Restore original values of ADC control registers */ snd_soc_write(codec, DA9055_ADC_L_CTRL, adc_left); snd_soc_write(codec, DA9055_ADC_R_CTRL, adc_right); + + /* Restore original values of Mic control registers */ + snd_soc_write(codec, DA9055_MIC_L_CTRL, mic_left); + snd_soc_write(codec, DA9055_MIC_R_CTRL, mic_right); } return snd_soc_put_volsw(kcontrol, ucontrol); -- cgit v1.2.3 From 733a48e5ae5bf28b046fad984d458c747cbb8c21 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Oct 2012 16:43:40 +0200 Subject: ALSA: ac97 - Fix missing NULL check in snd_ac97_cvol_new() Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=44721 Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_codec.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 9473fca9681d..8b0f99688303 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1271,6 +1271,8 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne tmp.index = ac97->num; kctl = snd_ctl_new1(&tmp, ac97); } + if (!kctl) + return -ENOMEM; if (reg >= AC97_PHONE && reg <= AC97_PCM) set_tlv_db_scale(kctl, db_scale_5bit_12db_max); else -- cgit v1.2.3 From e73fa21b4e6ce10934cc8016a9a512d7152a860b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Oct 2012 16:51:52 +0200 Subject: ALSA: hda - Clean up superfluous position_fix list entries The white-list entries of position_fix for ASUS laptops have been added just as a workaround for broken COMBO mode. Now the combo mode itself is disabled, we can safely remove these entries. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 6833835a218b..69810b21f7f4 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2813,8 +2813,6 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB), - SND_PCI_QUIRK(0x1043, 0x1ac3, "ASUS X53S", POS_FIX_POSBUF), - SND_PCI_QUIRK(0x1043, 0x1b43, "ASUS K53E", POS_FIX_POSBUF), SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), SND_PCI_QUIRK(0x10de, 0xcb89, "Macbook Pro 7,1", POS_FIX_LPIB), SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB), -- cgit v1.2.3 From 128960a9ad67e2d119738f5211956e0304517551 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 12 Oct 2012 17:28:18 +0200 Subject: ALSA: hda - Fix registration race of VGA switcheroo Delay the registration of VGA switcheroo client to the end of the probing. Otherwise a too quick switching may result in Oops during probing. Also add the check of the return value from snd_hda_lock_devices(). Reported-and-tested-by: Daniel J Blueman Cc: [v3.5+] Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 69810b21f7f4..ecf277506ad1 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -501,6 +501,7 @@ struct azx { /* VGA-switcheroo setup */ unsigned int use_vga_switcheroo:1; + unsigned int vga_switcheroo_registered:1; unsigned int init_failed:1; /* delayed init failed */ unsigned int disabled:1; /* disabled by VGA-switcher */ @@ -2640,7 +2641,9 @@ static void azx_vs_set_state(struct pci_dev *pci, if (disabled) { azx_suspend(&pci->dev); chip->disabled = true; - snd_hda_lock_devices(chip->bus); + if (snd_hda_lock_devices(chip->bus)) + snd_printk(KERN_WARNING SFX + "Cannot lock devices!\n"); } else { snd_hda_unlock_devices(chip->bus); chip->disabled = false; @@ -2683,14 +2686,20 @@ static const struct vga_switcheroo_client_ops azx_vs_ops = { static int __devinit register_vga_switcheroo(struct azx *chip) { + int err; + if (!chip->use_vga_switcheroo) return 0; /* FIXME: currently only handling DIS controller * is there any machine with two switchable HDMI audio controllers? */ - return vga_switcheroo_register_audio_client(chip->pci, &azx_vs_ops, + err = vga_switcheroo_register_audio_client(chip->pci, &azx_vs_ops, VGA_SWITCHEROO_DIS, chip->bus != NULL); + if (err < 0) + return err; + chip->vga_switcheroo_registered = 1; + return 0; } #else #define init_vga_switcheroo(chip) /* NOP */ @@ -2712,7 +2721,8 @@ static int azx_free(struct azx *chip) if (use_vga_switcheroo(chip)) { if (chip->disabled && chip->bus) snd_hda_unlock_devices(chip->bus); - vga_switcheroo_unregister_client(chip->pci); + if (chip->vga_switcheroo_registered) + vga_switcheroo_unregister_client(chip->pci); } if (chip->initialized) { @@ -3060,14 +3070,6 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, } ok: - err = register_vga_switcheroo(chip); - if (err < 0) { - snd_printk(KERN_ERR SFX - "Error registering VGA-switcheroo client\n"); - azx_free(chip); - return err; - } - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); @@ -3338,6 +3340,13 @@ static int __devinit azx_probe(struct pci_dev *pci, if (pci_dev_run_wake(pci)) pm_runtime_put_noidle(&pci->dev); + err = register_vga_switcheroo(chip); + if (err < 0) { + snd_printk(KERN_ERR SFX + "Error registering VGA-switcheroo client\n"); + goto out_free; + } + dev++; return 0; -- cgit v1.2.3 From 39013bd60e79148961583402ed70bd105f95d260 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 15 Oct 2012 14:13:25 +0100 Subject: ASoC: Ux500: Dispose of device nodes correctly When of_parse_phandle() is used to find a device node, its reference count is incremented by the helper. Once we're finished with them, it's our responsibly to ensure they are freed in the correct manor. Acked-by: Linus Walleij Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- sound/soc/ux500/mop500.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'sound') diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c index 356611d9654d..54f7e25b6f7d 100644 --- a/sound/soc/ux500/mop500.c +++ b/sound/soc/ux500/mop500.c @@ -57,6 +57,20 @@ static struct snd_soc_card mop500_card = { .num_links = ARRAY_SIZE(mop500_dai_links), }; +static void mop500_of_node_put(void) +{ + int i; + + for (i = 0; i < 2; i++) { + if (mop500_dai_links[i].cpu_of_node) + of_node_put((struct device_node *) + mop500_dai_links[i].cpu_of_node); + if (mop500_dai_links[i].codec_of_node) + of_node_put((struct device_node *) + mop500_dai_links[i].codec_of_node); + } +} + static int __devinit mop500_of_probe(struct platform_device *pdev, struct device_node *np) { @@ -69,6 +83,7 @@ static int __devinit mop500_of_probe(struct platform_device *pdev, if (!(msp_np[0] && msp_np[1] && codec_np)) { dev_err(&pdev->dev, "Phandle missing or invalid\n"); + mop500_of_node_put(); return -EINVAL; } @@ -83,6 +98,7 @@ static int __devinit mop500_of_probe(struct platform_device *pdev, return 0; } + static int __devinit mop500_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -128,6 +144,7 @@ static int __devexit mop500_remove(struct platform_device *pdev) snd_soc_unregister_card(mop500_card); mop500_ab8500_remove(mop500_card); + mop500_of_node_put(); return 0; } -- cgit v1.2.3 From 05304949332c6d2c7b50f2d0f666a52369f09ced Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 15 Oct 2012 14:13:26 +0100 Subject: ASoC: ux500_msp_i2s: Fix devm_* and return code merge error Some ux500_msp_i2s patches clashed with: b18e93a493626c1446f9788ebd5844d008bbf71c ASoC: ux500_msp_i2s: better use devm functions and fix error return code ... leaving the driver uncompilable. This patch fixes the issues encountered. Acked-by: Linus Walleij Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_msp_i2s.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c index b7c996e77570..a26c6bf0a29b 100644 --- a/sound/soc/ux500/ux500_msp_i2s.c +++ b/sound/soc/ux500/ux500_msp_i2s.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -697,14 +698,11 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev, platform_data = devm_kzalloc(&pdev->dev, sizeof(struct msp_i2s_platform_data), GFP_KERNEL); if (!platform_data) - ret = -ENOMEM; + return -ENOMEM; } } else if (!platform_data) - ret = -EINVAL; - - if (ret) - goto err_res; + return -EINVAL; dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__, pdev->name, platform_data->id); -- cgit v1.2.3 From 1f04661fde9deda4a2cd5845258715a22d8af197 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 16 Oct 2012 16:52:26 +0200 Subject: ALSA: hda - Stop LPIB delay counting on broken hardware If LPIB reports a pretty bad value, we can't trust such hardware for calculating the PCM delay. Automatically turn off the delay counting when such a problem is encountered. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=48911 Cc: [v3.6] Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index ecf277506ad1..72b085ae7d46 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2158,9 +2158,12 @@ static unsigned int azx_get_position(struct azx *chip, if (delay < 0) delay += azx_dev->bufsize; if (delay >= azx_dev->period_bytes) { - snd_printdd("delay %d > period_bytes %d\n", - delay, azx_dev->period_bytes); - delay = 0; /* something is wrong */ + snd_printk(KERN_WARNING SFX + "Unstable LPIB (%d >= %d); " + "disabling LPIB delay counting\n", + delay, azx_dev->period_bytes); + delay = 0; + chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; } azx_dev->substream->runtime->delay = bytes_to_frames(azx_dev->substream->runtime, delay); -- cgit v1.2.3 From 9233ef6b559faa3db14144f41dea2e70d1ad0092 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 26 Sep 2012 16:22:32 +0100 Subject: ASoC: bells: Correct typo in sub speaker DAI name for WM5110 Signed-off-by: Mark Brown --- sound/soc/samsung/bells.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c index a2ca1567b9e4..b0d46d63d55e 100644 --- a/sound/soc/samsung/bells.c +++ b/sound/soc/samsung/bells.c @@ -212,7 +212,7 @@ static struct snd_soc_dai_link bells_dai_wm5102[] = { { .name = "Sub", .stream_name = "Sub", - .cpu_dai_name = "wm5102-aif3", + .cpu_dai_name = "wm5110-aif3", .codec_dai_name = "wm9081-hifi", .codec_name = "wm9081.1-006c", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF -- cgit v1.2.3 From 71aa5ebe36a4e936eff281b375a4707b6a8320f2 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 17 Oct 2012 12:43:44 +0200 Subject: ALSA: hda - Always check array bounds in alc_get_line_out_pfx Even when CONFIG_SND_DEBUG is not enabled, we don't want to return an arbitrary memory location when the channel count is larger than we expected. Cc: stable@kernel.org Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8253b4eeb6a1..48d9d609f89b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2598,8 +2598,10 @@ static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch, return "PCM"; break; } - if (snd_BUG_ON(ch >= ARRAY_SIZE(channel_name))) + if (ch >= ARRAY_SIZE(channel_name)) { + snd_BUG(); return "PCM"; + } return channel_name[ch]; } -- cgit v1.2.3 From 10f571d09106c3eb85951896522c9650596eff2e Mon Sep 17 00:00:00 2001 From: Maxim Kachur Date: Wed, 17 Oct 2012 18:18:10 +0200 Subject: ALSA: emu10k1: add chip details for E-mu 1010 PCIe card Add chip details for E-mu 1010 PCIe card. It has the same chip as found in E-mu 1010b but it uses different PCI id. Signed-off-by: Maxim Kachur Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index bed4485f34f6..c21adb6ef1d5 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1416,6 +1416,15 @@ static struct snd_emu_chip_details emu_chip_details[] = { .ca0108_chip = 1, .spk71 = 1, .emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 new revision */ + /* Tested by Maxim Kachur 17th Oct 2012. */ + /* This is MAEM8986, 0202 is MAEM8980 */ + {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40071102, + .driver = "Audigy2", .name = "E-mu 1010 PCIe [MAEM8986]", + .id = "EMU1010", + .emu10k2_chip = 1, + .ca0108_chip = 1, + .spk71 = 1, + .emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 PCIe */ /* Tested by James@superbug.co.uk 8th July 2005. */ /* This is MAEM8810, 0202 is MAEM8820 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, -- cgit v1.2.3 From 84f98fdf7865fbd35b312eb39ea91e5618c514c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stef=C3=A1n=20Freyr?= Date: Fri, 19 Oct 2012 22:46:00 +0200 Subject: ALSA: hda - add dock support for Thinkpad T430 I have a Lenovo ThinkPad T430 and an UltraBase Series 3 docking station. Without this patch, if I plug my headphones into the jack on the computer, everything works fine. The computer speakers mute and the audio is played in the headphones. However, if I plug into the docking station headphone jack the computer speakers are muted but there is no audio in the headphones. Addresses https://bugs.launchpad.net/bugs/1060372 Signed-off-by: Joseph Salisbury Cc: stable@vger.kernel.org Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 48d9d609f89b..2c62edd6d4fd 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6188,6 +6188,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK), + SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), -- cgit v1.2.3 From 41285a98f8f052b59f01bbbcb0064e5e41b0ca2d Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 19 Oct 2012 17:42:22 +0200 Subject: ALSA: hdspm - Allow DDS/Varispeed to be set from userspace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DDS value is the actual physical sample rate. We set it indirectly when selecting 44100, 48000 and so on via snd_hdspm_hw_params or hdspm_set_clock_source. This commit now allows the DDS value to be altered at runtime, thus speeding up or slowing down the physical sample rate. This is required for MADI's varispeed that allows for ±12.5% speed adjustment from the "selected" rate (32kHz, 44100kHz, 48kHz and so on). Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index b12308b5ba2a..742bd5e430ab 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2003,8 +2003,10 @@ static int hdspm_get_system_sample_rate(struct hdspm *hdspm) { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ .index = xindex, \ - .access = SNDRV_CTL_ELEM_ACCESS_READ, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ .info = snd_hdspm_info_system_sample_rate, \ + .put = snd_hdspm_put_system_sample_rate, \ .get = snd_hdspm_get_system_sample_rate \ } @@ -2030,6 +2032,16 @@ static int snd_hdspm_get_system_sample_rate(struct snd_kcontrol *kcontrol, return 0; } +static int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value * + ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + + hdspm_set_dds_value(hdspm, ucontrol->value.enumerated.item[0]); + return 0; +} + /** * Returns the WordClock sample rate class for the given card. -- cgit v1.2.3 From 21a164df0c1c2e72d4bb78b2f67dc75a1c9d14fb Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 19 Oct 2012 17:42:23 +0200 Subject: ALSA: hdspm - Report external rate in slave mode on PCI MADI As a follow-up to a97bda7d29d02a2e9c6609d0947b15e55f5200e5, report the external sample rate as system_sample_rate when in slave mode. For PCIe MADI cards, the DDS value automatically contains the external sample rate, but the PCI version needs this manual workaround. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 742bd5e430ab..1131a8ab3f73 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -971,6 +971,7 @@ static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm); static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm); static int hdspm_autosync_ref(struct hdspm *hdspm); static int snd_hdspm_set_defaults(struct hdspm *hdspm); +static int hdspm_system_clock_mode(struct hdspm *hdspm); static void hdspm_set_sgbuf(struct hdspm *hdspm, struct snd_pcm_substream *substream, unsigned int reg, int channels); @@ -1989,10 +1990,14 @@ static int hdspm_get_system_sample_rate(struct hdspm *hdspm) rate = hdspm_calc_dds_value(hdspm, period); if (rate > 207000) { - /* Unreasonable high sample rate as seen on PCI MADI cards. - * Use the cached value instead. - */ - rate = hdspm->system_sample_rate; + /* Unreasonable high sample rate as seen on PCI MADI cards. */ + if (0 == hdspm_system_clock_mode(hdspm)) { + /* master mode, return internal sample rate */ + rate = hdspm->system_sample_rate; + } else { + /* slave mode, return external sample rate */ + rate = hdspm_external_sample_rate(hdspm); + } } return rate; -- cgit v1.2.3 From fba30fd342beda8e7908f214d9e7f8a62dcdc57d Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 19 Oct 2012 17:42:24 +0200 Subject: ALSA: hdspm - Fix sync check reporting on all RME HDSPM cards Due to missing breaks and the resulting fall-through, card subtype selection was effectively missing, thus causing the wrong sync check functions to be called. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 1131a8ab3f73..81d83faab510 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -3959,6 +3959,7 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, default: val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1); } + break; case AIO: switch (kcontrol->private_value) { @@ -3971,6 +3972,7 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, default: val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1); } + break; case MADI: switch (kcontrol->private_value) { @@ -3983,6 +3985,7 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, case 3: /* SYNC_IN */ val = hdspm_sync_in_sync_check(hdspm); break; } + break; case MADIface: val = hdspm_madi_sync_check(hdspm); /* MADI */ @@ -4000,6 +4003,7 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, val = hdspm_aes_sync_check(hdspm, kcontrol->private_value-1); } + break; } -- cgit v1.2.3 From d681deaa74748ce1d4b1a862438c955b70f46690 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 19 Oct 2012 17:42:25 +0200 Subject: ALSA: hdspm - Fix reported autosync_sample_rate Missing breaks lead to a fall-through, thus causing the wrong autosync_sample_rate to be reported. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 81d83faab510..976e3a6b0508 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2180,6 +2180,7 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, hdspm_get_s1_sample_rate(hdspm, kcontrol->private_value-1); } + break; case AIO: switch (kcontrol->private_value) { @@ -2200,6 +2201,7 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, hdspm_get_s1_sample_rate(hdspm, ucontrol->id.index-1); } + break; case AES32: @@ -2221,8 +2223,8 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, hdspm_get_s1_sample_rate(hdspm, kcontrol->private_value-1); break; - } + break; default: break; } -- cgit v1.2.3 From b8812c55c5e59596bbf4b1d3e5b4b3ef50a89cad Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 19 Oct 2012 17:42:26 +0200 Subject: ALSA: hdspm - Also report autosync_sample_rate on MADI and MADIface MADI and MADIface used to report the autosync_sample_rate. This functionality was lost in commit 0dca1793063c28dde8f6c49c9c72203fe5cb6efc, this commit now adds it back. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 976e3a6b0508..5f243aedeef7 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2225,6 +2225,21 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, break; } break; + + case MADI: + case MADIface: + { + int rate = hdspm_external_sample_rate(hdspm); + int i, selected_rate = 0; + for (i = 1; i < 10; i++) + if (HDSPM_bit2freq(i) == rate) { + selected_rate = i; + break; + } + ucontrol->value.enumerated.item[0] = selected_rate; + } + break; + default: break; } @@ -4450,6 +4465,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_madi[] = { HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), + HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), HDSPM_SYNC_CHECK("WC SyncCheck", 0), HDSPM_SYNC_CHECK("MADI SyncCheck", 1), HDSPM_SYNC_CHECK("TCO SyncCHeck", 2), -- cgit v1.2.3 From 2e0452f544758d798ba76016c00783f654b43fe3 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 19 Oct 2012 17:42:27 +0200 Subject: ALSA: hdspm - Fix sync_in reporting on RME MADI cards In contrast to AES32, MADI uses the first status register to report the sync_in status. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 5f243aedeef7..5d70efec26c0 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -3885,6 +3885,11 @@ static int hdspm_sync_in_sync_check(struct hdspm *hdspm) break; case MADI: + status = hdspm_read(hdspm, HDSPM_statusRegister); + lock = (status & HDSPM_syncInLock) ? 1 : 0; + sync = (status & HDSPM_syncInSync) ? 1 : 0; + break; + case AES32: status = hdspm_read(hdspm, HDSPM_statusRegister2); lock = (status & HDSPM_syncInLock) ? 1 : 0; -- cgit v1.2.3 From 9a215f47da029b04bf92f1f68abf978211155ceb Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 19 Oct 2012 17:42:28 +0200 Subject: ALSA: hdspm - Fix sync_in detection on AES/AES32 According to the documentation, AES32 cards use a different bit position for reporting the sync_in status. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 5d70efec26c0..b8b15ee5eebb 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -3892,8 +3892,8 @@ static int hdspm_sync_in_sync_check(struct hdspm *hdspm) case AES32: status = hdspm_read(hdspm, HDSPM_statusRegister2); - lock = (status & HDSPM_syncInLock) ? 1 : 0; - sync = (status & HDSPM_syncInSync) ? 1 : 0; + lock = (status & 0x100000) ? 1 : 0; + sync = (status & 0x200000) ? 1 : 0; break; case MADIface: -- cgit v1.2.3 From 930f4ff078b9c4484b0e9383fc17a04d4f9253bf Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 19 Oct 2012 17:42:29 +0200 Subject: ALSA: hdspm - Fix typo in kcontrol element on RME MADI cards Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index b8b15ee5eebb..096580473529 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -4473,7 +4473,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_madi[] = { HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), HDSPM_SYNC_CHECK("WC SyncCheck", 0), HDSPM_SYNC_CHECK("MADI SyncCheck", 1), - HDSPM_SYNC_CHECK("TCO SyncCHeck", 2), + HDSPM_SYNC_CHECK("TCO SyncCheck", 2), HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 3), HDSPM_LINE_OUT("Line Out", 0), HDSPM_TX_64("TX 64 channels mode", 0), -- cgit v1.2.3 From f27a64f9973ff932ece576793c195de60c1c6c9b Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 19 Oct 2012 17:42:30 +0200 Subject: ALSA: hdspm - Fix coding style in CTL_ELEM macros checkpatch.pl discourages the use of spaces at the beginning of lines. Some of the CTL_ELEM defines were not properly indented. This patch replaces the leading spaces by tabs. No functionality is changed, the commit is purely cosmetic. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 180 +++++++++++++++++++++++----------------------- 1 file changed, 90 insertions(+), 90 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 096580473529..f1cd1e387801 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2005,14 +2005,14 @@ static int hdspm_get_system_sample_rate(struct hdspm *hdspm) #define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ - SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ - .info = snd_hdspm_info_system_sample_rate, \ - .put = snd_hdspm_put_system_sample_rate, \ - .get = snd_hdspm_get_system_sample_rate \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_system_sample_rate, \ + .put = snd_hdspm_put_system_sample_rate, \ + .get = snd_hdspm_get_system_sample_rate \ } static int snd_hdspm_info_system_sample_rate(struct snd_kcontrol *kcontrol, @@ -2464,7 +2464,7 @@ static int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol, #define HDSPM_PREF_SYNC_REF(xname, xindex) \ -{.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ .index = xindex, \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ @@ -2800,12 +2800,12 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol, #define HDSPM_AUTOSYNC_REF(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .access = SNDRV_CTL_ELEM_ACCESS_READ, \ - .info = snd_hdspm_info_autosync_ref, \ - .get = snd_hdspm_get_autosync_ref, \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ, \ + .info = snd_hdspm_info_autosync_ref, \ + .get = snd_hdspm_get_autosync_ref, \ } static int hdspm_autosync_ref(struct hdspm *hdspm) @@ -2889,12 +2889,12 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol, #define HDSPM_LINE_OUT(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_line_out, \ - .get = snd_hdspm_get_line_out, \ - .put = snd_hdspm_put_line_out \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_line_out, \ + .get = snd_hdspm_get_line_out, \ + .put = snd_hdspm_put_line_out \ } static int hdspm_line_out(struct hdspm * hdspm) @@ -2946,12 +2946,12 @@ static int snd_hdspm_put_line_out(struct snd_kcontrol *kcontrol, #define HDSPM_TX_64(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_tx_64, \ - .get = snd_hdspm_get_tx_64, \ - .put = snd_hdspm_put_tx_64 \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_tx_64, \ + .get = snd_hdspm_get_tx_64, \ + .put = snd_hdspm_put_tx_64 \ } static int hdspm_tx_64(struct hdspm * hdspm) @@ -3002,12 +3002,12 @@ static int snd_hdspm_put_tx_64(struct snd_kcontrol *kcontrol, #define HDSPM_C_TMS(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_c_tms, \ - .get = snd_hdspm_get_c_tms, \ - .put = snd_hdspm_put_c_tms \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_c_tms, \ + .get = snd_hdspm_get_c_tms, \ + .put = snd_hdspm_put_c_tms \ } static int hdspm_c_tms(struct hdspm * hdspm) @@ -3058,12 +3058,12 @@ static int snd_hdspm_put_c_tms(struct snd_kcontrol *kcontrol, #define HDSPM_SAFE_MODE(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_safe_mode, \ - .get = snd_hdspm_get_safe_mode, \ - .put = snd_hdspm_put_safe_mode \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_safe_mode, \ + .get = snd_hdspm_get_safe_mode, \ + .put = snd_hdspm_put_safe_mode \ } static int hdspm_safe_mode(struct hdspm * hdspm) @@ -3114,12 +3114,12 @@ static int snd_hdspm_put_safe_mode(struct snd_kcontrol *kcontrol, #define HDSPM_EMPHASIS(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_emphasis, \ - .get = snd_hdspm_get_emphasis, \ - .put = snd_hdspm_put_emphasis \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_emphasis, \ + .get = snd_hdspm_get_emphasis, \ + .put = snd_hdspm_put_emphasis \ } static int hdspm_emphasis(struct hdspm * hdspm) @@ -3170,12 +3170,12 @@ static int snd_hdspm_put_emphasis(struct snd_kcontrol *kcontrol, #define HDSPM_DOLBY(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_dolby, \ - .get = snd_hdspm_get_dolby, \ - .put = snd_hdspm_put_dolby \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_dolby, \ + .get = snd_hdspm_get_dolby, \ + .put = snd_hdspm_put_dolby \ } static int hdspm_dolby(struct hdspm * hdspm) @@ -3226,12 +3226,12 @@ static int snd_hdspm_put_dolby(struct snd_kcontrol *kcontrol, #define HDSPM_PROFESSIONAL(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_professional, \ - .get = snd_hdspm_get_professional, \ - .put = snd_hdspm_put_professional \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_professional, \ + .get = snd_hdspm_get_professional, \ + .put = snd_hdspm_put_professional \ } static int hdspm_professional(struct hdspm * hdspm) @@ -3281,12 +3281,12 @@ static int snd_hdspm_put_professional(struct snd_kcontrol *kcontrol, } #define HDSPM_INPUT_SELECT(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_input_select, \ - .get = snd_hdspm_get_input_select, \ - .put = snd_hdspm_put_input_select \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_input_select, \ + .get = snd_hdspm_get_input_select, \ + .put = snd_hdspm_put_input_select \ } static int hdspm_input_select(struct hdspm * hdspm) @@ -3353,12 +3353,12 @@ static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol, #define HDSPM_DS_WIRE(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_ds_wire, \ - .get = snd_hdspm_get_ds_wire, \ - .put = snd_hdspm_put_ds_wire \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_ds_wire, \ + .get = snd_hdspm_get_ds_wire, \ + .put = snd_hdspm_put_ds_wire \ } static int hdspm_ds_wire(struct hdspm * hdspm) @@ -3425,12 +3425,12 @@ static int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol, #define HDSPM_QS_WIRE(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_qs_wire, \ - .get = snd_hdspm_get_qs_wire, \ - .put = snd_hdspm_put_qs_wire \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_qs_wire, \ + .get = snd_hdspm_get_qs_wire, \ + .put = snd_hdspm_put_qs_wire \ } static int hdspm_qs_wire(struct hdspm * hdspm) @@ -3597,15 +3597,15 @@ static int snd_hdspm_put_madi_speedmode(struct snd_kcontrol *kcontrol, } #define HDSPM_MIXER(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ - .name = xname, \ - .index = xindex, \ - .device = 0, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ - .info = snd_hdspm_info_mixer, \ - .get = snd_hdspm_get_mixer, \ - .put = snd_hdspm_put_mixer \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .device = 0, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_mixer, \ + .get = snd_hdspm_get_mixer, \ + .put = snd_hdspm_put_mixer \ } static int snd_hdspm_info_mixer(struct snd_kcontrol *kcontrol, @@ -3704,12 +3704,12 @@ static int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol, */ #define HDSPM_PLAYBACK_MIXER \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \ - SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ - .info = snd_hdspm_info_playback_mixer, \ - .get = snd_hdspm_get_playback_mixer, \ - .put = snd_hdspm_put_playback_mixer \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_playback_mixer, \ + .get = snd_hdspm_get_playback_mixer, \ + .put = snd_hdspm_put_playback_mixer \ } static int snd_hdspm_info_playback_mixer(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From cb766404e6b8c566569eb9ada02ea45d28729864 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 20 Oct 2012 10:55:21 +0200 Subject: ALSA: hda - Fix silent headphone output from Toshiba P200 By some reason, Toshiba laptop doesn't like the EAPD turned up for the headphone pin. Add a fix up code to force to turn down EAPD for NID 0x15. Bugzilla: https://bugzilla.novell.com/show_bug.cgi?id=569991 Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2c62edd6d4fd..f7397ad02a0d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5677,6 +5677,7 @@ static const struct hda_verb alc268_beep_init_verbs[] = { enum { ALC268_FIXUP_INV_DMIC, + ALC268_FIXUP_HP_EAPD, }; static const struct alc_fixup alc268_fixups[] = { @@ -5684,10 +5685,26 @@ static const struct alc_fixup alc268_fixups[] = { .type = ALC_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, }, + [ALC268_FIXUP_HP_EAPD] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0}, + {} + } + }, }; static const struct alc_model_fixup alc268_fixup_models[] = { {.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"}, + {.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"}, + {} +}; + +static const struct snd_pci_quirk alc268_fixup_tbl[] = { + /* below is codec SSID since multiple Toshiba laptops have the + * same PCI SSID 1179:ff00 + */ + SND_PCI_QUIRK(0x1179, 0xff06, "Toshiba P200", ALC268_FIXUP_HP_EAPD), {} }; @@ -5722,7 +5739,7 @@ static int patch_alc268(struct hda_codec *codec) spec = codec->spec; - alc_pick_fixup(codec, alc268_fixup_models, NULL, alc268_fixups); + alc_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups); alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); /* automatic parse from the BIOS config */ -- cgit v1.2.3 From edb66893860dbc0631afc2807efdb209a03d57a2 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 21 Oct 2012 12:52:03 +0200 Subject: ALSA: sound/isa/opti9xx/miro.c: eliminate possible double free snd_miro_probe is a static function that is only called twice in the file that defines it. At each call site, its argument is freed using snd_card_free. Thus, there is no need for snd_miro_probe to call snd_card_free on its argument on any of its error exit paths. Because snd_card_free both reads the fields of its argument and kfrees its argments, the results of the second snd_card_free should be unpredictable. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r@ identifier f,free,a; parameter list[n] ps; type T; expression e; @@ f(ps,T a,...) { ... when any when != a = e if(...) { ... free(a); ... return ...; } ... when any } @@ identifier r.f,r.free; expression x,a; expression list[r.n] xs; @@ * x = f(xs,a,...); if (...) { ... free(a); ... return ...; } // Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 3d1afb612b35..4a7ff4e8985b 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -1286,7 +1286,6 @@ static int __devinit snd_miro_probe(struct snd_card *card) error = snd_card_miro_aci_detect(card, miro); if (error < 0) { - snd_card_free(card); snd_printk(KERN_ERR "unable to detect aci chip\n"); return -ENODEV; } -- cgit v1.2.3 From 21b3de881b38a84002c07b1b4bfb91892644e83f Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Mon, 22 Oct 2012 17:05:53 +0400 Subject: ALSA: als3000: check for the kzalloc return value Signed-off-by: Denis Kirjanov Signed-off-by: Takashi Iwai --- sound/pci/als300.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 00f157a2cf64..5af3cb6b0c18 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -394,6 +394,8 @@ static int snd_als300_playback_open(struct snd_pcm_substream *substream) struct snd_als300_substream_data *data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; snd_als300_dbgcallenter(); chip->playback_substream = substream; runtime->hw = snd_als300_playback_hw; @@ -425,6 +427,8 @@ static int snd_als300_capture_open(struct snd_pcm_substream *substream) struct snd_als300_substream_data *data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; snd_als300_dbgcallenter(); chip->capture_substream = substream; runtime->hw = snd_als300_capture_hw; -- cgit v1.2.3 From 79748cdb39dbf914bc5f26c75cfd5f91d84d82c9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Oct 2012 15:28:30 +0100 Subject: ASoC: wm8994: Only enable extra BCLK cycles when required Rather than always assuming the maximum possible BCLK rate will be required generate BCLKs for stereo if either one or two channels is enabled. In order to support this we also need to ensure that only the relevant channels are enabled. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 18 +++++++++++++++++- sound/soc/codecs/wm8994.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 2b2dadc54dac..3fddc7ad1127 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -1045,6 +1045,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = codec->control_data; int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA; int i; @@ -1063,6 +1064,10 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + /* Don't enable timeslot 2 if not in use */ + if (wm8994->channels[0] <= 2) + mask &= ~(WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA); + val = snd_soc_read(codec, WM8994_AIF1_CONTROL_1); if ((val & WM8994_AIF1ADCL_SRC) && (val & WM8994_AIF1ADCR_SRC)) @@ -2687,7 +2692,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - bclk_rate = params_rate(params) * 4; + bclk_rate = params_rate(params); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: bclk_rate *= 16; @@ -2708,6 +2713,17 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + wm8994->channels[id] = params_channels(params); + switch (params_channels(params)) { + case 1: + case 2: + bclk_rate *= 2; + break; + default: + bclk_rate *= 4; + break; + } + /* Try to find an appropriate sample rate; look for an exact match. */ for (i = 0; i < ARRAY_SIZE(srs); i++) if (srs[i].rate == params_rate(params)) diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index f142ec198db3..ccbce5791e95 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -77,6 +77,7 @@ struct wm8994_priv { int sysclk_rate[2]; int mclk[2]; int aifclk[2]; + int channels[2]; struct wm8994_fll_config fll[2], fll_suspend[2]; struct completion fll_locked[2]; bool fll_locked_irq; -- cgit v1.2.3 From 5afc13af36d2fdaa48bc54386c6ad43590d88be5 Mon Sep 17 00:00:00 2001 From: Gustavo Maciel Dias Vieira Date: Fri, 26 Oct 2012 12:51:53 -0200 Subject: ALSA: hda - Fix mute-LED setup for HP dv5 laptop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BIOS on HP dv5 doesn't have the DMI string to guide the setup of mute led GPIO and polarity. Associate this laptop with the hp-inv-led model. Signed-off-by: Gustavo Maciel Dias Vieira Tested-by: Vinícius Angiolucci Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 770013ff556f..9ba8af056170 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1763,6 +1763,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { "HP", STAC_HP_ZEPHYR), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3660, "HP Mini", STAC_92HD83XXX_HP_LED), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x144E, + "HP Pavilion dv5", STAC_92HD83XXX_HP_INV_LED), {} /* terminator */ }; -- cgit v1.2.3 From 257d36fd696d76b622539c26af652d2a8a931ce9 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 3 Oct 2012 09:31:02 -0700 Subject: ASoC: zoom2: Fix compile error by including correct header files Also drop the includes that are no longer needed and just cause problems for the ARM common zImage. Acked-by: Peter Ujfalusi Signed-off-by: Tim Gardner [tony@atomide.com: updated to drop unneeded headers] Signed-off-by: Tony Lindgren Signed-off-by: Mark Brown --- sound/soc/omap/zoom2.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c index 677b567935f8..1ff6bb9ade5c 100644 --- a/sound/soc/omap/zoom2.c +++ b/sound/soc/omap/zoom2.c @@ -21,15 +21,14 @@ #include #include +#include #include #include #include #include -#include -#include -#include #include +#include /* Register descriptions for twl4030 codec part */ #include -- cgit v1.2.3 From 19118eb8dc3cd6bb1b1fdf0e4ad62070c6683158 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 26 Oct 2012 12:33:08 +0200 Subject: ASoC: omap-dmic: Correct functional clock name We should really use "fck" when asking for the functional clock and not "dmic_fck". This way we can ensure that multiple dmic modules can exist in the system. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-dmic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c index 68f2cd1a9206..5a6aeaf552a8 100644 --- a/sound/soc/omap/omap-dmic.c +++ b/sound/soc/omap/omap-dmic.c @@ -464,9 +464,9 @@ static __devinit int asoc_dmic_probe(struct platform_device *pdev) mutex_init(&dmic->mutex); - dmic->fclk = clk_get(dmic->dev, "dmic_fck"); + dmic->fclk = clk_get(dmic->dev, "fck"); if (IS_ERR(dmic->fclk)) { - dev_err(dmic->dev, "cant get dmic_fck\n"); + dev_err(dmic->dev, "cant get fck\n"); return -ENODEV; } -- cgit v1.2.3 From 9b0573c07f278e9888c352aa9724035c75784ea0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 12 Oct 2012 15:07:34 +0200 Subject: ALSA: PCM: Fix some races at disconnection Fix races at PCM disconnection: - while a PCM device is being opened or closed - while the PCM state is being changed without lock in prepare, hw_params, hw_free ops Reported-by: Matthieu CASTET Cc: Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 7 ++++++- sound/core/pcm_native.c | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm.c b/sound/core/pcm.c index f2991940b271..993b2405fdfe 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1086,11 +1086,15 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) if (list_empty(&pcm->list)) goto unlock; + mutex_lock(&pcm->open_mutex); list_del_init(&pcm->list); for (cidx = 0; cidx < 2; cidx++) - for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) + for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { + snd_pcm_stream_lock_irq(substream); if (substream->runtime) substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; + snd_pcm_stream_unlock_irq(substream); + } list_for_each_entry(notify, &snd_pcm_notify_list, list) { notify->n_disconnect(pcm); } @@ -1110,6 +1114,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) pcm->streams[cidx].chmap_kctl = NULL; } } + mutex_unlock(&pcm->open_mutex); unlock: mutex_unlock(®ister_mutex); return 0; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 5e12e5bacbba..8753c89f3290 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -369,6 +369,14 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime) return usecs; } +static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state) +{ + snd_pcm_stream_lock_irq(substream); + if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED) + substream->runtime->status->state = state; + snd_pcm_stream_unlock_irq(substream); +} + static int snd_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -452,7 +460,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, runtime->boundary *= 2; snd_pcm_timer_resolution_change(substream); - runtime->status->state = SNDRV_PCM_STATE_SETUP; + snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP); if (pm_qos_request_active(&substream->latency_pm_qos_req)) pm_qos_remove_request(&substream->latency_pm_qos_req); @@ -464,7 +472,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, /* hardware might be unusable from this time, so we force application to retry to set the correct hardware parameter settings */ - runtime->status->state = SNDRV_PCM_STATE_OPEN; + snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); if (substream->ops->hw_free != NULL) substream->ops->hw_free(substream); return err; @@ -512,7 +520,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) return -EBADFD; if (substream->ops->hw_free) result = substream->ops->hw_free(substream); - runtime->status->state = SNDRV_PCM_STATE_OPEN; + snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); pm_qos_remove_request(&substream->latency_pm_qos_req); return result; } @@ -1320,7 +1328,7 @@ static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state) { struct snd_pcm_runtime *runtime = substream->runtime; runtime->control->appl_ptr = runtime->status->hw_ptr; - runtime->status->state = SNDRV_PCM_STATE_PREPARED; + snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED); } static struct action_ops snd_pcm_action_prepare = { -- cgit v1.2.3 From 978520b75f0a1ce82b17e1e8186417250de6d545 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 12 Oct 2012 15:12:55 +0200 Subject: ALSA: usb-audio: Fix races at disconnection Close some races at disconnection of a USB audio device by adding the chip->shutdown_mutex and chip->shutdown check at appropriate places. The spots to put bandaids are: - PCM prepare, hw_params and hw_free - where the usb device is accessed for communication or get speed, in mixer.c and others; the device speed is now cached in subs->speed instead of accessing to chip->dev The accesses in PCM open and close don't need the mutex protection because these are already handled in the core PCM disconnection code. The autosuspend/autoresume codes are still uncovered by this patch because of possible mutex deadlocks. They'll be covered by the upcoming change to rwsem. Also the mixer codes are untouched, too. These will be fixed in another patch, too. Reported-by: Matthieu CASTET Cc: Signed-off-by: Takashi Iwai --- sound/usb/card.h | 1 + sound/usb/mixer.c | 65 ++++++++++++++++++++++++++++++++++++------------------ sound/usb/pcm.c | 49 ++++++++++++++++++++++++++-------------- sound/usb/proc.c | 4 ++-- sound/usb/stream.c | 1 + 5 files changed, 79 insertions(+), 41 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.h b/sound/usb/card.h index afa4f9e9b27a..814cb357ff88 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -126,6 +126,7 @@ struct snd_usb_substream { struct snd_usb_endpoint *sync_endpoint; unsigned long flags; bool need_setup_ep; /* (re)configure EP at prepare? */ + unsigned int speed; /* USB_SPEED_XXX */ u64 formats; /* format bitmasks (all or'ed) */ unsigned int num_formats; /* number of supported audio formats (list) */ diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index fe56c9da38e9..c2ef11ccd66a 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -287,25 +287,32 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v unsigned char buf[2]; int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; int timeout = 10; - int err; + int idx = 0, err; err = snd_usb_autoresume(cval->mixer->chip); if (err < 0) return -EIO; + mutex_lock(&chip->shutdown_mutex); while (timeout-- > 0) { + if (chip->shutdown) + break; + idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), - buf, val_len) >= val_len) { + validx, idx, buf, val_len) >= val_len) { *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); - snd_usb_autosuspend(cval->mixer->chip); - return 0; + err = 0; + goto out; } } - snd_usb_autosuspend(cval->mixer->chip); snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", - request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type); - return -EINVAL; + request, validx, idx, cval->val_type); + err = -EINVAL; + + out: + mutex_unlock(&chip->shutdown_mutex); + snd_usb_autosuspend(cval->mixer->chip); + return err; } static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) @@ -313,7 +320,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v struct snd_usb_audio *chip = cval->mixer->chip; unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */ unsigned char *val; - int ret, size; + int idx = 0, ret, size; __u8 bRequest; if (request == UAC_GET_CUR) { @@ -330,16 +337,22 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v if (ret) goto error; - ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, + mutex_lock(&chip->shutdown_mutex); + if (chip->shutdown) + ret = -ENODEV; + else { + idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); + ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), - buf, size); + validx, idx, buf, size); + } + mutex_unlock(&chip->shutdown_mutex); snd_usb_autosuspend(chip); if (ret < 0) { error: snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", - request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type); + request, validx, idx, cval->val_type); return ret; } @@ -417,7 +430,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, { struct snd_usb_audio *chip = cval->mixer->chip; unsigned char buf[2]; - int val_len, err, timeout = 10; + int idx = 0, val_len, err, timeout = 10; if (cval->mixer->protocol == UAC_VERSION_1) { val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; @@ -440,19 +453,27 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, err = snd_usb_autoresume(chip); if (err < 0) return -EIO; - while (timeout-- > 0) + mutex_lock(&chip->shutdown_mutex); + while (timeout-- > 0) { + if (chip->shutdown) + break; + idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); if (snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), - buf, val_len) >= 0) { - snd_usb_autosuspend(chip); - return 0; + validx, idx, buf, val_len) >= 0) { + err = 0; + goto out; } - snd_usb_autosuspend(chip); + } snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n", - request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]); - return -EINVAL; + request, validx, idx, cval->val_type, buf[0], buf[1]); + err = -EINVAL; + + out: + mutex_unlock(&chip->shutdown_mutex); + snd_usb_autosuspend(chip); + return err; } static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 55e19e1b80ec..55e741c5f231 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -71,6 +71,8 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream unsigned int hwptr_done; subs = (struct snd_usb_substream *)substream->runtime->private_data; + if (subs->stream->chip->shutdown) + return SNDRV_PCM_POS_XRUN; spin_lock(&subs->lock); hwptr_done = subs->hwptr_done; substream->runtime->delay = snd_usb_pcm_delay(subs, @@ -444,7 +446,6 @@ static int configure_endpoint(struct snd_usb_substream *subs) { int ret; - mutex_lock(&subs->stream->chip->shutdown_mutex); /* format changed */ stop_endpoints(subs, 0, 0, 0); ret = snd_usb_endpoint_set_params(subs->data_endpoint, @@ -455,7 +456,7 @@ static int configure_endpoint(struct snd_usb_substream *subs) subs->cur_audiofmt, subs->sync_endpoint); if (ret < 0) - goto unlock; + return ret; if (subs->sync_endpoint) ret = snd_usb_endpoint_set_params(subs->data_endpoint, @@ -465,9 +466,6 @@ static int configure_endpoint(struct snd_usb_substream *subs) subs->cur_rate, subs->cur_audiofmt, NULL); - -unlock: - mutex_unlock(&subs->stream->chip->shutdown_mutex); return ret; } @@ -505,7 +503,13 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - if ((ret = set_format(subs, fmt)) < 0) + mutex_lock(&subs->stream->chip->shutdown_mutex); + if (subs->stream->chip->shutdown) + ret = -ENODEV; + else + ret = set_format(subs, fmt); + mutex_unlock(&subs->stream->chip->shutdown_mutex); + if (ret < 0) return ret; subs->interface = fmt->iface; @@ -528,8 +532,10 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) subs->cur_rate = 0; subs->period_bytes = 0; mutex_lock(&subs->stream->chip->shutdown_mutex); - stop_endpoints(subs, 0, 1, 1); - deactivate_endpoints(subs); + if (!subs->stream->chip->shutdown) { + stop_endpoints(subs, 0, 1, 1); + deactivate_endpoints(subs); + } mutex_unlock(&subs->stream->chip->shutdown_mutex); return snd_pcm_lib_free_vmalloc_buffer(substream); } @@ -552,12 +558,19 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) return -ENXIO; } - if (snd_BUG_ON(!subs->data_endpoint)) - return -EIO; + mutex_lock(&subs->stream->chip->shutdown_mutex); + if (subs->stream->chip->shutdown) { + ret = -ENODEV; + goto unlock; + } + if (snd_BUG_ON(!subs->data_endpoint)) { + ret = -EIO; + goto unlock; + } ret = set_format(subs, subs->cur_audiofmt); if (ret < 0) - return ret; + goto unlock; iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; @@ -567,12 +580,12 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) subs->cur_audiofmt, subs->cur_rate); if (ret < 0) - return ret; + goto unlock; if (subs->need_setup_ep) { ret = configure_endpoint(subs); if (ret < 0) - return ret; + goto unlock; subs->need_setup_ep = false; } @@ -592,9 +605,11 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) /* for playback, submit the URBs now; otherwise, the first hwptr_done * updates for all URBs would happen at the same time when starting */ if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) - return start_endpoints(subs, 1); + ret = start_endpoints(subs, 1); - return 0; + unlock: + mutex_unlock(&subs->stream->chip->shutdown_mutex); + return ret; } static struct snd_pcm_hardware snd_usb_hardware = @@ -647,7 +662,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs, return 0; } /* check whether the period time is >= the data packet interval */ - if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) { + if (subs->speed != USB_SPEED_FULL) { ptime = 125 * (1 << fp->datainterval); if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); @@ -925,7 +940,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre return err; param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; - if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) + if (subs->speed == USB_SPEED_FULL) /* full speed devices have fixed data packet interval */ ptmin = 1000; if (ptmin == 1000) diff --git a/sound/usb/proc.c b/sound/usb/proc.c index ebc1a5b5b3f1..d218f763501f 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c @@ -108,7 +108,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s } snd_iprintf(buffer, "\n"); } - if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) + if (subs->speed != USB_SPEED_FULL) snd_iprintf(buffer, " Data packet interval: %d us\n", 125 * (1 << fp->datainterval)); // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); @@ -124,7 +124,7 @@ static void proc_dump_ep_status(struct snd_usb_substream *subs, return; snd_iprintf(buffer, " Packet Size = %d\n", ep->curpacksize); snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n", - snd_usb_get_speed(subs->dev) == USB_SPEED_FULL + subs->speed == USB_SPEED_FULL ? get_full_speed_hz(ep->freqm) : get_high_speed_hz(ep->freqm), ep->freqm >> 16, ep->freqm & 0xffff); diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 083ed81160e5..1de0c8c002a8 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -90,6 +90,7 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, subs->direction = stream; subs->dev = as->chip->dev; subs->txfr_quirk = as->chip->txfr_quirk; + subs->speed = snd_usb_get_speed(subs->dev); snd_usb_set_pcm_ops(as->pcm, stream); -- cgit v1.2.3 From 34f3c89fda4fba9fe689db22253ca8db2f5e6386 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 15 Oct 2012 12:16:02 +0200 Subject: ALSA: usb-audio: Use rwsem for disconnect protection Replace mutex with rwsem for codec->shutdown protection so that concurrent accesses are allowed. Also add the protection to snd_usb_autosuspend() and snd_usb_autoresume(), too. Reported-by: Matthieu CASTET Cc: Signed-off-by: Takashi Iwai --- sound/usb/card.c | 12 ++++++++---- sound/usb/mixer.c | 12 ++++++------ sound/usb/pcm.c | 12 ++++++------ sound/usb/usbaudio.h | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.c b/sound/usb/card.c index 561bb74fd364..282f0fc9fed1 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -339,7 +339,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, } mutex_init(&chip->mutex); - mutex_init(&chip->shutdown_mutex); + init_rwsem(&chip->shutdown_rwsem); chip->index = idx; chip->dev = dev; chip->card = card; @@ -560,7 +560,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, card = chip->card; mutex_lock(®ister_mutex); - mutex_lock(&chip->shutdown_mutex); + down_write(&chip->shutdown_rwsem); chip->shutdown = 1; chip->num_interfaces--; if (chip->num_interfaces <= 0) { @@ -582,11 +582,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, snd_usb_mixer_disconnect(p); } usb_chip[chip->index] = NULL; - mutex_unlock(&chip->shutdown_mutex); + up_write(&chip->shutdown_rwsem); mutex_unlock(®ister_mutex); snd_card_free_when_closed(card); } else { - mutex_unlock(&chip->shutdown_mutex); + up_write(&chip->shutdown_rwsem); mutex_unlock(®ister_mutex); } } @@ -618,16 +618,20 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) { int err = -ENODEV; + down_read(&chip->shutdown_rwsem); if (!chip->shutdown && !chip->probing) err = usb_autopm_get_interface(chip->pm_intf); + up_read(&chip->shutdown_rwsem); return err; } void snd_usb_autosuspend(struct snd_usb_audio *chip) { + down_read(&chip->shutdown_rwsem); if (!chip->shutdown && !chip->probing) usb_autopm_put_interface(chip->pm_intf); + up_read(&chip->shutdown_rwsem); } static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index c2ef11ccd66a..298070e8f2d4 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -292,7 +292,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v err = snd_usb_autoresume(cval->mixer->chip); if (err < 0) return -EIO; - mutex_lock(&chip->shutdown_mutex); + down_read(&chip->shutdown_rwsem); while (timeout-- > 0) { if (chip->shutdown) break; @@ -310,7 +310,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v err = -EINVAL; out: - mutex_unlock(&chip->shutdown_mutex); + up_read(&chip->shutdown_rwsem); snd_usb_autosuspend(cval->mixer->chip); return err; } @@ -337,7 +337,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v if (ret) goto error; - mutex_lock(&chip->shutdown_mutex); + down_read(&chip->shutdown_rwsem); if (chip->shutdown) ret = -ENODEV; else { @@ -346,7 +346,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, idx, buf, size); } - mutex_unlock(&chip->shutdown_mutex); + up_read(&chip->shutdown_rwsem); snd_usb_autosuspend(chip); if (ret < 0) { @@ -453,7 +453,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, err = snd_usb_autoresume(chip); if (err < 0) return -EIO; - mutex_lock(&chip->shutdown_mutex); + down_read(&chip->shutdown_rwsem); while (timeout-- > 0) { if (chip->shutdown) break; @@ -471,7 +471,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, err = -EINVAL; out: - mutex_unlock(&chip->shutdown_mutex); + up_read(&chip->shutdown_rwsem); snd_usb_autosuspend(chip); return err; } diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 55e741c5f231..37428f74dbb6 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -503,12 +503,12 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - mutex_lock(&subs->stream->chip->shutdown_mutex); + down_read(&subs->stream->chip->shutdown_rwsem); if (subs->stream->chip->shutdown) ret = -ENODEV; else ret = set_format(subs, fmt); - mutex_unlock(&subs->stream->chip->shutdown_mutex); + up_read(&subs->stream->chip->shutdown_rwsem); if (ret < 0) return ret; @@ -531,12 +531,12 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) subs->cur_audiofmt = NULL; subs->cur_rate = 0; subs->period_bytes = 0; - mutex_lock(&subs->stream->chip->shutdown_mutex); + down_read(&subs->stream->chip->shutdown_rwsem); if (!subs->stream->chip->shutdown) { stop_endpoints(subs, 0, 1, 1); deactivate_endpoints(subs); } - mutex_unlock(&subs->stream->chip->shutdown_mutex); + up_read(&subs->stream->chip->shutdown_rwsem); return snd_pcm_lib_free_vmalloc_buffer(substream); } @@ -558,7 +558,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) return -ENXIO; } - mutex_lock(&subs->stream->chip->shutdown_mutex); + down_read(&subs->stream->chip->shutdown_rwsem); if (subs->stream->chip->shutdown) { ret = -ENODEV; goto unlock; @@ -608,7 +608,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) ret = start_endpoints(subs, 1); unlock: - mutex_unlock(&subs->stream->chip->shutdown_mutex); + up_read(&subs->stream->chip->shutdown_rwsem); return ret; } diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index b8233ebe250f..ef42797f56fb 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -37,7 +37,7 @@ struct snd_usb_audio { struct usb_interface *pm_intf; u32 usb_id; struct mutex mutex; - struct mutex shutdown_mutex; + struct rw_semaphore shutdown_rwsem; unsigned int shutdown:1; unsigned int probing:1; unsigned int autosuspended:1; -- cgit v1.2.3 From 888ea7d5ac6815ba16b3b3a20f665a92c7af6724 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 15 Oct 2012 12:40:37 +0200 Subject: ALSA: usb-audio: Fix races at disconnection in mixer_quirks.c Similar like the previous commit, cover with chip->shutdown_rwsem and chip->shutdown checks. Reported-by: Matthieu CASTET Cc: Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 58 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 690000db0ec0..ae2b71435220 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -283,6 +283,11 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e if (value > 1) return -EINVAL; changed = value != mixer->audigy2nx_leds[index]; + down_read(&mixer->chip->shutdown_rwsem); + if (mixer->chip->shutdown) { + err = -ENODEV; + goto out; + } if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) err = snd_usb_ctl_msg(mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, @@ -299,6 +304,8 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, value, index + 2, NULL, 0); + out: + up_read(&mixer->chip->shutdown_rwsem); if (err < 0) return err; mixer->audigy2nx_leds[index] = value; @@ -392,11 +399,16 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, for (i = 0; jacks[i].name; ++i) { snd_iprintf(buffer, "%s: ", jacks[i].name); - err = snd_usb_ctl_msg(mixer->chip->dev, + down_read(&mixer->chip->shutdown_rwsem); + if (mixer->chip->shutdown) + err = 0; + else + err = snd_usb_ctl_msg(mixer->chip->dev, usb_rcvctrlpipe(mixer->chip->dev, 0), UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, jacks[i].unitid << 8, buf, 3); + up_read(&mixer->chip->shutdown_rwsem); if (err == 3 && (buf[0] == 3 || buf[0] == 6)) snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); else @@ -426,10 +438,15 @@ static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, else new_status = old_status & ~0x02; changed = new_status != old_status; - err = snd_usb_ctl_msg(mixer->chip->dev, + down_read(&mixer->chip->shutdown_rwsem); + if (mixer->chip->shutdown) + err = -ENODEV; + else + err = snd_usb_ctl_msg(mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 50, 0, &new_status, 1); + up_read(&mixer->chip->shutdown_rwsem); if (err < 0) return err; mixer->xonar_u1_status = new_status; @@ -468,11 +485,17 @@ static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, u8 bRequest = (kcontrol->private_value >> 16) & 0xff; u16 wIndex = kcontrol->private_value & 0xffff; u8 tmp; + int ret; - int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, + down_read(&mixer->chip->shutdown_rwsem); + if (mixer->chip->shutdown) + ret = -ENODEV; + else + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 0, cpu_to_le16(wIndex), &tmp, sizeof(tmp), 1000); + up_read(&mixer->chip->shutdown_rwsem); if (ret < 0) { snd_printk(KERN_ERR @@ -493,11 +516,17 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, u8 bRequest = (kcontrol->private_value >> 16) & 0xff; u16 wIndex = kcontrol->private_value & 0xffff; u16 wValue = ucontrol->value.integer.value[0]; + int ret; - int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest, + down_read(&mixer->chip->shutdown_rwsem); + if (mixer->chip->shutdown) + ret = -ENODEV; + else + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, cpu_to_le16(wValue), cpu_to_le16(wIndex), NULL, 0, 1000); + up_read(&mixer->chip->shutdown_rwsem); if (ret < 0) { snd_printk(KERN_ERR @@ -656,11 +685,16 @@ static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, return -EINVAL; - err = snd_usb_ctl_msg(chip->dev, + down_read(&mixer->chip->shutdown_rwsem); + if (mixer->chip->shutdown) + err = -ENODEV; + else + err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), value, val_len); + up_read(&mixer->chip->shutdown_rwsem); if (err < 0) return err; @@ -703,11 +737,16 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, if (!pval->is_cached) { /* Read current value */ - err = snd_usb_ctl_msg(chip->dev, + down_read(&mixer->chip->shutdown_rwsem); + if (mixer->chip->shutdown) + err = -ENODEV; + else + err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), value, val_len); + up_read(&mixer->chip->shutdown_rwsem); if (err < 0) return err; @@ -719,11 +758,16 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, if (cur_val != new_val) { value[0] = new_val; value[1] = 0; - err = snd_usb_ctl_msg(chip->dev, + down_read(&mixer->chip->shutdown_rwsem); + if (mixer->chip->shutdown) + err = -ENODEV; + else + err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), value, val_len); + up_read(&mixer->chip->shutdown_rwsem); if (err < 0) return err; -- cgit v1.2.3 From a0830dbd4e42b38aefdf3fb61ba5019a1a99ea85 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 16 Oct 2012 13:05:59 +0200 Subject: ALSA: Add a reference counter to card instance For more strict protection for wild disconnections, a refcount is introduced to the card instance, and let it up/down when an object is referred via snd_lookup_*() in the open ops. The free-after-last-close check is also changed to check this refcount instead of the empty list, too. Reported-by: Matthieu CASTET Cc: Signed-off-by: Takashi Iwai --- sound/core/compress_offload.c | 9 ++++++-- sound/core/control.c | 3 +++ sound/core/hwdep.c | 5 ++++- sound/core/init.c | 50 ++++++++++++++++++++++++++----------------- sound/core/oss/mixer_oss.c | 10 +++++++-- sound/core/oss/pcm_oss.c | 2 ++ sound/core/pcm_native.c | 9 ++++++-- sound/core/rawmidi.c | 6 +++++- sound/core/sound.c | 11 ++++++++-- sound/core/sound_oss.c | 10 +++++++-- 10 files changed, 83 insertions(+), 32 deletions(-) (limited to 'sound') diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index c40ae573346d..ad11dc994792 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -100,12 +100,15 @@ static int snd_compr_open(struct inode *inode, struct file *f) if (dirn != compr->direction) { pr_err("this device doesn't support this direction\n"); + snd_card_unref(compr->card); return -EINVAL; } data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) + if (!data) { + snd_card_unref(compr->card); return -ENOMEM; + } data->stream.ops = compr->ops; data->stream.direction = dirn; data->stream.private_data = compr->private_data; @@ -113,6 +116,7 @@ static int snd_compr_open(struct inode *inode, struct file *f) runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); if (!runtime) { kfree(data); + snd_card_unref(compr->card); return -ENOMEM; } runtime->state = SNDRV_PCM_STATE_OPEN; @@ -126,7 +130,8 @@ static int snd_compr_open(struct inode *inode, struct file *f) kfree(runtime); kfree(data); } - return ret; + snd_card_unref(compr->card); + return 0; } static int snd_compr_free(struct inode *inode, struct file *f) diff --git a/sound/core/control.c b/sound/core/control.c index 7e86a5b9f3b5..9768a3963c8f 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -86,6 +86,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file) write_lock_irqsave(&card->ctl_files_rwlock, flags); list_add_tail(&ctl->list, &card->ctl_files); write_unlock_irqrestore(&card->ctl_files_rwlock, flags); + snd_card_unref(card); return 0; __error: @@ -93,6 +94,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file) __error2: snd_card_file_remove(card, file); __error1: + if (card) + snd_card_unref(card); return err; } diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 75ea16f35b1a..53a6ba5ad615 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -100,8 +100,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) if (hw == NULL) return -ENODEV; - if (!try_module_get(hw->card->module)) + if (!try_module_get(hw->card->module)) { + snd_card_unref(hw->card); return -EFAULT; + } init_waitqueue_entry(&wait, current); add_wait_queue(&hw->open_wait, &wait); @@ -148,6 +150,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) mutex_unlock(&hw->open_mutex); if (err < 0) module_put(hw->card->module); + snd_card_unref(hw->card); return err; } diff --git a/sound/core/init.c b/sound/core/init.c index d8ec849af128..7b012d15c2cf 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -213,6 +213,7 @@ int snd_card_create(int idx, const char *xid, spin_lock_init(&card->files_lock); INIT_LIST_HEAD(&card->files_list); init_waitqueue_head(&card->shutdown_sleep); + atomic_set(&card->refcount, 0); #ifdef CONFIG_PM mutex_init(&card->power_lock); init_waitqueue_head(&card->power_sleep); @@ -446,21 +447,36 @@ static int snd_card_do_free(struct snd_card *card) return 0; } +/** + * snd_card_unref - release the reference counter + * @card: the card instance + * + * Decrements the reference counter. When it reaches to zero, wake up + * the sleeper and call the destructor if needed. + */ +void snd_card_unref(struct snd_card *card) +{ + if (atomic_dec_and_test(&card->refcount)) { + wake_up(&card->shutdown_sleep); + if (card->free_on_last_close) + snd_card_do_free(card); + } +} +EXPORT_SYMBOL(snd_card_unref); + int snd_card_free_when_closed(struct snd_card *card) { - int free_now = 0; - int ret = snd_card_disconnect(card); - if (ret) - return ret; + int ret; - spin_lock(&card->files_lock); - if (list_empty(&card->files_list)) - free_now = 1; - else - card->free_on_last_close = 1; - spin_unlock(&card->files_lock); + atomic_inc(&card->refcount); + ret = snd_card_disconnect(card); + if (ret) { + atomic_dec(&card->refcount); + return ret; + } - if (free_now) + card->free_on_last_close = 1; + if (atomic_dec_and_test(&card->refcount)) snd_card_do_free(card); return 0; } @@ -474,7 +490,7 @@ int snd_card_free(struct snd_card *card) return ret; /* wait, until all devices are ready for the free operation */ - wait_event(card->shutdown_sleep, list_empty(&card->files_list)); + wait_event(card->shutdown_sleep, !atomic_read(&card->refcount)); snd_card_do_free(card); return 0; } @@ -886,6 +902,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file) return -ENODEV; } list_add(&mfile->list, &card->files_list); + atomic_inc(&card->refcount); spin_unlock(&card->files_lock); return 0; } @@ -908,7 +925,6 @@ EXPORT_SYMBOL(snd_card_file_add); int snd_card_file_remove(struct snd_card *card, struct file *file) { struct snd_monitor_file *mfile, *found = NULL; - int last_close = 0; spin_lock(&card->files_lock); list_for_each_entry(mfile, &card->files_list, list) { @@ -923,19 +939,13 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) break; } } - if (list_empty(&card->files_list)) - last_close = 1; spin_unlock(&card->files_lock); - if (last_close) { - wake_up(&card->shutdown_sleep); - if (card->free_on_last_close) - snd_card_do_free(card); - } if (!found) { snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); return -ENOENT; } kfree(found); + snd_card_unref(card); return 0; } diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 29f6ded02555..a9a2e63c0222 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -52,14 +52,19 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file) SNDRV_OSS_DEVICE_TYPE_MIXER); if (card == NULL) return -ENODEV; - if (card->mixer_oss == NULL) + if (card->mixer_oss == NULL) { + snd_card_unref(card); return -ENODEV; + } err = snd_card_file_add(card, file); - if (err < 0) + if (err < 0) { + snd_card_unref(card); return err; + } fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL); if (fmixer == NULL) { snd_card_file_remove(card, file); + snd_card_unref(card); return -ENOMEM; } fmixer->card = card; @@ -68,6 +73,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file) if (!try_module_get(card->module)) { kfree(fmixer); snd_card_file_remove(card, file); + snd_card_unref(card); return -EFAULT; } return 0; diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 08fde0060fd9..2529e01538e9 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -2457,6 +2457,8 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) __error2: snd_card_file_remove(pcm->card, file); __error1: + if (pcm) + snd_card_unref(pcm->card); return err; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 8753c89f3290..48c6a70ad69e 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1642,6 +1642,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); _nolock: + snd_card_unref(substream1->pcm->card); fput_light(file, fput_needed); if (res < 0) kfree(group); @@ -2116,7 +2117,9 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file) return err; pcm = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_PCM_PLAYBACK); - return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); + err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); + snd_card_unref(pcm->card); + return err; } static int snd_pcm_capture_open(struct inode *inode, struct file *file) @@ -2127,7 +2130,9 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file) return err; pcm = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_PCM_CAPTURE); - return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); + err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); + snd_card_unref(pcm->card); + return err; } static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index ebf6e49ad3d4..7d4f62ab6711 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -379,8 +379,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) if (rmidi == NULL) return -ENODEV; - if (!try_module_get(rmidi->card->module)) + if (!try_module_get(rmidi->card->module)) { + snd_card_unref(rmidi->card); return -ENXIO; + } mutex_lock(&rmidi->open_mutex); card = rmidi->card; @@ -440,6 +442,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) #endif file->private_data = rawmidi_file; mutex_unlock(&rmidi->open_mutex); + snd_card_unref(rmidi->card); return 0; __error: @@ -447,6 +450,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) __error_card: mutex_unlock(&rmidi->open_mutex); module_put(rmidi->card->module); + snd_card_unref(rmidi->card); return err; } diff --git a/sound/core/sound.c b/sound/core/sound.c index 643976000ce8..89780c323f19 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -98,6 +98,10 @@ static void snd_request_other(int minor) * * Checks that a minor device with the specified type is registered, and returns * its user data pointer. + * + * This function increments the reference counter of the card instance + * if an associated instance with the given minor number and type is found. + * The caller must call snd_card_unref() appropriately later. */ void *snd_lookup_minor_data(unsigned int minor, int type) { @@ -108,9 +112,11 @@ void *snd_lookup_minor_data(unsigned int minor, int type) return NULL; mutex_lock(&sound_mutex); mreg = snd_minors[minor]; - if (mreg && mreg->type == type) + if (mreg && mreg->type == type) { private_data = mreg->private_data; - else + if (mreg->card_ptr) + atomic_inc(&mreg->card_ptr->refcount); + } else private_data = NULL; mutex_unlock(&sound_mutex); return private_data; @@ -275,6 +281,7 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev, preg->device = dev; preg->f_ops = f_ops; preg->private_data = private_data; + preg->card_ptr = card; mutex_lock(&sound_mutex); #ifdef CONFIG_SND_DYNAMIC_MINORS minor = snd_find_free_minor(type); diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index e9528333e36d..e1d79ee35906 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c @@ -40,6 +40,9 @@ static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS]; static DEFINE_MUTEX(sound_oss_mutex); +/* NOTE: This function increments the refcount of the associated card like + * snd_lookup_minor_data(); the caller must call snd_card_unref() appropriately + */ void *snd_lookup_oss_minor_data(unsigned int minor, int type) { struct snd_minor *mreg; @@ -49,9 +52,11 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type) return NULL; mutex_lock(&sound_oss_mutex); mreg = snd_oss_minors[minor]; - if (mreg && mreg->type == type) + if (mreg && mreg->type == type) { private_data = mreg->private_data; - else + if (mreg->card_ptr) + atomic_inc(&mreg->card_ptr->refcount); + } else private_data = NULL; mutex_unlock(&sound_oss_mutex); return private_data; @@ -123,6 +128,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev, preg->device = dev; preg->f_ops = f_ops; preg->private_data = private_data; + preg->card_ptr = card; mutex_lock(&sound_oss_mutex); snd_oss_minors[minor] = preg; minor_unit = SNDRV_MINOR_OSS_DEVICE(minor); -- cgit v1.2.3 From 0914f7961babbf28aaa2f19b453951fb4841c03f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 16 Oct 2012 16:43:39 +0200 Subject: ALSA: Avoid endless sleep after disconnect When disconnect callback is called, each component should wake up sleepers and check card->shutdown flag for avoiding the endless sleep blocking the proper resource release. Cc: Signed-off-by: Takashi Iwai --- sound/core/control.c | 2 ++ sound/core/hwdep.c | 7 +++++++ sound/core/oss/pcm_oss.c | 4 ++++ sound/core/pcm.c | 6 +++++- sound/core/pcm_native.c | 8 ++++++++ sound/core/rawmidi.c | 20 ++++++++++++++++++++ 6 files changed, 46 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index 9768a3963c8f..8c7c2c9bba61 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1437,6 +1437,8 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer, spin_unlock_irq(&ctl->read_lock); schedule(); remove_wait_queue(&ctl->change_sleep, &wait); + if (ctl->card->shutdown) + return -ENODEV; if (signal_pending(current)) return -ERESTARTSYS; spin_lock_irq(&ctl->read_lock); diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 53a6ba5ad615..3f7f6628cf7b 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -131,6 +131,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) mutex_unlock(&hw->open_mutex); schedule(); mutex_lock(&hw->open_mutex); + if (hw->card->shutdown) { + err = -ENODEV; + break; + } if (signal_pending(current)) { err = -ERESTARTSYS; break; @@ -462,12 +466,15 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device) mutex_unlock(®ister_mutex); return -EINVAL; } + mutex_lock(&hwdep->open_mutex); + wake_up(&hwdep->open_wait); #ifdef CONFIG_SND_OSSEMUL if (hwdep->ossreg) snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); #endif snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); list_del_init(&hwdep->list); + mutex_unlock(&hwdep->open_mutex); mutex_unlock(®ister_mutex); return 0; } diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 2529e01538e9..f337b66a020b 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -2441,6 +2441,10 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) mutex_unlock(&pcm->open_mutex); schedule(); mutex_lock(&pcm->open_mutex); + if (pcm->card->shutdown) { + err = -ENODEV; + break; + } if (signal_pending(current)) { err = -ERESTARTSYS; break; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 993b2405fdfe..030102caeee9 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1087,12 +1087,16 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) goto unlock; mutex_lock(&pcm->open_mutex); + wake_up(&pcm->open_wait); list_del_init(&pcm->list); for (cidx = 0; cidx < 2; cidx++) for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { snd_pcm_stream_lock_irq(substream); - if (substream->runtime) + if (substream->runtime) { substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; + wake_up(&substream->runtime->sleep); + wake_up(&substream->runtime->tsleep); + } snd_pcm_stream_unlock_irq(substream); } list_for_each_entry(notify, &snd_pcm_notify_list, list) { diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 48c6a70ad69e..6e8872de5ba0 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1518,6 +1518,10 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, down_read(&snd_pcm_link_rwsem); snd_pcm_stream_lock_irq(substream); remove_wait_queue(&to_check->sleep, &wait); + if (card->shutdown) { + result = -ENODEV; + break; + } if (tout == 0) { if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) result = -ESTRPIPE; @@ -2169,6 +2173,10 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) mutex_unlock(&pcm->open_mutex); schedule(); mutex_lock(&pcm->open_mutex); + if (pcm->card->shutdown) { + err = -ENODEV; + break; + } if (signal_pending(current)) { err = -ERESTARTSYS; break; diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 7d4f62ab6711..1bb95aeea084 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -424,6 +424,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) mutex_unlock(&rmidi->open_mutex); schedule(); mutex_lock(&rmidi->open_mutex); + if (rmidi->card->shutdown) { + err = -ENODEV; + break; + } if (signal_pending(current)) { err = -ERESTARTSYS; break; @@ -995,6 +999,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun spin_unlock_irq(&runtime->lock); schedule(); remove_wait_queue(&runtime->sleep, &wait); + if (rfile->rmidi->card->shutdown) + return -ENODEV; if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; if (!runtime->avail) @@ -1238,6 +1244,8 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, spin_unlock_irq(&runtime->lock); timeout = schedule_timeout(30 * HZ); remove_wait_queue(&runtime->sleep, &wait); + if (rfile->rmidi->card->shutdown) + return -ENODEV; if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; if (!runtime->avail && !timeout) @@ -1613,9 +1621,20 @@ static int snd_rawmidi_dev_register(struct snd_device *device) static int snd_rawmidi_dev_disconnect(struct snd_device *device) { struct snd_rawmidi *rmidi = device->device_data; + int dir; mutex_lock(®ister_mutex); + mutex_lock(&rmidi->open_mutex); + wake_up(&rmidi->open_wait); list_del_init(&rmidi->list); + for (dir = 0; dir < 2; dir++) { + struct snd_rawmidi_substream *s; + list_for_each_entry(s, &rmidi->streams[dir].substreams, list) { + if (s->runtime) + wake_up(&s->runtime->sleep); + } + } + #ifdef CONFIG_SND_OSSEMUL if (rmidi->ossreg) { if ((int)rmidi->device == midi_map[rmidi->card->number]) { @@ -1630,6 +1649,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) } #endif /* CONFIG_SND_OSSEMUL */ snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); + mutex_unlock(&rmidi->open_mutex); mutex_unlock(®ister_mutex); return 0; } -- cgit v1.2.3 From 16c2e1fae8d60a9d6d16e009a76ba3472568e094 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 31 Oct 2012 07:41:42 +0100 Subject: ALSA: ice1724: Fix rate setup after resume The rate isn't restored properly after resume since it's only set up in hw_params, and not in prepare callback. For fixing it, put the corresponding call to resume callback as well. Reported-and-tested-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1724.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 3050a5279253..245d874891ba 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2859,7 +2859,12 @@ static int snd_vt1724_resume(struct device *dev) ice->set_spdif_clock(ice, 0); } else { /* internal on-card clock */ - snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1); + int rate; + if (ice->cur_rate) + rate = ice->cur_rate; + else + rate = ice->pro_rate_default; + snd_vt1724_set_pro_rate(ice, rate, 1); } update_spdif_bits(ice, ice->pm_saved_spdif_ctrl); -- cgit v1.2.3