Merge tag 'microblaze-v5.11' of git://git.monstr.eu/linux-2.6-microblaze
[linux-2.6-microblaze.git] / sound / soc / soc-pcm.c
index dcab952..ee51dc7 100644 (file)
@@ -662,8 +662,6 @@ static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback)
 
        soc_pcm_components_close(substream, rollback);
 
-       if (!rollback)
-               snd_soc_dapm_stream_stop(rtd, substream->stream);
 
        mutex_unlock(&rtd->card->pcm_mutex);
 
@@ -860,6 +858,57 @@ static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
        interval->max = channels;
 }
 
+static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback)
+{
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *dai;
+       int i;
+
+       mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
+
+       /* clear the corresponding DAIs parameters when going to be inactive */
+       for_each_rtd_dais(rtd, i, dai) {
+               int active = snd_soc_dai_stream_active(dai, substream->stream);
+
+               if (snd_soc_dai_active(dai) == 1) {
+                       dai->rate = 0;
+                       dai->channels = 0;
+                       dai->sample_bits = 0;
+               }
+
+               if (active == 1)
+                       snd_soc_dai_digital_mute(dai, 1, substream->stream);
+       }
+
+       /* run the stream event */
+       snd_soc_dapm_stream_stop(rtd, substream->stream);
+
+       /* free any machine hw params */
+       snd_soc_link_hw_free(substream, rollback);
+
+       /* free any component resources */
+       snd_soc_pcm_component_hw_free(substream, rollback);
+
+       /* now free hw params for the DAIs  */
+       for_each_rtd_dais(rtd, i, dai) {
+               if (!snd_soc_dai_stream_valid(dai, substream->stream))
+                       continue;
+
+               snd_soc_dai_hw_free(dai, substream, rollback);
+       }
+
+       mutex_unlock(&rtd->card->pcm_mutex);
+       return 0;
+}
+
+/*
+ * Frees resources allocated by hw_params, can be called multiple times
+ */
+static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       return soc_pcm_hw_clean(substream, 0);
+}
+
 /*
  * Called by ALSA when the hardware params are set by application. This
  * function can also be called multiple times and can allocate buffers
@@ -869,7 +918,6 @@ static int soc_pcm_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_component *component;
        struct snd_soc_dai *cpu_dai;
        struct snd_soc_dai *codec_dai;
        int i, ret = 0;
@@ -921,7 +969,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                ret = snd_soc_dai_hw_params(codec_dai, substream,
                                            &codec_params);
                if(ret < 0)
-                       goto codec_err;
+                       goto out;
 
                codec_dai->rate = params_rate(&codec_params);
                codec_dai->channels = params_channels(&codec_params);
@@ -941,7 +989,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 
                ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
                if (ret < 0)
-                       goto interface_err;
+                       goto out;
 
                /* store the parameters for each DAI */
                cpu_dai->rate = params_rate(params);
@@ -952,121 +1000,73 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                snd_soc_dapm_update_dai(substream, params, cpu_dai);
        }
 
-       ret = snd_soc_pcm_component_hw_params(substream, params, &component);
-       if (ret < 0)
-               goto component_err;
-
+       ret = snd_soc_pcm_component_hw_params(substream, params);
 out:
        mutex_unlock(&rtd->card->pcm_mutex);
-       return ret;
 
-component_err:
-       snd_soc_pcm_component_hw_free(substream, component);
-
-       i = rtd->num_cpus;
-
-interface_err:
-       for_each_rtd_cpu_dais_rollback(rtd, i, cpu_dai) {
-               if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
-                       continue;
-
-               snd_soc_dai_hw_free(cpu_dai, substream);
-               cpu_dai->rate = 0;
-       }
-
-       i = rtd->num_codecs;
-
-codec_err:
-       for_each_rtd_codec_dais_rollback(rtd, i, codec_dai) {
-               if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
-                       continue;
-
-               snd_soc_dai_hw_free(codec_dai, substream);
-               codec_dai->rate = 0;
-       }
-
-       snd_soc_link_hw_free(substream);
+       if (ret < 0)
+               soc_pcm_hw_clean(substream, 1);
 
-       mutex_unlock(&rtd->card->pcm_mutex);
        return ret;
 }
 
-/*
- * Frees resources allocated by hw_params, can be called multiple times
- */
-static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-       struct snd_soc_dai *dai;
-       int i;
-
-       mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
-
-       /* clear the corresponding DAIs parameters when going to be inactive */
-       for_each_rtd_dais(rtd, i, dai) {
-               int active = snd_soc_dai_stream_active(dai, substream->stream);
-
-               if (snd_soc_dai_active(dai) == 1) {
-                       dai->rate = 0;
-                       dai->channels = 0;
-                       dai->sample_bits = 0;
-               }
-
-               if (active == 1)
-                       snd_soc_dai_digital_mute(dai, 1, substream->stream);
-       }
-
-       /* free any machine hw params */
-       snd_soc_link_hw_free(substream);
-
-       /* free any component resources */
-       snd_soc_pcm_component_hw_free(substream, NULL);
-
-       /* now free hw params for the DAIs  */
-       for_each_rtd_dais(rtd, i, dai) {
-               if (!snd_soc_dai_stream_valid(dai, substream->stream))
-                       continue;
-
-               snd_soc_dai_hw_free(dai, substream);
-       }
-
-       mutex_unlock(&rtd->card->pcm_mutex);
-       return 0;
-}
-
 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);
+               ret = snd_soc_pcm_component_trigger(substream, cmd, 0);
                if (ret < 0)
+                       goto start_err;
+
+               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;
 }
 
@@ -1284,7 +1284,8 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
 
        /* get number of valid DAI paths and their widgets */
        paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
-                       dpcm_end_walk_at_be);
+                       fe->card->component_chaining ?
+                               NULL : dpcm_end_walk_at_be);
 
        dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths,
                        stream ? "capture" : "playback");
@@ -1883,7 +1884,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
        /* now shutdown the frontend */
        soc_pcm_close(substream);
 
-       /* run the stream event for each BE */
+       /* run the stream stop event */
        dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
 
        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
@@ -2073,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)
 {
@@ -2104,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) &&
@@ -2111,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;
 
@@ -2121,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;
 
@@ -2131,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;
 
@@ -2145,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;
 
@@ -2158,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;
 
@@ -2171,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;
 
@@ -2231,6 +2220,7 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
                case SNDRV_PCM_TRIGGER_START:
                case SNDRV_PCM_TRIGGER_RESUME:
                case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               case SNDRV_PCM_TRIGGER_DRAIN:
                        ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
                        break;
                case SNDRV_PCM_TRIGGER_STOP:
@@ -2248,6 +2238,7 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
                case SNDRV_PCM_TRIGGER_START:
                case SNDRV_PCM_TRIGGER_RESUME:
                case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               case SNDRV_PCM_TRIGGER_DRAIN:
                        ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
                        break;
                case SNDRV_PCM_TRIGGER_STOP:
@@ -2385,8 +2376,6 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
                goto out;
        }
 
-       /* run the stream event for each BE */
-       dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
 
 out: