Unverified Commit 2ad1e059 authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: soc-pcm: improve BE state transitions

Merge series from Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>:

With additional tests with the introduction of a 'deep-buffer' PCM
device mixed with the regular low-latency path, we came up with two
improvements in the BE state machine and transitions. The short
explanation is that the BE cannot directly use the trigger commands
provided by the FE, and a translation is needed to deal with paused
states.
parents 7ed1bf73 374b50e2
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -103,6 +103,8 @@ struct snd_soc_dpcm_runtime {
	int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */

	int be_start; /* refcount protected by BE stream pcm lock */
	int be_pause; /* refcount protected by BE stream pcm lock */
	bool fe_pause; /* used to track STOP after PAUSE */
};

#define for_each_dpcm_fe(be, stream, _dpcm)				\
+35 −3
Original line number Diff line number Diff line
@@ -2090,6 +2090,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
			       int cmd)
{
	struct snd_soc_pcm_runtime *be;
	bool pause_stop_transition;
	struct snd_soc_dpcm *dpcm;
	unsigned long flags;
	int ret = 0;
@@ -2121,6 +2122,13 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
			if (be->dpcm[stream].be_start != 1)
				goto next;

			if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_PAUSED)
				ret = soc_pcm_trigger(be_substream,
						      SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
			else
				ret = soc_pcm_trigger(be_substream,
						      SNDRV_PCM_TRIGGER_START);

			ret = soc_pcm_trigger(be_substream, cmd);
			if (ret) {
				be->dpcm[stream].be_start--;
@@ -2148,10 +2156,12 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
			if (!be->dpcm[stream].be_start &&
			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
				goto next;

			fe->dpcm[stream].fe_pause = false;
			be->dpcm[stream].be_pause--;

			be->dpcm[stream].be_start++;
			if (be->dpcm[stream].be_start != 1)
				goto next;
@@ -2175,14 +2185,33 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
			if (be->dpcm[stream].be_start != 0)
				goto next;

			ret = soc_pcm_trigger(be_substream, cmd);
			pause_stop_transition = false;
			if (fe->dpcm[stream].fe_pause) {
				pause_stop_transition = true;
				fe->dpcm[stream].fe_pause = false;
				be->dpcm[stream].be_pause--;
			}

			if (be->dpcm[stream].be_pause != 0)
				ret = soc_pcm_trigger(be_substream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
			else
				ret = soc_pcm_trigger(be_substream, SNDRV_PCM_TRIGGER_STOP);

			if (ret) {
				if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_START)
					be->dpcm[stream].be_start++;
				if (pause_stop_transition) {
					fe->dpcm[stream].fe_pause = true;
					be->dpcm[stream].be_pause++;
				}
				goto next;
			}

			if (be->dpcm[stream].be_pause != 0)
				be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
			else
				be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;

			break;
		case SNDRV_PCM_TRIGGER_SUSPEND:
			if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
@@ -2204,6 +2233,9 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
			if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
				goto next;

			fe->dpcm[stream].fe_pause = true;
			be->dpcm[stream].be_pause++;

			be->dpcm[stream].be_start--;
			if (be->dpcm[stream].be_start != 0)
				goto next;