diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2020-12-01 08:51:33 +0900 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2020-12-09 12:13:38 +0000 |
commit | 6374f493d93b2232444b94989c380d5aada5b810 (patch) | |
tree | f0ce8423cb1f5a532caae32724408427a84c2a63 /sound/soc | |
parent | a9faca15a644ff754a9d6e3c9e81f91cb8ca59bd (diff) |
ASoC: soc-pcm: care trigger rollback
soc_pcm_trigger() calls DAI/Component/Link trigger,
but some of them might be failed.
static int soc_pcm_trigger(...)
{
...
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
ret = snd_soc_link_trigger(substream, cmd);
if (ret < 0)
break;
(*) ret = snd_soc_pcm_component_trigger(substream, cmd);
if (ret < 0)
break;
ret = snd_soc_pcm_dai_trigger(substream, cmd);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ret = snd_soc_pcm_dai_trigger(substream, cmd);
if (ret < 0)
break;
ret = snd_soc_pcm_component_trigger(substream, cmd);
if (ret < 0)
break;
ret = snd_soc_link_trigger(substream, cmd);
break;
}
...
}
For example, if soc_pcm_trigger() failed at (*) point,
we need to rollback previous succeeded trigger.
This patch adds trigger mark for DAI/Component/Link,
and do STOP if START/RESUME/PAUSE_RELEASE were failed.
Because it need to use new rollback parameter,
we need to modify DAI/Component/Link trigger functions in the same time.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87a6uycssd.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/soc-component.c | 45 | ||||
-rw-r--r-- | sound/soc/soc-dai.c | 44 | ||||
-rw-r--r-- | sound/soc/soc-link.c | 30 | ||||
-rw-r--r-- | sound/soc/soc-pcm.c | 42 |
4 files changed, 135 insertions, 26 deletions
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 434987a64353..760523382f3c 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -1075,22 +1075,51 @@ void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream, } } +static int soc_component_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + int cmd) +{ + int ret = 0; + + if (component->driver->trigger) + ret = component->driver->trigger(component, substream, cmd); + + return soc_component_ret(component, ret); +} + int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream, - int cmd) + int cmd, 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->driver->trigger) { - ret = component->driver->trigger(component, substream, cmd); + int i, r, ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + for_each_rtd_components(rtd, i, component) { + ret = soc_component_trigger(component, substream, cmd); if (ret < 0) - return soc_component_ret(component, ret); + break; + soc_component_mark_push(component, substream, trigger); + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + for_each_rtd_components(rtd, i, component) { + if (rollback && !soc_component_mark_match(component, substream, trigger)) + continue; + + r = soc_component_trigger(component, substream, cmd); + if (r < 0) + ret = r; /* use last ret */ + soc_component_mark_pop(component, substream, trigger); } } - return 0; + return ret; } int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 9afc6e8c3f9f..cd3bb9a7983f 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -564,23 +564,51 @@ int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream) return 0; } +static int soc_dai_trigger(struct snd_soc_dai *dai, + struct snd_pcm_substream *substream, int cmd) +{ + int ret = 0; + + if (dai->driver->ops && + dai->driver->ops->trigger) + ret = dai->driver->ops->trigger(substream, cmd, dai); + + return soc_dai_ret(dai, ret); +} + int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, - int cmd) + int cmd, int rollback) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *dai; - int i, ret; + int i, r, ret = 0; - for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->ops && - dai->driver->ops->trigger) { - ret = dai->driver->ops->trigger(substream, cmd, dai); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + for_each_rtd_dais(rtd, i, dai) { + ret = soc_dai_trigger(dai, substream, cmd); if (ret < 0) - return soc_dai_ret(dai, ret); + break; + soc_dai_mark_push(dai, substream, trigger); + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + for_each_rtd_dais(rtd, i, dai) { + if (rollback && !soc_dai_mark_match(dai, substream, trigger)) + continue; + + r = soc_dai_trigger(dai, substream, cmd); + if (r < 0) + ret = r; /* use last ret */ + soc_dai_mark_pop(dai, substream, trigger); } } - return 0; + return ret; } int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream, diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c index 26cc60f8dcfb..619664cc9ab9 100644 --- a/sound/soc/soc-link.c +++ b/sound/soc/soc-link.c @@ -141,7 +141,7 @@ void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback) soc_link_mark_pop(rtd, substream, hw_params); } -int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd) +static int soc_link_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); int ret = 0; @@ -153,6 +153,34 @@ int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd) return soc_link_ret(rtd, ret); } +int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd, + int rollback) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = soc_link_trigger(substream, cmd); + if (ret < 0) + break; + soc_link_mark_push(rtd, substream, trigger); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (rollback && !soc_link_mark_match(rtd, substream, trigger)) + break; + + ret = soc_link_trigger(substream, cmd); + soc_link_mark_pop(rtd, substream, startup); + } + + return ret; +} + int snd_soc_link_compr_startup(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 707c1a49f6b2..ee51dc7fd893 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1012,37 +1012,61 @@ out: static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { - int ret = -EINVAL; + int ret = -EINVAL, _ret = 0; + int rollback = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = snd_soc_link_trigger(substream, cmd); + ret = snd_soc_link_trigger(substream, cmd, 0); if (ret < 0) - break; + goto start_err; + + ret = snd_soc_pcm_component_trigger(substream, cmd, 0); + if (ret < 0) + goto start_err; - ret = snd_soc_pcm_component_trigger(substream, cmd); + ret = snd_soc_pcm_dai_trigger(substream, cmd, 0); +start_err: if (ret < 0) + rollback = 1; + } + + if (rollback) { + _ret = ret; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + cmd = SNDRV_PCM_TRIGGER_STOP; + break; + case SNDRV_PCM_TRIGGER_RESUME: + cmd = SNDRV_PCM_TRIGGER_SUSPEND; + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + cmd = SNDRV_PCM_TRIGGER_PAUSE_PUSH; break; + } + } - ret = snd_soc_pcm_dai_trigger(substream, cmd); - break; + switch (cmd) { case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = snd_soc_pcm_dai_trigger(substream, cmd); + ret = snd_soc_pcm_dai_trigger(substream, cmd, rollback); if (ret < 0) break; - ret = snd_soc_pcm_component_trigger(substream, cmd); + ret = snd_soc_pcm_component_trigger(substream, cmd, rollback); if (ret < 0) break; - ret = snd_soc_link_trigger(substream, cmd); + ret = snd_soc_link_trigger(substream, cmd, rollback); break; } + if (_ret) + ret = _ret; + return ret; } |