int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
int stream, struct snd_soc_dapm_widget_list **list, int new);
int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream);
-int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream);
+void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream,
+ int do_hw_free, struct snd_soc_dpcm *last);
void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream);
void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream);
int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream);
int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
int event);
+#define dpcm_be_dai_startup_rollback(fe, stream, last) \
+ dpcm_be_dai_stop(fe, stream, 0, last)
+#define dpcm_be_dai_startup_unwind(fe, stream) dpcm_be_dai_stop(fe, stream, 0, NULL)
+#define dpcm_be_dai_shutdown(fe, stream) dpcm_be_dai_stop(fe, stream, 1, NULL)
+
#endif
spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
}
-static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
- int stream)
+void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream,
+ int do_hw_free, struct snd_soc_dpcm *last)
{
struct snd_soc_dpcm *dpcm;
/* disable any enabled and non active backends */
for_each_dpcm_be(fe, stream, dpcm) {
-
struct snd_soc_pcm_runtime *be = dpcm->be;
struct snd_pcm_substream *be_substream =
snd_soc_dpcm_get_substream(be, stream);
+ if (dpcm == last)
+ return;
+
+ /* is this op for this BE ? */
+ if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ continue;
+
if (be->dpcm[stream].users == 0) {
dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
stream ? "capture" : "playback",
if (--be->dpcm[stream].users != 0)
continue;
- if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
- continue;
+ if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) {
+ if (!do_hw_free)
+ continue;
+
+ if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) {
+ soc_pcm_hw_free(be_substream);
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
+ }
+ }
soc_pcm_close(be_substream);
be_substream->runtime = NULL;
return count;
unwind:
- /* disable any enabled and non active backends */
- for_each_dpcm_be_rollback(fe, stream, dpcm) {
- struct snd_soc_pcm_runtime *be = dpcm->be;
- struct snd_pcm_substream *be_substream =
- snd_soc_dpcm_get_substream(be, stream);
-
- if (!snd_soc_dpcm_be_can_update(fe, be, stream))
- continue;
-
- if (be->dpcm[stream].users == 0) {
- dev_err(be->dev, "ASoC: no users %s at close %d\n",
- stream ? "capture" : "playback",
- be->dpcm[stream].state);
- continue;
- }
-
- if (--be->dpcm[stream].users != 0)
- continue;
-
- if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
- continue;
-
- soc_pcm_close(be_substream);
- be_substream->runtime = NULL;
- be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
- }
+ dpcm_be_dai_startup_rollback(fe, stream, dpcm);
return err;
}
return ret;
}
-int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
-{
- struct snd_soc_dpcm *dpcm;
-
- /* only shutdown BEs that are either sinks or sources to this FE DAI */
- for_each_dpcm_be(fe, stream, dpcm) {
-
- struct snd_soc_pcm_runtime *be = dpcm->be;
- struct snd_pcm_substream *be_substream =
- snd_soc_dpcm_get_substream(be, stream);
-
- /* is this op for this BE ? */
- if (!snd_soc_dpcm_be_can_update(fe, be, stream))
- continue;
-
- if (be->dpcm[stream].users == 0)
- dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
- stream ? "capture" : "playback",
- be->dpcm[stream].state);
-
- if (--be->dpcm[stream].users != 0)
- continue;
-
- if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
- (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
- soc_pcm_hw_free(be_substream);
- be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
- }
-
- dev_dbg(be->dev, "ASoC: close BE %s\n",
- be->dai_link->name);
-
- soc_pcm_close(be_substream);
- be_substream->runtime = NULL;
-
- be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
- }
- return 0;
-}
-
static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
if (err < 0)
dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
- err = dpcm_be_dai_shutdown(fe, stream);
- if (err < 0)
- dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
+ dpcm_be_dai_shutdown(fe, stream);
/* run the stream event for each BE */
dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);