Update of /cvsroot/alsa/alsa-driver/drivers/vx
In directory sc8-pr-cvs1:/tmp/cvs-serv15714/drivers/vx
Modified Files:
vx_core.c vx_pcm.c
Log Message:
fixed the handling of pcm playback. now dmix plugin is working.
Index: vx_core.c
===================================================================
RCS file: /cvsroot/alsa/alsa-driver/drivers/vx/vx_core.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- vx_core.c 25 Feb 2003 15:09:23 -0000 1.5
+++ vx_core.c 21 Mar 2003 10:31:01 -0000 1.6
@@ -511,8 +511,7 @@
static void vx_interrupt(unsigned long private_data)
{
vx_core_t *chip = snd_magic_cast(vx_core_t, (void*)private_data, return);
- unsigned int i, events;
- vx_pipe_t *pipe;
+ unsigned int events;
if (chip->chip_status & VX_STAT_IS_STALE)
return;
@@ -541,19 +540,8 @@
if (events & FREQUENCY_CHANGE_EVENT_PENDING)
vx_change_frequency(chip);
- /* update the pcm pointers as frequently as possible */
- for (i = 0; i < chip->audio_outs; i++) {
- pipe = chip->playback_pipes[i];
- if (pipe && pipe->substream) {
- vx_pcm_playback_update_buffer(chip, pipe->substream, pipe);
- vx_pcm_playback_update(chip, pipe->substream, pipe);
- }
- }
- for (i = 0; i < chip->audio_ins; i++) {
- pipe = chip->capture_pipes[i];
- if (pipe && pipe->substream)
- vx_pcm_capture_update(chip, pipe->substream, pipe);
- }
+ /* update the pcm streams */
+ vx_pcm_update_intr(chip, events);
}
Index: vx_pcm.c
===================================================================
RCS file: /cvsroot/alsa/alsa-driver/drivers/vx/vx_pcm.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- vx_pcm.c 17 Mar 2003 09:07:07 -0000 1.9
+++ vx_pcm.c 21 Mar 2003 10:31:01 -0000 1.10
@@ -22,6 +22,33 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
+ * STRATEGY
+ * for playback, we send series of "chunks", which size is equal with the
+ * IBL size, typically 126 samples. at each end of chunk, the end-of-buffer
+ * interrupt is notified, and the interrupt handler will feed the next chunk.
+ *
+ * for keeping the buffer usage, there are appl_ptr and hw_ptr for each pipe.
+ * the appl_ptr is proceeded at each time the chunk is fed. the hw_ptr is
+ * calculated in the interrupt handler which reflects the current buffer
+ * position.
+ * note that pipe's appl_ptr isn't always identical with
+ * runtime->status->appl_ptr. the actual xrun is checked in the middle layer.
+ *
+ * pipe->transferred is the counter of data which has been already transferred.
+ * if this counter reaches to the period size, snd_pcm_period_elapsed() will
+ * be issued.
+ * meanwhile, pipe->chunk_transferred holds also the data counter but it's
+ * used to check whether the current transfer reaches to the end of the chunk.
+ * if the data of chunk size is processed, the end-of-buffer notify event is
+ * scheduled.
+ *
+ * for capture, the situation is much easier.
+ * to get a low latency response, we'll check the capture streams at each
+ * interrupt (capture stream has no EOB notification). if the pending
+ * data is accumulated to the period size, snd_pcm_period_elapsed() is
+ * called and the pointer is updated.
+ *
+ *
* TODO
* - linked trigger for full-duplex mode.
* - scheduled action on the stream.
@@ -105,7 +132,7 @@
unsigned char *buf = (unsigned char *)(runtime->dma_area + offset);
pipe->hw_ptr += bytes_to_frames(runtime, count);
- if (pipe->hw_ptr >= runtime->buffer_size)
+ if ((unsigned int)pipe->hw_ptr >= runtime->buffer_size)
pipe->hw_ptr -= runtime->buffer_size;
while (count > 0) {
*buf++ = vx_inb(chip, RXH);
@@ -649,7 +676,7 @@
{
int size, space, err = 0;
- size = (int)runtime->control->appl_ptr - pipe->hw_ptr;
+ size = pipe->appl_ptr - pipe->hw_ptr;
if (size < 0)
size += runtime->buffer_size;
size = frames_to_bytes(runtime, size);
@@ -673,7 +700,7 @@
size = bytes_to_frames(runtime, space);
vx_pseudo_dma_write(chip, runtime, pipe, space);
pipe->chunk_transferred += size;
- if (pipe->chunk_transferred >= chip->ibl.min_size) {
+ if (pipe->chunk_transferred >= chip->ibl.size) {
pipe->chunk_transferred = 0;
err = vx_notify_end_of_buffer(chip, pipe);
}
@@ -715,15 +742,19 @@
/*
* transfer the pending playback buffer data to DSP
+ * pip->appl_ptr is forwarded to the number of chunks
* called from interrupt handler
*/
-void vx_pcm_playback_update_buffer(vx_core_t *chip, snd_pcm_substream_t *subs,
vx_pipe_t *pipe)
+static void vx_pcm_playback_transfer(vx_core_t *chip, snd_pcm_substream_t *subs,
vx_pipe_t *pipe, int nchunks)
{
int err;
snd_pcm_runtime_t *runtime = subs->runtime;
if (! pipe->prepared || (chip->chip_status & VX_STAT_IS_STALE))
return;
+ pipe->appl_ptr += chip->ibl.size * nchunks;
+ if ((unsigned int)pipe->appl_ptr >= runtime->buffer_size)
+ pipe->appl_ptr -= runtime->buffer_size;
if ((err = vx_update_playback_buffer(chip, runtime, pipe)) < 0)
return;
}
@@ -732,7 +763,7 @@
* update the playback position and call snd_pcm_period_elapsed() if necessary
* called from interrupt handler
*/
-void vx_pcm_playback_update(vx_core_t *chip, snd_pcm_substream_t *subs, vx_pipe_t
*pipe)
+static void vx_pcm_playback_update(vx_core_t *chip, snd_pcm_substream_t *subs,
vx_pipe_t *pipe)
{
int err;
snd_pcm_runtime_t *runtime = subs->runtime;
@@ -781,14 +812,10 @@
if (chip->chip_status & VX_STAT_IS_STALE)
return -EBUSY;
- /* FIXME: dmix plugin requires no-xrun mode */
- if (subs->runtime->stop_threshold >= subs->runtime->boundary)
- return -EIO;
-
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
if (! pipe->is_capture)
- vx_update_playback_buffer(chip, subs->runtime, pipe);
+ vx_pcm_playback_transfer(chip, subs, pipe, 2);
/* FIXME:
* we trigger the pipe using tasklet, so that the interrupts are
* issued surely after the trigger is completed.
@@ -809,8 +836,6 @@
return err;
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (! pipe->is_capture)
- vx_update_playback_buffer(chip, subs->runtime, pipe);
if ((err = vx_toggle_pipe(chip, pipe, 1)) < 0)
return err;
break;
@@ -901,7 +926,7 @@
}
pipe->buffer_bytes = frames_to_bytes(runtime, runtime->buffer_size);
- pipe->hw_ptr = 0;
+ pipe->appl_ptr = pipe->hw_ptr = 0;
pipe->chunk_transferred = 0;
/* set the timestamp */
@@ -1004,7 +1029,7 @@
/*
* vx_pcm_capture_update - update the capture buffer
*/
-void vx_pcm_capture_update(vx_core_t *chip, snd_pcm_substream_t *subs, vx_pipe_t
*pipe)
+static void vx_pcm_capture_update(vx_core_t *chip, snd_pcm_substream_t *subs,
vx_pipe_t *pipe)
{
int size, space;
snd_pcm_runtime_t *runtime = subs->runtime;
@@ -1070,6 +1095,46 @@
.pointer = vx_pcm_capture_pointer,
.page = snd_pcm_get_vmalloc_page,
};
+
+
+/*
+ * interrupt handler for pcm streams
+ */
+void vx_pcm_update_intr(vx_core_t *chip, unsigned int events)
+{
+ unsigned int i;
+ vx_pipe_t *pipe;
+
+ if (events & END_OF_BUFFER_EVENTS_PENDING) {
+ vx_init_rmh(&chip->irq_rmh, CMD_ASYNC);
+ /* rmh.Cmd[0] |= 0x00000001;*/ /* we ignore the xrun async
notifications, SEL_ASYNC_EVENTS */
+ chip->irq_rmh.Cmd[0] |= 0x00000002; /* SEL_END_OF_BUF_EVENTS */
+
+ if (! vx_send_msg(chip, &chip->irq_rmh)) {
+ for (i = 1; i < chip->irq_rmh.LgStat; i++) {
+ int p, buf, capture;
+ p = chip->irq_rmh.Stat[i] & MASK_FIRST_FIELD;
+ capture = (chip->irq_rmh.Stat[i] & 0x400000) ? 1 : 0;
+ i++;
+ buf = chip->irq_rmh.Stat[i++];
+ if (capture)
+ continue; /* shouldn't happen... */
+ pipe = chip->playback_pipes[p];
+ if (pipe && pipe->substream) {
+ vx_pcm_playback_update(chip, pipe->substream,
pipe);
+ vx_pcm_playback_transfer(chip,
pipe->substream, pipe, buf);
+ }
+ }
+ }
+ }
+
+ /* update the capture pcm pointers as frequently as possible */
+ for (i = 0; i < chip->audio_ins; i++) {
+ pipe = chip->capture_pipes[i];
+ if (pipe && pipe->substream)
+ vx_pcm_capture_update(chip, pipe->substream, pipe);
+ }
+}
/*
-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
Alsa-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/alsa-cvslog