Merge tag 'printk-for-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/printk...
[linux-2.6-microblaze.git] / sound / soc / soc-dai.c
index 4705c3d..cd3bb9a 100644 (file)
@@ -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,
@@ -553,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,
@@ -601,16 +640,27 @@ int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
            dai->driver->cops->startup)
                ret = dai->driver->cops->startup(cstream, dai);
 
+       /* mark cstream if succeeded */
+       if (ret == 0)
+               soc_dai_mark_push(dai, cstream, compr_startup);
+
        return soc_dai_ret(dai, ret);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);
 
 void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
-                               struct snd_compr_stream *cstream)
+                               struct snd_compr_stream *cstream,
+                               int rollback)
 {
+       if (rollback && !soc_dai_mark_match(dai, cstream, compr_startup))
+               return;
+
        if (dai->driver->cops &&
            dai->driver->cops->shutdown)
                dai->driver->cops->shutdown(cstream, dai);
+
+       /* remove marked cstream */
+       soc_dai_mark_pop(dai, cstream, compr_startup);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);