Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: soc-pcm.c: Make sure DAI parameters cleared if the DAI becomes inactive

The commit 1da681e52853 ("ASoC: soc-pcm.c: Clear DAIs parameters after
stream_active is updated") tries to make sure DAI parameters can be
cleared properly through moving the cleanup to the place where stream
active status is updated. However, it will cause the cleanup only
happening in soc_pcm_close().

Suppose a case: aplay -Dhw:0 44100.wav 48000.wav. The case calls
soc_pcm_open()->soc_pcm_hw_params()->soc_pcm_hw_free()->
soc_pcm_hw_params()->soc_pcm_hw_free()->soc_pcm_close() in order. The
parameters would be remained in the system even if the playback of
44100.wav is finished.

The case requires us clearing parameters in phase of soc_pcm_hw_free().
However, moving the DAI parameters cleanup back to soc_pcm_hw_free()
has the risk that DAIs parameters never be cleared if there're more
than one stream, see commit 1da681e52853 ("ASoC: soc-pcm.c: Clear DAIs
parameters after stream_active is updated") for more details.

To meet all these requirements, in addition to do DAI parameters
cleanup in soc_pcm_hw_free(), also check it in soc_pcm_close() to make
sure DAI parameters cleared if the DAI becomes inactive.

Fixes: 1da681e52853 ("ASoC: soc-pcm.c: Clear DAIs parameters after stream_active is updated")
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
Link: https://lore.kernel.org/r/20230920153621.711373-2-chancel.liu@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Chancel Liu and committed by
Mark Brown
3efcb471 ad484cc9

+14 -7
+14 -7
sound/soc/soc-pcm.c
··· 698 698 699 699 if (!rollback) { 700 700 snd_soc_runtime_deactivate(rtd, substream->stream); 701 - /* clear the corresponding DAIs parameters when going to be inactive */ 702 - for_each_rtd_dais(rtd, i, dai) { 703 - if (snd_soc_dai_active(dai) == 0) 704 - soc_pcm_set_dai_params(dai, NULL); 705 701 706 - if (snd_soc_dai_stream_active(dai, substream->stream) == 0) 707 - snd_soc_dai_digital_mute(dai, 1, substream->stream); 708 - } 702 + /* Make sure DAI parameters cleared if the DAI becomes inactive */ 703 + for_each_rtd_dais(rtd, i, dai) 704 + if (snd_soc_dai_active(dai) == 0 && 705 + (dai->rate || dai->channels || dai->sample_bits)) 706 + soc_pcm_set_dai_params(dai, NULL); 709 707 } 710 708 711 709 for_each_rtd_dais(rtd, i, dai) ··· 933 935 int i; 934 936 935 937 snd_soc_dpcm_mutex_assert_held(rtd); 938 + 939 + /* clear the corresponding DAIs parameters when going to be inactive */ 940 + for_each_rtd_dais(rtd, i, dai) { 941 + if (snd_soc_dai_active(dai) == 1) 942 + soc_pcm_set_dai_params(dai, NULL); 943 + 944 + if (snd_soc_dai_stream_active(dai, substream->stream) == 1) 945 + snd_soc_dai_digital_mute(dai, 1, substream->stream); 946 + } 936 947 937 948 /* run the stream event */ 938 949 snd_soc_dapm_stream_stop(rtd, substream->stream);