aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/sound/soc/soc-link.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-link.c')
-rw-r--r--sound/soc/soc-link.c86
1 files changed, 76 insertions, 10 deletions
diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c
index cec70b19863e..fee4022708bc 100644
--- a/sound/soc/soc-link.c
+++ b/sound/soc/soc-link.c
@@ -30,6 +30,14 @@ static inline int _soc_link_ret(struct snd_soc_pcm_runtime *rtd,
return ret;
}
+/*
+ * We might want to check substream by using list.
+ * In such case, we can update these macros.
+ */
+#define soc_link_mark_push(rtd, substream, tgt) ((rtd)->mark_##tgt = substream)
+#define soc_link_mark_pop(rtd, substream, tgt) ((rtd)->mark_##tgt = NULL)
+#define soc_link_mark_match(rtd, substream, tgt) ((rtd)->mark_##tgt == substream)
+
int snd_soc_link_init(struct snd_soc_pcm_runtime *rtd)
{
int ret = 0;
@@ -59,28 +67,39 @@ int snd_soc_link_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
int snd_soc_link_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret = 0;
if (rtd->dai_link->ops &&
rtd->dai_link->ops->startup)
ret = rtd->dai_link->ops->startup(substream);
+ /* mark substream if succeeded */
+ if (ret == 0)
+ soc_link_mark_push(rtd, substream, startup);
+
return soc_link_ret(rtd, ret);
}
-void snd_soc_link_shutdown(struct snd_pcm_substream *substream)
+void snd_soc_link_shutdown(struct snd_pcm_substream *substream,
+ int rollback)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+
+ if (rollback && !soc_link_mark_match(rtd, substream, startup))
+ return;
if (rtd->dai_link->ops &&
rtd->dai_link->ops->shutdown)
rtd->dai_link->ops->shutdown(substream);
+
+ /* remove marked substream */
+ soc_link_mark_pop(rtd, substream, startup);
}
int snd_soc_link_prepare(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret = 0;
if (rtd->dai_link->ops &&
@@ -93,28 +112,38 @@ int snd_soc_link_prepare(struct snd_pcm_substream *substream)
int snd_soc_link_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_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret = 0;
if (rtd->dai_link->ops &&
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);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_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)
+static int soc_link_trigger(struct snd_pcm_substream *substream, int cmd)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
int ret = 0;
if (rtd->dai_link->ops &&
@@ -124,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 = snd_soc_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;
@@ -133,17 +190,26 @@ int snd_soc_link_compr_startup(struct snd_compr_stream *cstream)
rtd->dai_link->compr_ops->startup)
ret = rtd->dai_link->compr_ops->startup(cstream);
+ if (ret == 0)
+ soc_link_mark_push(rtd, cstream, compr_startup);
+
return soc_link_ret(rtd, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_link_compr_startup);
-void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream)
+void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream,
+ int rollback)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ if (rollback && !soc_link_mark_match(rtd, cstream, compr_startup))
+ return;
+
if (rtd->dai_link->compr_ops &&
rtd->dai_link->compr_ops->shutdown)
rtd->dai_link->compr_ops->shutdown(cstream);
+
+ soc_link_mark_pop(rtd, cstream, compr_startup);
}
EXPORT_SYMBOL_GPL(snd_soc_link_compr_shutdown);