diff options
author | Manjula Gupta <magupta@nvidia.com> | 2010-06-21 18:00:59 +0530 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-06-22 10:33:02 -0700 |
commit | 04d466815e7dbc2a3c34b9279fba182b92c1a8b3 (patch) | |
tree | 14c3e30d24912fe8ea974fa5dba8f0053ccc69cc /sound | |
parent | cfc9f617720bda069b54d2233ee91d1cd55d9865 (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>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/tegra/tegra_pcm_rpc.c | 72 |
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: |