ASoC: soc-pcm: add soc_pcm_clean() and call it from soc_pcm_open/close()
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Mon, 28 Sep 2020 00:01:24 +0000 (09:01 +0900)
committerMark Brown <broonie@kernel.org>
Mon, 28 Sep 2020 16:01:45 +0000 (17:01 +0100)
soc_pcm_open() does rollback when failed (A),
but, it is almost same as soc_pcm_close().

static int soc_pcm_open(xxx)
{
...
if (ret < 0)
goto xxx_err;
...
return 0;

 ^ config_err:
 | ...
 | rtd_startup_err:
(A) ...
 | component_err:
 | ...
 v return ret;
}

The difference is
soc_pcm_close() is for all dai/component/substream,
rollback        is for succeeded part only.

This kind of duplicated code can be a hotbed of bugs,
thus, we want to share soc_pcm_close() and rollback.

Now, soc_pcm_open/close() are handling
1) snd_soc_dai_startup/shutdown()
2) snd_soc_link_startup/shutdown()
3) snd_soc_component_module_get/put()
4) snd_soc_component_open/close()
5) pm_runtime_put/get()

Now, 1) to 5) are handled.
This patch adds new soc_pcm_clean() and call it from
soc_pcm_open() as rollback, and from soc_pcm_close() as
normal close handler.

One note here is that it don't need to call snd_soc_runtime_deactivate()
when rollback case, because it will be called without
snd_soc_runtime_activate().
It also don't need to call snd_soc_dapm_stream_stop() when rollback case.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87ft72bwn4.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/soc-pcm.c

index 0934a06a9cc95234a097be7af518771bfd683ec8..7f3e44918f19f0fe5893d3f829cda340e7eeeba9 100644 (file)
@@ -651,12 +651,7 @@ static int soc_pcm_components_close(struct snd_pcm_substream *substream,
        return ret;
 }
 
-/*
- * Called by ALSA when a PCM substream is closed. Private data can be
- * freed here. The cpu DAI, codec DAI, machine and components are also
- * shutdown.
- */
-static int soc_pcm_close(struct snd_pcm_substream *substream)
+static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback)
 {
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_component *component;
@@ -665,20 +660,22 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
 
        mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
 
-       snd_soc_runtime_deactivate(rtd, substream->stream);
+       if (!rollback)
+               snd_soc_runtime_deactivate(rtd, substream->stream);
 
        for_each_rtd_dais(rtd, i, dai)
-               snd_soc_dai_shutdown(dai, substream, 0);
+               snd_soc_dai_shutdown(dai, substream, rollback);
 
-       snd_soc_link_shutdown(substream, 0);
+       snd_soc_link_shutdown(substream, rollback);
 
-       soc_pcm_components_close(substream, 0);
+       soc_pcm_components_close(substream, rollback);
 
-       snd_soc_dapm_stream_stop(rtd, substream->stream);
+       if (!rollback)
+               snd_soc_dapm_stream_stop(rtd, substream->stream);
 
        mutex_unlock(&rtd->card->pcm_mutex);
 
-       snd_soc_pcm_component_pm_runtime_put(rtd, substream, 0);
+       snd_soc_pcm_component_pm_runtime_put(rtd, substream, rollback);
 
        for_each_rtd_components(rtd, i, component)
                if (!snd_soc_component_active(component))
@@ -687,6 +684,16 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
+/*
+ * Called by ALSA when a PCM substream is closed. Private data can be
+ * freed here. The cpu DAI, codec DAI, machine and components are also
+ * shutdown.
+ */
+static int soc_pcm_close(struct snd_pcm_substream *substream)
+{
+       return soc_pcm_clean(substream, 0);
+}
+
 /*
  * Called by ALSA when a PCM substream is opened, the runtime->hw record is
  * then initialized and any private data can be allocated. This also calls
@@ -707,17 +714,17 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
 
        ret = snd_soc_pcm_component_pm_runtime_get(rtd, substream);
        if (ret < 0)
-               goto pm_err;
+               goto err;
 
        mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
 
        ret = soc_pcm_components_open(substream);
        if (ret < 0)
-               goto component_err;
+               goto err;
 
        ret = snd_soc_link_startup(substream);
        if (ret < 0)
-               goto rtd_startup_err;
+               goto err;
 
        /* startup the audio subsystem */
        for_each_rtd_dais(rtd, i, dai) {
@@ -726,7 +733,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                        dev_err(dai->dev,
                                "ASoC: can't open DAI %s: %d\n",
                                dai->name, ret);
-                       goto config_err;
+                       goto err;
                }
 
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -755,18 +762,18 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        if (!runtime->hw.rates) {
                printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
                        codec_dai_name, cpu_dai_name);
-               goto config_err;
+               goto err;
        }
        if (!runtime->hw.formats) {
                printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n",
                        codec_dai_name, cpu_dai_name);
-               goto config_err;
+               goto err;
        }
        if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
            runtime->hw.channels_min > runtime->hw.channels_max) {
                printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n",
                                codec_dai_name, cpu_dai_name);
-               goto config_err;
+               goto err;
        }
 
        soc_pcm_apply_msb(substream);
@@ -776,7 +783,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                if (snd_soc_dai_active(dai)) {
                        ret = soc_pcm_apply_symmetry(substream, dai);
                        if (ret != 0)
-                               goto config_err;
+                               goto err;
                }
        }
 
@@ -787,29 +794,13 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                 runtime->hw.channels_max);
        pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min,
                 runtime->hw.rate_max);
-
 dynamic:
-
        snd_soc_runtime_activate(rtd, substream->stream);
-
-       mutex_unlock(&rtd->card->pcm_mutex);
-       return 0;
-
-config_err:
-       for_each_rtd_dais_rollback(rtd, i, dai)
-               snd_soc_dai_shutdown(dai, substream, 1);
-
-       snd_soc_link_shutdown(substream, 1);
-rtd_startup_err:
-       soc_pcm_components_close(substream, 1);
-component_err:
+err:
        mutex_unlock(&rtd->card->pcm_mutex);
-pm_err:
-       snd_soc_pcm_component_pm_runtime_put(rtd, substream, 1);
 
-       for_each_rtd_components(rtd, i, component)
-               if (!snd_soc_component_active(component))
-                       pinctrl_pm_select_sleep_state(component->dev);
+       if (ret < 0)
+               soc_pcm_clean(substream, 1);
 
        return ret;
 }