The newly added CODEC to CODEC DAI link widget pointers in snd_soc_dai_link are better placed in snd_soc_pcm_runtime. snd_soc_dai_link is really intended for static configuration of the DAI, and the runtime for dynamic data. The snd_soc_dai_link structures are not destroyed if the card is unbound. The widgets are cleared up on unbind, however if the card is rebound as the snd_soc_dai_link structures are reused these pointers will be left at their old values, causing access to freed memory.
Fixes: 595571cca4de ("ASoC: dapm: Fix regression introducing multiple copies of DAI widgets") Signed-off-by: Charles Keepax ckeepax@opensource.cirrus.com --- include/sound/soc.h | 6 +++--- sound/soc/soc-dapm.c | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index a7fa642601081..ba07cdfcdcee4 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -801,9 +801,6 @@ struct snd_soc_dai_link { const struct snd_soc_pcm_stream *params; unsigned int num_params;
- struct snd_soc_dapm_widget *playback_widget; - struct snd_soc_dapm_widget *capture_widget; - unsigned int dai_fmt; /* format to set on init */
enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */ @@ -1169,6 +1166,9 @@ struct snd_soc_pcm_runtime { unsigned int num_codecs; unsigned int num_cpus;
+ struct snd_soc_dapm_widget *playback_widget; + struct snd_soc_dapm_widget *capture_widget; + struct delayed_work delayed_work; void (*close_delayed_work_func)(struct snd_soc_pcm_runtime *rtd); #ifdef CONFIG_DEBUG_FS diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index a4de3e4bc2eff..fc40f283a2480 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4340,16 +4340,16 @@ static void dapm_connect_dai_pair(struct snd_soc_card *card, codec = codec_dai->playback_widget;
if (playback_cpu && codec) { - if (dai_link->params && !dai_link->playback_widget) { + if (dai_link->params && !rtd->playback_widget) { substream = streams[SNDRV_PCM_STREAM_PLAYBACK].substream; dai = snd_soc_dapm_new_dai(card, substream, "playback"); if (IS_ERR(dai)) goto capture; - dai_link->playback_widget = dai; + rtd->playback_widget = dai; }
dapm_connect_dai_routes(&card->dapm, cpu_dai, playback_cpu, - dai_link->playback_widget, + rtd->playback_widget, codec_dai, codec); }
@@ -4358,16 +4358,16 @@ static void dapm_connect_dai_pair(struct snd_soc_card *card, codec = codec_dai->capture_widget;
if (codec && capture_cpu) { - if (dai_link->params && !dai_link->capture_widget) { + if (dai_link->params && !rtd->capture_widget) { substream = streams[SNDRV_PCM_STREAM_CAPTURE].substream; dai = snd_soc_dapm_new_dai(card, substream, "capture"); if (IS_ERR(dai)) return; - dai_link->capture_widget = dai; + rtd->capture_widget = dai; }
dapm_connect_dai_routes(&card->dapm, codec_dai, codec, - dai_link->capture_widget, + rtd->capture_widget, cpu_dai, capture_cpu); } }