diff mbox series

[RFC,3/4] ASoC: pcm: Add support for running detect on capture stream

Message ID 20241016130228.1013227-4-amadeuszx.slawinski@linux.intel.com (mailing list archive)
State Superseded
Headers show
Series Add support for detection | expand

Commit Message

Amadeusz Sławiński Oct. 16, 2024, 1:02 p.m. UTC
In order to be able to run detection on capture streams, DPCM state
machine needs to be expanded to recognize "detect" state.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
---
 include/sound/soc-dpcm.h |  2 ++
 sound/core/pcm_native.c  |  2 +-
 sound/soc/soc-pcm.c      | 56 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 59 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h
index c6fb350b4b062..7062f77528edd 100644
--- a/include/sound/soc-dpcm.h
+++ b/include/sound/soc-dpcm.h
@@ -40,6 +40,7 @@  enum snd_soc_dpcm_state {
 	SND_SOC_DPCM_STATE_OPEN,
 	SND_SOC_DPCM_STATE_HW_PARAMS,
 	SND_SOC_DPCM_STATE_PREPARE,
+	SND_SOC_DPCM_STATE_DETECT,
 	SND_SOC_DPCM_STATE_START,
 	SND_SOC_DPCM_STATE_STOP,
 	SND_SOC_DPCM_STATE_PAUSED,
@@ -98,6 +99,7 @@  struct snd_soc_dpcm_runtime {
 
 	int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */
 
+	int be_detect; /* detection runinng on BE */
 	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 */
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index c024eb0ed74ff..5370797801132 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1470,7 +1470,7 @@  static const struct action_ops snd_pcm_action_detect = {
  * Return: Zero if successful, or a negative error code.
  * The stream lock must be acquired before calling this function.
  */
-int snd_pcm_detect(struct snd_pcm_substream *substream)
+static int snd_pcm_detect(struct snd_pcm_substream *substream)
 {
 	return snd_pcm_action_lock_irq(&snd_pcm_action_detect, substream,
 				       SNDRV_PCM_STATE_DETECTING);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 7a59121fc323c..2d65008ec7a2b 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -110,6 +110,7 @@  static int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
 		SND_SOC_DPCM_STATE_START,
 		SND_SOC_DPCM_STATE_PAUSED,
 		SND_SOC_DPCM_STATE_SUSPEND,
+		SND_SOC_DPCM_STATE_DETECT,
 	};
 
 	return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
@@ -127,6 +128,7 @@  static int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
 		SND_SOC_DPCM_STATE_PAUSED,
 		SND_SOC_DPCM_STATE_SUSPEND,
 		SND_SOC_DPCM_STATE_PREPARE,
+		SND_SOC_DPCM_STATE_DETECT,
 	};
 
 	return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
@@ -171,6 +173,8 @@  static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
 		return "hw_params";
 	case SND_SOC_DPCM_STATE_PREPARE:
 		return "prepare";
+	case SND_SOC_DPCM_STATE_DETECT:
+		return "detect";
 	case SND_SOC_DPCM_STATE_START:
 		return "start";
 	case SND_SOC_DPCM_STATE_STOP:
@@ -1250,6 +1254,7 @@  static int soc_pcm_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_DETECT_START:
 		for (i = 0; i < TRIGGER_MAX; i++) {
 			r = trigger[start][i](substream, cmd, 0);
 			if (r < 0)
@@ -1274,6 +1279,9 @@  static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 			cmd = SNDRV_PCM_TRIGGER_PAUSE_PUSH;
 			break;
+		case SNDRV_PCM_TRIGGER_DETECT_START:
+			cmd = SNDRV_PCM_TRIGGER_DETECT_STOP;
+			break;
 		}
 	}
 
@@ -1284,6 +1292,7 @@  static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_DETECT_STOP:
 		for (i = TRIGGER_MAX; i > 0; i--) {
 			r = trigger[stop][i - 1](substream, cmd, rollback);
 			if (r < 0)
@@ -2247,6 +2256,25 @@  int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
 			be->dai_link->name, cmd);
 
 		switch (cmd) {
+		case SNDRV_PCM_TRIGGER_DETECT_START:
+			if (!be->dpcm[stream].be_start &&
+			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
+			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+				goto next;
+
+			be->dpcm[stream].be_detect++;
+			if (be->dpcm[stream].be_detect != 1)
+				goto next;
+
+			ret = soc_pcm_trigger(be_substream,
+					      SNDRV_PCM_TRIGGER_DETECT_START);
+			if (ret) {
+				be->dpcm[stream].be_detect--;
+				goto next;
+			}
+
+			be->dpcm[stream].state = SND_SOC_DPCM_STATE_DETECT;
+			break;
 		case SNDRV_PCM_TRIGGER_START:
 			if (!be->dpcm[stream].be_start &&
 			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
@@ -2254,6 +2282,8 @@  int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
 			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
 				goto next;
 
+			if (be->dpcm[stream].be_detect > 0)
+				be->dpcm[stream].be_detect = 0;
 			be->dpcm[stream].be_start++;
 			if (be->dpcm[stream].be_start != 1)
 				goto next;
@@ -2308,6 +2338,23 @@  int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
 
 			be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
 			break;
+		case SNDRV_PCM_TRIGGER_DETECT_STOP:
+			if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_DETECT)
+				goto next;
+
+			be->dpcm[stream].be_detect--;
+
+			if (be->dpcm[stream].be_detect != 0)
+				goto next;
+
+			ret = soc_pcm_trigger(be_substream, SNDRV_PCM_TRIGGER_DETECT_STOP);
+			if (ret) {
+				be->dpcm[stream].be_detect++;
+				goto next;
+			}
+
+			be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
+			break;
 		case SNDRV_PCM_TRIGGER_STOP:
 			if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
 			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
@@ -2440,11 +2487,13 @@  static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
 		case SNDRV_PCM_TRIGGER_RESUME:
 		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		case SNDRV_PCM_TRIGGER_DRAIN:
+		case SNDRV_PCM_TRIGGER_DETECT_START:
 			ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
 			break;
 		case SNDRV_PCM_TRIGGER_STOP:
 		case SNDRV_PCM_TRIGGER_SUSPEND:
 		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		case SNDRV_PCM_TRIGGER_DETECT_STOP:
 			ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
 			break;
 		default:
@@ -2458,11 +2507,13 @@  static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
 		case SNDRV_PCM_TRIGGER_RESUME:
 		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		case SNDRV_PCM_TRIGGER_DRAIN:
+		case SNDRV_PCM_TRIGGER_DETECT_START:
 			ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
 			break;
 		case SNDRV_PCM_TRIGGER_STOP:
 		case SNDRV_PCM_TRIGGER_SUSPEND:
 		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		case SNDRV_PCM_TRIGGER_DETECT_STOP:
 			ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
 			break;
 		default:
@@ -2484,6 +2535,10 @@  static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
 	}
 
 	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_DETECT_START:
+		// return -EINVAL;? as FE is not running when detect happens?
+		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_DETECT;
+		break;
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -2491,6 +2546,7 @@  static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_DETECT_STOP:
 		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: