summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2020-10-26 21:37:15 +0300
committerMark Brown <broonie@kernel.org>2020-10-26 21:37:15 +0300
commit0d8902d57646df202ad7bf602c734220d65fe75d (patch)
treea7331b1ee07ac47c9b7321b80c5f5c740a02d08a /sound/soc
parent155eacf880b86b7797e20b7841611323a0918b87 (diff)
parent4662c59688b8db8834aab14f0d37a4f26fc0dd20 (diff)
downloadlinux-0d8902d57646df202ad7bf602c734220d65fe75d.tar.xz
Merge series "ASoC: merge soc_pcm_hw_param() rollback and soc_pcm_hw_free()" from Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>:
Hi Mark soc_pcm_hw_params() does rollback when failed (A), but, it is almost same as soc_pcm_hw_free(). static int soc_pcm_hw_params(xxx) { ... if (ret < 0) goto xxx_err; ... return ret; ^ component_err: | ... | interface_err: (A) ... | codec_err: | ... v return ret; } This kind of duplicated code can be a hotbed of bugs, thus, this patch-set share soc_pcm_hw_free() and rollback. Kuninori Morimoto (6): ASoC: soc.h: remove for_each_rtd_dais_rollback() ASoC: soc-pcm: move soc_pcm_hw_free() next to soc_pcm_hw_params() ASoC: soc-link: add mark for snd_soc_link_hw_params/free() ASoC: soc-component: add mark for snd_soc_pcm_component_hw_params/free() ASoC: soc-dai: add mark for snd_soc_dai_hw_params/free() ASoC: soc-pcm: add soc_pcm_hw_clean() and call it from soc_pcm_hw_params/free() include/sound/soc-component.h | 6 +- include/sound/soc-dai.h | 4 +- include/sound/soc-link.h | 3 +- include/sound/soc.h | 7 +- sound/soc/soc-component.c | 19 ++--- sound/soc/soc-dai.c | 13 +++- sound/soc/soc-dapm.c | 4 +- sound/soc/soc-link.c | 12 +++- sound/soc/soc-pcm.c | 131 ++++++++++++++-------------------- 9 files changed, 97 insertions(+), 102 deletions(-) -- 2.25.1
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/soc-component.c19
-rw-r--r--sound/soc/soc-dai.c13
-rw-r--r--sound/soc/soc-dapm.c4
-rw-r--r--sound/soc/soc-link.c12
-rw-r--r--sound/soc/soc-pcm.c131
5 files changed, 88 insertions, 91 deletions
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c
index 728e93f35ffb..6d719c2db92e 100644
--- a/sound/soc/soc-component.c
+++ b/sound/soc/soc-component.c
@@ -779,8 +779,7 @@ int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream)
}
int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_component **last)
+ struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_component *component;
@@ -790,33 +789,35 @@ int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream,
if (component->driver->hw_params) {
ret = component->driver->hw_params(component,
substream, params);
- if (ret < 0) {
- *last = component;
+ if (ret < 0)
return soc_component_ret(component, ret);
- }
}
+ /* mark substream if succeeded */
+ soc_component_mark_push(component, substream, hw_params);
}
- *last = NULL;
return 0;
}
void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream,
- struct snd_soc_component *last)
+ int rollback)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_component *component;
int i, ret;
for_each_rtd_components(rtd, i, component) {
- if (component == last)
- break;
+ if (rollback && !soc_component_mark_match(component, substream, hw_params))
+ continue;
if (component->driver->hw_free) {
ret = component->driver->hw_free(component, substream);
if (ret < 0)
soc_component_ret(component, ret);
}
+
+ /* remove marked substream */
+ soc_component_mark_pop(component, substream, hw_params);
}
}
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 4705c3da6280..2686a566649b 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -335,16 +335,27 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
if (dai->driver->ops &&
dai->driver->ops->hw_params)
ret = dai->driver->ops->hw_params(substream, params, dai);
+
+ /* mark substream if succeeded */
+ if (ret == 0)
+ soc_dai_mark_push(dai, substream, hw_params);
end:
return soc_dai_ret(dai, ret);
}
void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
- struct snd_pcm_substream *substream)
+ struct snd_pcm_substream *substream,
+ int rollback)
{
+ if (rollback && !soc_dai_mark_match(dai, substream, hw_params))
+ return;
+
if (dai->driver->ops &&
dai->driver->ops->hw_free)
dai->driver->ops->hw_free(substream, dai);
+
+ /* remove marked substream */
+ soc_dai_mark_pop(dai, substream, hw_params);
}
int snd_soc_dai_startup(struct snd_soc_dai *dai,
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 6e764c793e49..a6ef160a6af5 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -3955,13 +3955,13 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
substream->stream = SNDRV_PCM_STREAM_CAPTURE;
snd_soc_dapm_widget_for_each_source_path(w, path) {
source = path->source->priv;
- snd_soc_dai_hw_free(source, substream);
+ snd_soc_dai_hw_free(source, substream, 0);
}
substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
snd_soc_dapm_widget_for_each_sink_path(w, path) {
sink = path->sink->priv;
- snd_soc_dai_hw_free(sink, substream);
+ snd_soc_dai_hw_free(sink, substream, 0);
}
substream->stream = SNDRV_PCM_STREAM_CAPTURE;
diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c
index 2a8881978930..409ae4940da3 100644
--- a/sound/soc/soc-link.c
+++ b/sound/soc/soc-link.c
@@ -119,16 +119,26 @@ int snd_soc_link_hw_params(struct snd_pcm_substream *substream,
rtd->dai_link->ops->hw_params)
ret = rtd->dai_link->ops->hw_params(substream, params);
+ /* mark substream if succeeded */
+ if (ret == 0)
+ soc_link_mark_push(rtd, substream, hw_params);
+
return soc_link_ret(rtd, ret);
}
-void snd_soc_link_hw_free(struct snd_pcm_substream *substream)
+void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ if (rollback && !soc_link_mark_match(rtd, substream, hw_params))
+ return;
+
if (rtd->dai_link->ops &&
rtd->dai_link->ops->hw_free)
rtd->dai_link->ops->hw_free(substream);
+
+ /* remove marked substream */
+ soc_link_mark_pop(rtd, substream, hw_params);
}
int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd)
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index dcab9527ba3d..17ff3a369631 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -860,6 +860,54 @@ static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
interval->max = channels;
}
+static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *dai;
+ int i;
+
+ mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
+
+ /* clear the corresponding DAIs parameters when going to be inactive */
+ for_each_rtd_dais(rtd, i, dai) {
+ int active = snd_soc_dai_stream_active(dai, substream->stream);
+
+ if (snd_soc_dai_active(dai) == 1) {
+ dai->rate = 0;
+ dai->channels = 0;
+ dai->sample_bits = 0;
+ }
+
+ if (active == 1)
+ snd_soc_dai_digital_mute(dai, 1, substream->stream);
+ }
+
+ /* free any machine hw params */
+ snd_soc_link_hw_free(substream, rollback);
+
+ /* free any component resources */
+ snd_soc_pcm_component_hw_free(substream, rollback);
+
+ /* now free hw params for the DAIs */
+ for_each_rtd_dais(rtd, i, dai) {
+ if (!snd_soc_dai_stream_valid(dai, substream->stream))
+ continue;
+
+ snd_soc_dai_hw_free(dai, substream, rollback);
+ }
+
+ mutex_unlock(&rtd->card->pcm_mutex);
+ return 0;
+}
+
+/*
+ * Frees resources allocated by hw_params, can be called multiple times
+ */
+static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return soc_pcm_hw_clean(substream, 0);
+}
+
/*
* Called by ALSA when the hardware params are set by application. This
* function can also be called multiple times and can allocate buffers
@@ -869,7 +917,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_component *component;
struct snd_soc_dai *cpu_dai;
struct snd_soc_dai *codec_dai;
int i, ret = 0;
@@ -921,7 +968,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
ret = snd_soc_dai_hw_params(codec_dai, substream,
&codec_params);
if(ret < 0)
- goto codec_err;
+ goto out;
codec_dai->rate = params_rate(&codec_params);
codec_dai->channels = params_channels(&codec_params);
@@ -941,7 +988,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
if (ret < 0)
- goto interface_err;
+ goto out;
/* store the parameters for each DAI */
cpu_dai->rate = params_rate(params);
@@ -952,88 +999,16 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
snd_soc_dapm_update_dai(substream, params, cpu_dai);
}
- ret = snd_soc_pcm_component_hw_params(substream, params, &component);
- if (ret < 0)
- goto component_err;
-
+ ret = snd_soc_pcm_component_hw_params(substream, params);
out:
mutex_unlock(&rtd->card->pcm_mutex);
- return ret;
-
-component_err:
- snd_soc_pcm_component_hw_free(substream, component);
-
- i = rtd->num_cpus;
-
-interface_err:
- for_each_rtd_cpu_dais_rollback(rtd, i, cpu_dai) {
- if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
- continue;
-
- snd_soc_dai_hw_free(cpu_dai, substream);
- cpu_dai->rate = 0;
- }
- i = rtd->num_codecs;
-
-codec_err:
- for_each_rtd_codec_dais_rollback(rtd, i, codec_dai) {
- if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
- continue;
-
- snd_soc_dai_hw_free(codec_dai, substream);
- codec_dai->rate = 0;
- }
-
- snd_soc_link_hw_free(substream);
+ if (ret < 0)
+ soc_pcm_hw_clean(substream, 1);
- mutex_unlock(&rtd->card->pcm_mutex);
return ret;
}
-/*
- * Frees resources allocated by hw_params, can be called multiple times
- */
-static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *dai;
- int i;
-
- mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
-
- /* clear the corresponding DAIs parameters when going to be inactive */
- for_each_rtd_dais(rtd, i, dai) {
- int active = snd_soc_dai_stream_active(dai, substream->stream);
-
- if (snd_soc_dai_active(dai) == 1) {
- dai->rate = 0;
- dai->channels = 0;
- dai->sample_bits = 0;
- }
-
- if (active == 1)
- snd_soc_dai_digital_mute(dai, 1, substream->stream);
- }
-
- /* free any machine hw params */
- snd_soc_link_hw_free(substream);
-
- /* free any component resources */
- snd_soc_pcm_component_hw_free(substream, NULL);
-
- /* now free hw params for the DAIs */
- for_each_rtd_dais(rtd, i, dai) {
- if (!snd_soc_dai_stream_valid(dai, substream->stream))
- continue;
-
- snd_soc_dai_hw_free(dai, substream);
- }
-
- mutex_unlock(&rtd->card->pcm_mutex);
- return 0;
-}
-
static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
int ret = -EINVAL;