[alsa-devel] Implementing sync start
Jon Smirl
jonsmirl at gmail.com
Mon Aug 10 04:19:37 CEST 2009
Here's how I implemented sync start/stop.......
/**
* psc_dma_trigger: start and stop the DMA transfer.
*
* This function is called by ALSA to start, stop, pause, and resume the DMA
* transfer of data.
*/
static int psc_dma_trigger(struct snd_pcm_substream *sub, int cmd)
{
struct snd_soc_pcm_runtime *rtd;
struct psc_dma *psc_dma;
struct snd_pcm_runtime *runtime;
struct psc_dma_stream *s;
struct snd_pcm_substream *substream;
struct mpc52xx_psc __iomem *regs;
u16 imr;
unsigned long flags;
int i;
snd_pcm_group_for_each_entry(substream, sub) {
rtd = substream->private_data;
psc_dma = rtd->dai->cpu_dai->private_data;
runtime = substream->runtime;
regs = psc_dma->psc_regs;
dev_dbg(psc_dma->dev, "psc_dma_trigger(substream=%p, cmd=%i)"
" stream_id=%i\n",
sub, cmd, substream->pstr->stream);
if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
s = &psc_dma->capture;
else
s = &psc_dma->playback;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
s->period_bytes = frames_to_bytes(runtime,
runtime->period_size);
s->period_start = virt_to_phys(runtime->dma_area);
s->period_end = s->period_start +
(s->period_bytes * runtime->periods);
s->period_next_pt = s->period_start;
s->period_current_pt = s->period_start;
s->period_size = runtime->period_size;
s->active = 1;
/* track appl_ptr so that we have a better chance of detecting
* end of stream and not over running it.
*/
s->runtime = runtime;
s->appl_ptr = s->runtime->control->appl_ptr -
(runtime->period_size * runtime->periods);
/* Fill up the bestcomm bd queue and enable DMA.
* This will begin filling the PSC's fifo.
*/
spin_lock_irqsave(&psc_dma->lock, flags);
if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
bcom_gen_bd_rx_reset(s->bcom_task);
for (i = 0; i < runtime->periods; i++)
if (!bcom_queue_full(s->bcom_task))
psc_dma_bcom_enqueue_next_buffer(s);
} else {
bcom_gen_bd_tx_reset(s->bcom_task);
psc_dma_bcom_enqueue_tx(s);
}
bcom_enable(s->bcom_task);
spin_unlock_irqrestore(&psc_dma->lock, flags);
out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT);
break;
case SNDRV_PCM_TRIGGER_STOP:
s->active = 0;
spin_lock_irqsave(&psc_dma->lock, flags);
bcom_disable(s->bcom_task);
if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
bcom_gen_bd_rx_reset(s->bcom_task);
else
bcom_gen_bd_tx_reset(s->bcom_task);
spin_unlock_irqrestore(&psc_dma->lock, flags);
break;
default:
dev_dbg(psc_dma->dev, "invalid command\n");
return -EINVAL;
}
if (sub != substream)
snd_pcm_trigger_done(substream, sub);
/* Update interrupt enable settings */
imr = 0;
if (psc_dma->playback.active)
imr |= MPC52xx_PSC_IMR_TXEMP;
if (psc_dma->capture.active)
imr |= MPC52xx_PSC_IMR_ORERR;
out_be16(®s->isr_imr.imr, psc_dma->imr | imr);
}
return 0;
}
--
Jon Smirl
jonsmirl at gmail.com
More information about the Alsa-devel
mailing list