Current ALSA SoC Sound Card basically consists of CPU/Codec/Platform drivers. If system uses Kernel modules, we can disable these drivers by using rmmod command. In such case, we can't disable CPU/Codec/Platform driver without disabling Sound Card driver.
But on the other hand, we can disable these drivers by using unbind command. In such case, we can disable these drivers randomly. In this case, we can create dirty Sound Card which is missing necessary components.
(1) If user disabled Sound Card first, but did nothing to other drivers, user can't use Sound because Sound Card is no longer exists. (2) If user disabled CPU/Codec/Platform driver randomly, but did nothing to Sound Card, user still be able to use Sound Card, because dirty Sound Card which is missing necessary components still exists. In this case, Sound system will be crashed if user started sound playback/capture. But we can't block such random unbind now.
To avoid Sound Card crash in (2) case, what we can do now is, add dirty flag on Sound Card, and avoid to open Sound Card. This patch solved this issue.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- Mark, Lars-Peter
This is still RFC, but I think we need to consider about this issue. I tested this patch on my system, and it can block to sound card crash for me
include/sound/soc.h | 6 ++++-- sound/soc/soc-core.c | 12 +++++++++++- sound/soc/soc-pcm.c | 20 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index 316fdce..4813fc5 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1106,8 +1106,6 @@ struct snd_soc_card { struct mutex mutex; struct mutex dapm_mutex;
- bool instantiated; - int (*probe)(struct snd_soc_card *card); int (*late_probe)(struct snd_soc_card *card); int (*remove)(struct snd_soc_card *card); @@ -1197,6 +1195,10 @@ struct snd_soc_card { u32 pop_time;
void *drvdata; + + /* bit field */ + u32 instantiated:1; + u32 dirty:1; };
/* SoC machine DAI configuration, glues a codec and cpu DAI together */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 07e4eec..a18e106 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2882,7 +2882,15 @@ int snd_soc_unregister_card(struct snd_soc_card *card) { if (card->instantiated) { card->instantiated = false; - snd_soc_dapm_shutdown(card); + if (!card->dirty) { + /* + * In case of unbind, CPU/Codec/Platform component can + * be unbinded *before* Card unbind. In such case + * (= card->dirty) Card connected DAPMs are already + * doesn't exist. + */ + snd_soc_dapm_shutdown(card); + } soc_cleanup_card_resources(card); dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); } @@ -3236,6 +3244,8 @@ static void snd_soc_component_cleanup(struct snd_soc_component *component)
static void snd_soc_component_del_unlocked(struct snd_soc_component *component) { + if (component->card) + component->card->dirty = 1; list_del(&component->list); }
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index efc5831..c861aba 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -455,6 +455,16 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) const char *codec_dai_name = "multicodec"; int i, ret = 0;
+ if (rtd->card->dirty) { + /* + * In case of unbind, each CPU/Codec/Platform component can + * be unbinded randomly. In such case (= card->dirty) + * Sound Card is no longer safety. Don't open it. + */ + dev_warn(cpu_dai->dev, "Sound SoC Card is dirty, Recheck your system\n"); + return -ENXIO; + } + pinctrl_pm_select_default_state(cpu_dai->dev); for (i = 0; i < rtd->num_codecs; i++) pinctrl_pm_select_default_state(rtd->codec_dais[i]->dev); @@ -2577,6 +2587,16 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) int ret; int stream = fe_substream->stream;
+ if (fe->card->dirty) { + /* + * In case of unbind, each CPU/Codec/Platform component can + * be unbinded randomly. In such case (= card->dirty) + * Sound Card is no longer safety. Don't open it. + */ + dev_warn(fe->dev, "Sound SoC Card is dirty, Recheck your system\n"); + return -ENXIO; + } + mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); fe->dpcm[stream].runtime = fe_substream->runtime;