diff options
Diffstat (limited to 'sound/soc/soc-pcm.c')
-rw-r--r-- | sound/soc/soc-pcm.c | 217 |
1 files changed, 103 insertions, 114 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index dcab9527ba3d..ee51dc7fd893 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -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: |