summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManjula Gupta <magupta@nvidia.com>2010-06-21 18:00:59 +0530
committerGary King <gking@nvidia.com>2010-06-22 10:33:02 -0700
commit04d466815e7dbc2a3c34b9279fba182b92c1a8b3 (patch)
tree14c3e30d24912fe8ea974fa5dba8f0053ccc69cc
parentcfc9f617720bda069b54d2233ee91d1cd55d9865 (diff)
[tegra ALSA]: Avoid race condition in state change.
As Play/Record and trigger thread both are modifying the prtd->state the current state of the thread, if START->STOP->START is called fast enough play/record might set the state to NVALSA_INVALID_STATE and doesn't execute STOP/START triggered by application at all. Play/Record thread should not modify the prtd->state, use the local variable 'state' to keep track of the current state of the play/record thread and to avoid execution of START/STOP multiple times. Here we are respecting only the last triggered state after processing of the current state, for example if application calls START->STOP->START->STOP fast enough play/record thread might execute only the first START and last STOP. For Bug: 697124 Change-Id: I5879b1428f45c9172d1db7ad10338a170590bed5 Reviewed-on: http://git-master/r/2940 Tested-by: Manjula Gupta <magupta@nvidia.com> Reviewed-by: Vijay Mali <vmali@nvidia.com> Reviewed-by: Gary King <gking@nvidia.com>
-rw-r--r--sound/soc/tegra/tegra_pcm_rpc.c72
1 files changed, 37 insertions, 35 deletions
diff --git a/sound/soc/tegra/tegra_pcm_rpc.c b/sound/soc/tegra/tegra_pcm_rpc.c
index cc255de26ca8..c64d5a2f8d62 100644
--- a/sound/soc/tegra/tegra_pcm_rpc.c
+++ b/sound/soc/tegra/tegra_pcm_rpc.c
@@ -81,13 +81,14 @@ static int play_thread( void *arg)
for (;;) {
switch (prtd->state) {
case SNDRV_PCM_TRIGGER_START:
- state = NvAudioFxState_Run;
- tegra_snd_cx->xrt_fxn.SetProperty(
+ if (state != NvAudioFxState_Run) {
+ state = NvAudioFxState_Run;
+ tegra_snd_cx->xrt_fxn.SetProperty(
prtd->stdoutpath->Stream,
NvAudioFxProperty_State,
sizeof(NvAudioFxState),
&state);
- prtd->state = NVALSA_INVALID_STATE;
+ }
break;
case SNDRV_PCM_TRIGGER_STOP:
if (state != NvAudioFxState_Stop) {
@@ -99,8 +100,8 @@ static int play_thread( void *arg)
&state);
down(&prtd->stop_done_sem);
buffer_in_queue = 0;
- prtd->state = NVALSA_INVALID_STATE;
}
+ break;
default:
;
}
@@ -206,39 +207,40 @@ static int rec_thread( void *arg )
for (;;) {
switch (prtd->state) {
case SNDRV_PCM_TRIGGER_START:
- pin_format.Format.FormatTag = 1;
- pin_format.Format.SampleRate = runtime->rate;
- pin_format.Format.BitsPerSample = runtime->sample_bits;
- pin_format.Format.Channels = runtime->channels;
- pin_format.Format.ChannelMask = 0;
- pin_format.Format.ValidBitsPerSample = 0;
- pin_format.Pin = NvAudioFxSourcePin;
-
- e = tegra_snd_cx->xrt_fxn.SetProperty(
- prtd->stdinpath->Convert,
- NvAudioFxPinProperty_Format,
- sizeof(NvAudioFxPinFormatDescriptor),
- &pin_format);
- if (e != NvSuccess) {
- snd_printk(KERN_ERR"set_property failed!\n");
- }
-
- e = tegra_snd_cx->xrt_fxn.SetProperty(
- prtd->stdinpath->Src,
- NvAudioFxProperty_SampleRate,
- sizeof(NvS32),
- &pin_format.Format.SampleRate);
- if (e != NvSuccess) {
- snd_printk(KERN_ERR "set_property failed!\n");
- }
-
- state = NvAudioFxState_Run;
- tegra_snd_cx->xrt_fxn.SetProperty(
+ if (state != NvAudioFxState_Run) {
+ pin_format.Format.FormatTag = 1;
+ pin_format.Format.SampleRate = runtime->rate;
+ pin_format.Format.BitsPerSample = runtime->sample_bits;
+ pin_format.Format.Channels = runtime->channels;
+ pin_format.Format.ChannelMask = 0;
+ pin_format.Format.ValidBitsPerSample = 0;
+ pin_format.Pin = NvAudioFxSourcePin;
+
+ e = tegra_snd_cx->xrt_fxn.SetProperty(
+ prtd->stdinpath->Convert,
+ NvAudioFxPinProperty_Format,
+ sizeof(NvAudioFxPinFormatDescriptor),
+ &pin_format);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR"set_property failed!\n");
+ }
+
+ e = tegra_snd_cx->xrt_fxn.SetProperty(
+ prtd->stdinpath->Src,
+ NvAudioFxProperty_SampleRate,
+ sizeof(NvS32),
+ &pin_format.Format.SampleRate);
+ if (e != NvSuccess) {
+ snd_printk(KERN_ERR "set_property failed!\n");
+ }
+
+ state = NvAudioFxState_Run;
+ tegra_snd_cx->xrt_fxn.SetProperty(
prtd->stdinpath->Stream,
NvAudioFxProperty_State,
sizeof(NvAudioFxState),
&state);
- prtd->state = NVALSA_INVALID_STATE;
+ }
break;
case SNDRV_PCM_TRIGGER_STOP:
if (state != NvAudioFxState_Stop) {
@@ -250,7 +252,6 @@ static int rec_thread( void *arg )
&state);
down(&prtd->stop_done_sem);
buffer_in_queue = 0;
- prtd->state = NVALSA_INVALID_STATE;
}
goto EXIT;
default:
@@ -332,9 +333,9 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
int ret = 0;
int state = prtd->state;
- prtd->state = cmd;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ prtd->state = cmd;
prtd->cur_pos = 0;
prtd->last_pos = 0;
prtd->audiofx_frames = 0;
@@ -357,6 +358,7 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
}
break;
case SNDRV_PCM_TRIGGER_STOP:
+ prtd->state = cmd;
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: