/* Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * max98357a.c -- MAX98357A ALSA SoC Codec driver */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int max98357a_daiops_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct gpio_desc *sdmode = snd_soc_dai_get_drvdata(dai); if (!sdmode) return 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: gpiod_set_value(sdmode, 1); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: gpiod_set_value(sdmode, 0); break; } return 0; } static const struct snd_soc_dapm_widget max98357a_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("Speaker"), }; static const struct snd_soc_dapm_route max98357a_dapm_routes[] = { {"Speaker", NULL, "HiFi Playback"}, }; static int max98357a_codec_probe(struct snd_soc_codec *codec) { struct gpio_desc *sdmode; sdmode = devm_gpiod_get_optional(codec->dev, "sdmode", GPIOD_OUT_LOW); if (IS_ERR(sdmode)) return PTR_ERR(sdmode); snd_soc_codec_set_drvdata(codec, sdmode); return 0; } static struct snd_soc_codec_driver max98357a_codec_driver = { .probe = max98357a_codec_probe, .component_driver = { .dapm_widgets = max98357a_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(max98357a_dapm_widgets), .dapm_routes = max98357a_dapm_routes, .num_dapm_routes = ARRAY_SIZE(max98357a_dapm_routes), }, }; static const struct snd_soc_dai_ops max98357a_dai_ops = { .trigger = max98357a_daiops_trigger, }; static struct snd_soc_dai_driver max98357a_dai_driver = { .name = "HiFi", .playback = { .stream_name = "HiFi Playback", .formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_S32, .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000, .rate_min = 8000, .rate_max = 96000, .channels_min = 1, .channels_max = 2, }, .ops = &max98357a_dai_ops, }; static int max98357a_platform_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &max98357a_codec_driver, &max98357a_dai_driver, 1); } static int max98357a_platform_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); return 0; } #ifdef CONFIG_OF static const struct of_device_id max98357a_device_id[] = { { .compatible = "maxim,max98357a" }, {} }; MODULE_DEVICE_TABLE(of, max98357a_device_id); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id max98357a_acpi_match[] = { { "MX98357A", 0 }, {}, }; MODULE_DEVICE_TABLE(acpi, max98357a_acpi_match); #endif static struct platform_driver max98357a_platform_driver = { .driver = { .name = "max98357a", .of_match_table = of_match_ptr(max98357a_device_id), .acpi_match_table = ACPI_PTR(max98357a_acpi_match), }, .probe = max98357a_platform_probe, .remove = max98357a_platform_remove, }; module_platform_driver(max98357a_platform_driver); MODULE_DESCRIPTION("Maxim MAX98357A Codec Driver"); MODULE_LICENSE("GPL v2"); tion>space:mode:
authorIago Abal <mail@iagoabal.eu>2017-01-11 14:00:21 +0100
committerVinod Koul <vinod.koul@intel.com>2017-01-25 15:35:11 +0530
commit91539eb1fda2d530d3b268eef542c5414e54bf1a (patch)
tree960f5ca6342ad20837aff18aad6e8ecd7da32fd6 /net/9p/trans_common.c
parent6610d0edf6dc7ee97e46ab3a538a565c79d26199 (diff)
dmaengine: pl330: fix double lock
The static bug finder EBA (http://www.iagoabal.eu/eba/) reported the following double-lock bug: Double lock: 1. spin_lock_irqsave(pch->lock, flags) at pl330_free_chan_resources:2236; 2. call to function `pl330_release_channel' immediately after; 3. call to function `dma_pl330_rqcb' in line 1753; 4. spin_lock_irqsave(pch->lock, flags) at dma_pl330_rqcb:1505. I have fixed it as suggested by Marek Szyprowski. First, I have replaced `pch->lock' with `pl330->lock' in functions `pl330_alloc_chan_resources' and `pl330_free_chan_resources'. This avoids the double-lock by acquiring a different lock than `dma_pl330_rqcb'. NOTE that, as a result, `pl330_free_chan_resources' executes `list_splice_tail_init' on `pch->work_list' under lock `pl330->lock', whereas in the rest of the code `pch->work_list' is protected by `pch->lock'. I don't know if this may cause race conditions. Similarly `pch->cyclic' is written by `pl330_alloc_chan_resources' under `pl330->lock' but read by `pl330_tx_submit' under `pch->lock'. Second, I have removed locking from `pl330_request_channel' and `pl330_release_channel' functions. Function `pl330_request_channel' is only called from `pl330_alloc_chan_resources', so the lock is already held. Function `pl330_release_channel' is called from `pl330_free_chan_resources', which already holds the lock, and from `pl330_del'. Function `pl330_del' is called in an error path of `pl330_probe' and at the end of `pl330_remove', but I assume that there cannot be concurrent accesses to the protected data at those points. Signed-off-by: Iago Abal <mail@iagoabal.eu> Reviewed-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'net/9p/trans_common.c')