summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2020-12-01 08:51:33 +0900
committerMark Brown <broonie@kernel.org>2020-12-09 12:13:38 +0000
commit6374f493d93b2232444b94989c380d5aada5b810 (patch)
treef0ce8423cb1f5a532caae32724408427a84c2a63 /sound/soc
parenta9faca15a644ff754a9d6e3c9e81f91cb8ca59bd (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.c45
-rw-r--r--sound/soc/soc-dai.c44
-rw-r--r--sound/soc/soc-link.c30
-rw-r--r--sound/soc/soc-pcm.c42
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;
}