diff options
author | Sumit Bhattacharya <sumitb@nvidia.com> | 2011-02-22 18:58:12 +0530 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2011-03-03 10:49:08 -0800 |
commit | 93e42ab68ea32f5722814d19aebe397f1df64690 (patch) | |
tree | 35d7bfcc06f1dc7edfe5c626febcd00b6e22a195 /sound | |
parent | a2bf16e81127328fa074134bc5be4f8a12cac44d (diff) |
tegra-alsa: return accurate pcm pointer position
Bug 793968
Change-Id: Ia4ee5a83d18b409dd223f70fb1a5a78fad16a08e
Reviewed-on: http://git-master/r/20403
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/tegra/tegra_pcm.c | 107 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_soc.h | 5 |
2 files changed, 51 insertions, 61 deletions
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index c982eb6cddb4..da2d476b6886 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -25,31 +25,19 @@ static void tegra_pcm_play(struct tegra_runtime_data *prtd) { - static int reqid = 0; struct snd_pcm_substream *substream = prtd->substream; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_dma_buffer *buf = &substream->dma_buffer; if (runtime->dma_addr) { prtd->size = frames_to_bytes(runtime, runtime->period_size); - if (reqid == 0) { - if (prtd->dma_state != STATE_ABORT) { - prtd->dma_req1.source_addr = buf->addr + - frames_to_bytes(runtime,prtd->dma_pos); - prtd->dma_req1.size = prtd->size; - tegra_dma_enqueue_req(prtd->dma_chan, - &prtd->dma_req1); - reqid = 1; - } - } else { - if (prtd->dma_state != STATE_ABORT) { - prtd->dma_req2.source_addr = buf->addr + - frames_to_bytes(runtime,prtd->dma_pos); - prtd->dma_req2.size = prtd->size; - tegra_dma_enqueue_req(prtd->dma_chan, - &prtd->dma_req2); - reqid = 0; - } + if (prtd->dma_state != STATE_ABORT) { + prtd->dma_reqid_tail = (prtd->dma_reqid_tail + 1) % DMA_REQ_QCOUNT; + prtd->dma_req[prtd->dma_reqid_tail].source_addr = buf->addr + + frames_to_bytes(runtime,prtd->dma_pos); + prtd->dma_req[prtd->dma_reqid_tail].size = prtd->size; + tegra_dma_enqueue_req(prtd->dma_chan, + &prtd->dma_req[prtd->dma_reqid_tail]); } } @@ -62,31 +50,19 @@ static void tegra_pcm_play(struct tegra_runtime_data *prtd) static void tegra_pcm_capture(struct tegra_runtime_data *prtd) { - static int reqid = 0; struct snd_pcm_substream *substream = prtd->substream; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_dma_buffer *buf = &substream->dma_buffer; if (runtime->dma_addr) { prtd->size = frames_to_bytes(runtime, runtime->period_size); - if (reqid == 0) { - if (prtd->dma_state != STATE_ABORT) { - prtd->dma_req1.dest_addr = buf->addr + - frames_to_bytes(runtime,prtd->dma_pos); - prtd->dma_req1.size = prtd->size; - tegra_dma_enqueue_req(prtd->dma_chan, - &prtd->dma_req1); - reqid = 1; - } - } else { - if (prtd->dma_state != STATE_ABORT) { - prtd->dma_req2.dest_addr = buf->addr + - frames_to_bytes(runtime,prtd->dma_pos); - prtd->dma_req2.size = prtd->size; - tegra_dma_enqueue_req(prtd->dma_chan, - &prtd->dma_req2); - reqid = 0; - } + if (prtd->dma_state != STATE_ABORT) { + prtd->dma_reqid_tail = (prtd->dma_reqid_tail + 1) % DMA_REQ_QCOUNT; + prtd->dma_req[prtd->dma_reqid_tail].dest_addr = buf->addr + + frames_to_bytes(runtime,prtd->dma_pos); + prtd->dma_req[prtd->dma_reqid_tail].size = prtd->size; + tegra_dma_enqueue_req(prtd->dma_chan, + &prtd->dma_req[prtd->dma_reqid_tail]); } } @@ -108,6 +84,7 @@ static void dma_complete_callback (struct tegra_dma_req *req) } if (prtd->dma_state != STATE_ABORT) { + prtd->dma_reqid_head = (prtd->dma_reqid_head + 1) % DMA_REQ_QCOUNT; snd_pcm_period_elapsed(substream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { tegra_pcm_play(prtd); @@ -151,6 +128,8 @@ static int tegra_pcm_prepare(struct snd_pcm_substream *substream) prtd->dma_pos = 0; prtd->period_index = 0; + prtd->dma_reqid_head = 0; + prtd->dma_reqid_tail = DMA_REQ_QCOUNT - 1; return 0; } @@ -158,7 +137,7 @@ static int tegra_pcm_prepare(struct snd_pcm_substream *substream) static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct tegra_runtime_data *prtd = substream->runtime->private_data; - int ret = 0; + int i, ret = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -185,17 +164,19 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) tegra_dma_cancel(prtd->dma_chan); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (prtd->dma_chan) { - tegra_dma_dequeue_req(prtd->dma_chan, - &prtd->dma_req1); - tegra_dma_dequeue_req(prtd->dma_chan, - &prtd->dma_req2); + for (i = 0; i < DMA_REQ_QCOUNT; i++) + tegra_dma_dequeue_req(prtd->dma_chan, + &prtd->dma_req[i]); + prtd->dma_reqid_head = 0; + prtd->dma_reqid_tail = DMA_REQ_QCOUNT - 1; } } else { if (prtd->dma_chan) { - tegra_dma_dequeue_req(prtd->dma_chan, - &prtd->dma_req1); - tegra_dma_dequeue_req(prtd->dma_chan, - &prtd->dma_req2); + for (i = 0; i < DMA_REQ_QCOUNT; i++) + tegra_dma_dequeue_req(prtd->dma_chan, + &prtd->dma_req[i]); + prtd->dma_reqid_head = 0; + prtd->dma_reqid_tail = DMA_REQ_QCOUNT - 1; } } break; @@ -211,7 +192,13 @@ static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd = runtime->private_data; int size; - size = prtd->period_index * runtime->period_size; + + size = (prtd->period_index * runtime->period_size) + + bytes_to_frames(runtime, + tegra_dma_get_transfer_count( + prtd->dma_chan, + &prtd->dma_req[prtd->dma_reqid_head], + false)); return (size); } @@ -219,7 +206,7 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd = 0; - int ret=0; + int i, ret=0; /* Ensure period size is multiple of minimum DMA step size */ ret = snd_pcm_hw_constraint_step(runtime, 0, @@ -249,15 +236,12 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream) prtd->state = STATE_INVALID; - setup_dma_request(substream, - &prtd->dma_req1, - dma_complete_callback, - prtd); - - setup_dma_request(substream, - &prtd->dma_req2, - dma_complete_callback, - prtd); + for (i = 0; i < DMA_REQ_QCOUNT; i++) { + setup_dma_request(substream, + &prtd->dma_req[i], + dma_complete_callback, + prtd); + } prtd->dma_chan = tegra_dma_allocate_channel(TEGRA_DMA_MODE_CONTINUOUS_DOUBLE); if (IS_ERR(prtd->dma_chan)) { @@ -291,6 +275,7 @@ static int tegra_pcm_close(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd = runtime->private_data; + int i; if (!prtd) { printk(KERN_ERR "tegra_pcm_close called with prtd == NULL\n"); @@ -301,11 +286,13 @@ static int tegra_pcm_close(struct snd_pcm_substream *substream) if (prtd->dma_chan) { prtd->dma_state = STATE_EXIT; - tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req1); - tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req2); + for (i = 0; i < DMA_REQ_QCOUNT; i++) + tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[i]); tegra_dma_flush(prtd->dma_chan); tegra_dma_free_channel(prtd->dma_chan); prtd->dma_chan = NULL; + prtd->dma_reqid_head = 0; + prtd->dma_reqid_tail = DMA_REQ_QCOUNT - 1; } kfree(prtd); diff --git a/sound/soc/tegra/tegra_soc.h b/sound/soc/tegra/tegra_soc.h index 1510d6dbee76..215b4c580edb 100644 --- a/sound/soc/tegra/tegra_soc.h +++ b/sound/soc/tegra/tegra_soc.h @@ -76,6 +76,7 @@ #define TEGRA_VOICE_SAMPLE_RATES SNDRV_PCM_RATE_8000 #define DMA_STEP_SIZE_MIN 8 +#define DMA_REQ_QCOUNT 2 struct tegra_dma_channel; @@ -83,7 +84,9 @@ struct tegra_runtime_data { struct snd_pcm_substream *substream; int size; int dma_pos; - struct tegra_dma_req dma_req1, dma_req2; + struct tegra_dma_req dma_req[DMA_REQ_QCOUNT]; + int dma_reqid_head; + int dma_reqid_tail; volatile int state; int period_index; int i2s_shutdown; |