aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-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.c72
4 files changed, 144 insertions, 47 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 ae062e4d1ce8..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;
}
@@ -2050,21 +2074,6 @@ out:
return ret;
}
-static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
- struct snd_pcm_substream *substream, int cmd)
-{
- int ret;
-
- dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d\n",
- dpcm->be->dai_link->name, cmd);
-
- ret = soc_pcm_trigger(substream, cmd);
- if (ret < 0)
- dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d\n", ret);
-
- return ret;
-}
-
int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
int cmd)
{
@@ -2081,6 +2090,9 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
if (!snd_soc_dpcm_be_can_update(fe, be, stream))
continue;
+ dev_dbg(be->dev, "ASoC: trigger BE %s cmd %d\n",
+ be->dai_link->name, cmd);
+
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
@@ -2088,7 +2100,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
continue;
- ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+ ret = soc_pcm_trigger(be_substream, cmd);
if (ret)
return ret;
@@ -2098,7 +2110,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
continue;
- ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+ ret = soc_pcm_trigger(be_substream, cmd);
if (ret)
return ret;
@@ -2108,7 +2120,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
continue;
- ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+ ret = soc_pcm_trigger(be_substream, cmd);
if (ret)
return ret;
@@ -2122,7 +2134,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
continue;
- ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+ ret = soc_pcm_trigger(be_substream, cmd);
if (ret)
return ret;
@@ -2135,7 +2147,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
continue;
- ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+ ret = soc_pcm_trigger(be_substream, cmd);
if (ret)
return ret;
@@ -2148,7 +2160,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
continue;
- ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+ ret = soc_pcm_trigger(be_substream, cmd);
if (ret)
return ret;