@@ -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 */
@@ -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);
@@ -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:
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(-)