diff options
author | Mark Brown <broonie@kernel.org> | 2020-10-26 21:37:15 +0300 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2020-10-26 21:37:15 +0300 |
commit | 0d8902d57646df202ad7bf602c734220d65fe75d (patch) | |
tree | a7331b1ee07ac47c9b7321b80c5f5c740a02d08a /sound/soc | |
parent | 155eacf880b86b7797e20b7841611323a0918b87 (diff) | |
parent | 4662c59688b8db8834aab14f0d37a4f26fc0dd20 (diff) | |
download | linux-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.c | 19 | ||||
-rw-r--r-- | sound/soc/soc-dai.c | 13 | ||||
-rw-r--r-- | sound/soc/soc-dapm.c | 4 | ||||
-rw-r--r-- | sound/soc/soc-link.c | 12 | ||||
-rw-r--r-- | sound/soc/soc-pcm.c | 131 |
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; |