summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSandeep Shinde <sashinde@nvidia.com>2010-04-26 14:48:05 +0530
committerYu-Huan Hsu <yhsu@nvidia.com>2010-04-27 17:23:51 -0700
commit1a6769405dbaa37775cf8ea0018f57d93d171319 (patch)
treece01854e786f24e2f48398220ecb8f273e4d3b82
parent0570c93445adbe2f7156b2eb26190e9987eacf53 (diff)
tegra ALSA: Fixing a hang in streaming playback
In playback, play_thread hangs in case there is no continuous flow of buffers. That is when buffer_queue variable becomes 0 inside play_thread, it might hang on waiting for a semaphore. This conditions always happens in case of streaming playback, where buffer supply may not be continuous at the start. Resolved this hang by making use of ack function available for ALSA driver, this function is called from ALSA middleware whenever application buffer is supplied. Incorporated few more review comments. Fix for bug 674653 Synopsis: kernel spam when playing flash videos Change-Id: I4eeebdc3369b02b849955bd8dab1f8172a85c407 Reviewed-on: http://git-master/r/1211 Reviewed-by: Manjula Gupta <magupta@nvidia.com> Tested-by: Manjula Gupta <magupta@nvidia.com> Reviewed-by: Vijay Mali <vmali@nvidia.com> Tested-by: Vijay Mali <vmali@nvidia.com> Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
-rw-r--r--sound/soc/tegra/tegra_pcm_rpc.c29
-rw-r--r--sound/soc/tegra/tegra_transport.h2
2 files changed, 30 insertions, 1 deletions
diff --git a/sound/soc/tegra/tegra_pcm_rpc.c b/sound/soc/tegra/tegra_pcm_rpc.c
index afa17e4b43e8..3ddd08a471ad 100644
--- a/sound/soc/tegra/tegra_pcm_rpc.c
+++ b/sound/soc/tegra/tegra_pcm_rpc.c
@@ -131,6 +131,13 @@ static int play_thread( void *arg)
size);
}
+ if (buffer_in_queue == 0) {
+ prtd->play_thread_waiting = TRUE;
+ wait_for_completion(&prtd->appl_ptr_comp);
+ prtd->play_thread_waiting = FALSE;
+ init_completion(&prtd->appl_ptr_comp);
+ }
+
if ((buffer_to_prime == buffer_in_queue) ||
(prtd->audiofx_frames >=
runtime->control->appl_ptr)) {
@@ -463,6 +470,12 @@ static int pcm_common_close(struct snd_pcm_substream *substream)
prtd->state = SNDRV_PCM_TRIGGER_STOP;
+ if (completion_done(&prtd->thread_comp) == 0)
+ complete(&prtd->thread_comp);
+
+ if (completion_done(&prtd->appl_ptr_comp) == 0)
+ complete(&prtd->appl_ptr_comp);
+
if (prtd->play_thread)
kthread_stop(prtd->play_thread);
@@ -534,6 +547,8 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream)
goto fail;
init_completion(&prtd->thread_comp);
+ init_completion(&prtd->appl_ptr_comp);
+ prtd->play_thread_waiting = FALSE;
sema_init(&prtd->buf_done_sem, 0);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
@@ -671,6 +686,17 @@ static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
return err;
}
+static int tegra_pcm_ack(struct snd_pcm_substream *substream)
+{
+ struct pcm_runtime_data *prtd = substream->runtime->private_data;
+
+ if (prtd->play_thread_waiting) {
+ complete(&prtd->appl_ptr_comp);
+ }
+
+ return 0;
+}
+
static struct snd_pcm_ops tegra_pcm_ops = {
.open = tegra_pcm_open,
.close = tegra_pcm_close,
@@ -680,7 +706,8 @@ static struct snd_pcm_ops tegra_pcm_ops = {
.prepare = tegra_pcm_prepare,
.trigger = tegra_pcm_trigger,
.pointer = tegra_pcm_pointer,
- .mmap = tegra_pcm_mmap,
+ .mmap = tegra_pcm_mmap,
+ .ack = tegra_pcm_ack,
};
static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
diff --git a/sound/soc/tegra/tegra_transport.h b/sound/soc/tegra/tegra_transport.h
index 9f8cfcc57bc9..74ff22004ce8 100644
--- a/sound/soc/tegra/tegra_transport.h
+++ b/sound/soc/tegra/tegra_transport.h
@@ -391,8 +391,10 @@ struct pcm_runtime_data {
int state;
int stream;
int shutdown_thrd;
+ bool play_thread_waiting;
unsigned int audiofx_frames;
struct completion thread_comp;
+ struct completion appl_ptr_comp;
struct semaphore buf_done_sem;
StandardPath* stdoutpath;
StandardPath* stdinpath;