Update of /cvsroot/alsa/alsa-driver/drivers/vx
In directory sc8-pr-cvs1:/tmp/cvs-serv19024/drivers/vx

Modified Files:
        vx_pcm.c 
Log Message:
- fixed the capture.
- fixed the handling of async events.  now duplex mode is working.



Index: vx_pcm.c
===================================================================
RCS file: /cvsroot/alsa/alsa-driver/drivers/vx/vx_pcm.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- vx_pcm.c    21 Mar 2003 10:31:01 -0000      1.10
+++ vx_pcm.c    21 Mar 2003 17:41:56 -0000      1.11
@@ -27,20 +27,10 @@
  *  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.
- *  
+ *  the current position is calculated from the sample count RMH.
  *  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
@@ -48,6 +38,9 @@
  *  data is accumulated to the period size, snd_pcm_period_elapsed() is
  *  called and the pointer is updated.
  *
+ *  the current point of read buffer is kept in pipe->hw_ptr.  note that
+ *  this is in bytes.
+ *
  *
  * TODO
  *  - linked trigger for full-duplex mode.
@@ -98,6 +91,7 @@
        runtime->dma_area = vmalloc_32(size);
        if (! runtime->dma_area)
                return -ENOMEM;
+       memset(runtime->dma_area, 0, size);
        runtime->dma_bytes = size;
        return 1; /* changed */
 }
@@ -119,39 +113,28 @@
 
 
 /*
- * vx_flush_read - read rest of bytes via normal transfer mode
- * @count: bytes to read
- *
- * the data size must be aligned to 3 bytes, though.
- * NB: call with a certain lock!
+ * read three pending pcm bytes via inb()
  */
-static void vx_flush_read(vx_core_t *chip, snd_pcm_runtime_t *runtime,
-                         vx_pipe_t *pipe, int count)
+static void vx_pcm_read_per_bytes(vx_core_t *chip, snd_pcm_runtime_t *runtime, 
vx_pipe_t *pipe)
 {
-       int offset = frames_to_bytes(runtime, pipe->hw_ptr);
+       int offset = pipe->hw_ptr;
        unsigned char *buf = (unsigned char *)(runtime->dma_area + offset);
-
-       pipe->hw_ptr += bytes_to_frames(runtime, count);
-       if ((unsigned int)pipe->hw_ptr >= runtime->buffer_size)
-               pipe->hw_ptr -= runtime->buffer_size;
-       while (count > 0) {
-               *buf++ = vx_inb(chip, RXH);
-               if (++offset >= pipe->buffer_bytes) {
-                       offset = 0;
-                       buf = (unsigned char *)runtime->dma_area;
-               }
-               *buf++ = vx_inb(chip, RXM);
-               if (++offset >= pipe->buffer_bytes) {
-                       offset = 0;
-                       buf = (unsigned char *)runtime->dma_area;
-               }
-               *buf++ = vx_inb(chip, RXL);
-               if (++offset >= pipe->buffer_bytes) {
-                       offset = 0;
-                       buf = (unsigned char *)runtime->dma_area;
-               }
-               count -= 3;
+       *buf++ = vx_inb(chip, RXH);
+       if (++offset >= pipe->buffer_bytes) {
+               offset = 0;
+               buf = (unsigned char *)runtime->dma_area;
+       }
+       *buf++ = vx_inb(chip, RXM);
+       if (++offset >= pipe->buffer_bytes) {
+               offset = 0;
+               buf = (unsigned char *)runtime->dma_area;
+       }
+       *buf++ = vx_inb(chip, RXL);
+       if (++offset >= pipe->buffer_bytes) {
+               offset = 0;
+               buf = (unsigned char *)runtime->dma_area;
        }
+       pipe->hw_ptr = offset;
 }
 
 /*
@@ -663,48 +646,39 @@
 }
 
 /*
- * vx_update_playback_buffer - update the playback buffer
+ * vx_pcm_playback_transfer_chunk - transfer a single chunk
  * @subs: substream
  * @pipe: the pipe to transfer
+ * @size: chunk size in bytes
  *
- * transfer as much data as possible.
+ * transfer a single buffer chunk.  EOB notificaton is added after that.
  * called from the interrupt handler, too.
  *
  * return 0 if ok.
  */
-static int vx_update_playback_buffer(vx_core_t *chip, snd_pcm_runtime_t *runtime, 
vx_pipe_t *pipe)
+static int vx_pcm_playback_transfer_chunk(vx_core_t *chip, snd_pcm_runtime_t 
*runtime, vx_pipe_t *pipe, int size)
 {
-       int size, space, err = 0;
+       int space, err = 0;
 
-       size = pipe->appl_ptr - pipe->hw_ptr;
-       if (size < 0)
-               size += runtime->buffer_size;
-       size = frames_to_bytes(runtime, size);
-       if (! size) /* nothing to copy */
-               return 0;
        space = vx_query_hbuffer_size(chip, pipe);
        if (space < 0) {
                /* disconnect the host, SIZE_HBUF command always switches to the 
stream mode */
                vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);
+               snd_printd("error hbuffer\n");
                return space;
        }
+       if (space < size) {
+               vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);
+               snd_printd("no enough hbuffer space %d\n", space);
+               return -EIO; /* XRUN */
+       }
+               
        /* we don't need irqsave here, because this function
         * is called from either trigger callback or irq handler
         */
        spin_lock(&chip->lock); 
-       if (space > size)
-               space = size;
-       space = (space / pipe->align) * pipe->align;
-       if (! space)
-               goto _finish;
-       size = bytes_to_frames(runtime, space);
-       vx_pseudo_dma_write(chip, runtime, pipe, space);
-       pipe->chunk_transferred += size;
-       if (pipe->chunk_transferred >= chip->ibl.size) {
-               pipe->chunk_transferred = 0;
-               err = vx_notify_end_of_buffer(chip, pipe);
-       }
- _finish:
+       vx_pseudo_dma_write(chip, runtime, pipe, size);
+       err = vx_notify_end_of_buffer(chip, pipe);
        /* disconnect the host, SIZE_HBUF command always switches to the stream mode */
        vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);
        spin_unlock(&chip->lock);
@@ -742,21 +716,20 @@
 
 /*
  * transfer the pending playback buffer data to DSP
- * pip->appl_ptr is forwarded to the number of chunks
  * called from interrupt handler
  */
 static void vx_pcm_playback_transfer(vx_core_t *chip, snd_pcm_substream_t *subs, 
vx_pipe_t *pipe, int nchunks)
 {
-       int err;
+       int i, 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;
+       for (i = 0; i < nchunks; i++) {
+               if ((err = vx_pcm_playback_transfer_chunk(chip, runtime, pipe,
+                                                         chip->ibl.size)) < 0)
+                       return;
+       }
 }
 
 /*
@@ -915,19 +888,14 @@
                return err;
 
        if (vx_is_pcmcia(chip)) {
-               /* minimal DMA alignment = 6 */
-               if (snd_pcm_format_physical_width(runtime->format) == 16)
-                       pipe->align = runtime->channels * 6;
-               else
-                       pipe->align = 6;
+               pipe->align = 2; /* 16bit word */
        } else {
-               /* minimal DMA alignment = 12 */
-               pipe->align = 12;
+               pipe->align = 4; /* 32bit word */
        }
 
        pipe->buffer_bytes = frames_to_bytes(runtime, runtime->buffer_size);
-       pipe->appl_ptr = pipe->hw_ptr = 0;
-       pipe->chunk_transferred = 0;
+       pipe->period_bytes = frames_to_bytes(runtime, runtime->period_size);
+       pipe->hw_ptr = 0;
 
        /* set the timestamp */
        vx_update_pipe_position(chip, runtime, pipe);
@@ -1026,12 +994,15 @@
 }
 
 
+
+#define DMA_READ_ALIGN 6       /* hardware alignment for read */
+
 /*
  * vx_pcm_capture_update - update the capture buffer
  */
 static void vx_pcm_capture_update(vx_core_t *chip, snd_pcm_substream_t *subs, 
vx_pipe_t *pipe)
 {
-       int size, space;
+       int size, space, count;
        snd_pcm_runtime_t *runtime = subs->runtime;
 
        if (! pipe->prepared || (chip->chip_status & VX_STAT_IS_STALE))
@@ -1042,33 +1013,61 @@
                return;
        size = frames_to_bytes(runtime, size);
        space = vx_query_hbuffer_size(chip, pipe);
-       if (space < 0) {
-               /* disconnect the host, SIZE_HBUF command always switches to the 
stream mode */
-               vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT);
-               return;
-       }
+       if (space < 0)
+               goto _error;
        if (size > space)
                size = space;
-       size = (size / pipe->align) * pipe->align;
-       if (! size)
-               goto _finish;
-#if 1 /* read the last aligned frames by vx_flush_read */
-       if (size > pipe->align)
-               vx_pseudo_dma_read(chip, runtime, pipe, size - pipe->align);
- _finish:
+       size = (size / 3) * 3; /* align to 3 bytes */
+       if (size < DMA_READ_ALIGN)
+               goto _error;
+
+       /* keep the last 6 bytes, they will be read after disconnection */
+       count = size - DMA_READ_ALIGN;
+       /* read bytes until the current pointer reaches to the aligned position
+        * for word-transfer
+        */
+       while (count > 0) {
+               if ((pipe->hw_ptr % pipe->align) == 0)
+                       break;
+               if (vx_wait_for_rx_full(chip) < 0)
+                       goto _error;
+               vx_pcm_read_per_bytes(chip, runtime, pipe);
+               count -= 3;
+       }
+       if (count > 0) {
+               /* ok, let's accelerate! */
+               int align = pipe->align * 3;
+               space = (count / align) * align;
+               vx_pseudo_dma_read(chip, runtime, pipe, space);
+               count -= space;
+       }
+       /* read the rest of bytes */
+       while (count > 0) {
+               if (vx_wait_for_rx_full(chip) < 0)
+                       goto _error;
+               vx_pcm_read_per_bytes(chip, runtime, pipe);
+               count -= 3;
+       }
        /* disconnect the host, SIZE_HBUF command always switches to the stream mode */
        vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);
-       vx_flush_read(chip, runtime, pipe, pipe->align);
-#else
-       vx_pseudo_dma_read(chip, runtime, pipe, size);
- _finish:
-       vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);
-#endif
-       pipe->transferred += bytes_to_frames(runtime, size);
-       if (pipe->transferred >= (int)runtime->period_size) {
-               pipe->transferred %= runtime->period_size;
+       /* read the last pending 6 bytes */
+       count = DMA_READ_ALIGN;
+       while (count > 0) {
+               vx_pcm_read_per_bytes(chip, runtime, pipe);
+               count -= 3;
+       }
+       /* update the position */
+       pipe->transferred += size;
+       if (pipe->transferred >= pipe->period_bytes) {
+               pipe->transferred %= pipe->period_bytes;
                snd_pcm_period_elapsed(subs);
        }
+       return;
+
+ _error:
+       /* disconnect the host, SIZE_HBUF command always switches to the stream mode */
+       vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT);
+       return;
 }
 
 /*
@@ -1078,7 +1077,7 @@
 {
        snd_pcm_runtime_t *runtime = subs->runtime;
        vx_pipe_t *pipe = snd_magic_cast(vx_pipe_t, runtime->private_data, return 
-EINVAL);
-       return pipe->hw_ptr;
+       return bytes_to_frames(runtime, pipe->hw_ptr);
 }
 
 /*
@@ -1105,25 +1104,42 @@
        unsigned int i;
        vx_pipe_t *pipe;
 
-       if (events & END_OF_BUFFER_EVENTS_PENDING) {
+#define EVENT_MASK     (END_OF_BUFFER_EVENTS_PENDING|ASYNC_EVENTS_PENDING)
+
+       if (events & EVENT_MASK) {
                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 (events & ASYNC_EVENTS_PENDING)
+                       chip->irq_rmh.Cmd[0] |= 0x00000001;     /* SEL_ASYNC_EVENTS */
+               if (events & END_OF_BUFFER_EVENTS_PENDING)
+                       chip->irq_rmh.Cmd[0] |= 0x00000002;     /* 
SEL_END_OF_BUF_EVENTS */
+
+               if (vx_send_msg(chip, &chip->irq_rmh) < 0) {
+                       snd_printdd(KERN_ERR "msg send error!!\n");
+                       return;
+               }
 
-               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 = 1;
+               while (i < chip->irq_rmh.LgStat) {
+                       int p, buf, capture, eob;
+                       p = chip->irq_rmh.Stat[i] & MASK_FIRST_FIELD;
+                       capture = (chip->irq_rmh.Stat[i] & 0x400000) ? 1 : 0;
+                       eob = (chip->irq_rmh.Stat[i] & 0x800000) ? 1 : 0;
+                       i++;
+                       if (events & ASYNC_EVENTS_PENDING)
+                               i++;
+                       buf = 1; /* force to transfer */
+                       if (events & END_OF_BUFFER_EVENTS_PENDING) {
+                               if (eob)
+                                       buf = chip->irq_rmh.Stat[i];
                                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);
-                               }
+                       }
+                       if (capture)
+                               continue;
+                       snd_assert(p >= 0 && (unsigned int)p < chip->audio_outs,);
+                       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);
                        }
                }
        }
@@ -1167,9 +1183,11 @@
        preferred = chip->ibl.size;
        chip->ibl.size = 0;
        vx_set_ibl(chip, &chip->ibl); /* query the info */
-       if (preferred > 0)
+       if (preferred > 0) {
                chip->ibl.size = ((preferred + chip->ibl.granularity - 1) / 
chip->ibl.granularity) * chip->ibl.granularity;
-       else
+               if (chip->ibl.size > chip->ibl.max_size)
+                       chip->ibl.size = chip->ibl.max_size;
+       } else
                chip->ibl.size = chip->ibl.min_size; /* set to the minimum */
        vx_set_ibl(chip, &chip->ibl);
 



-------------------------------------------------------
This SF.net email is sponsored by:Crypto Challenge is now open! 
Get cracking and register here for some mind boggling fun and 
the chance of winning an Apple iPod:
http://ads.sourceforge.net/cgi-bin/redirect.pl?thaw0031en
_______________________________________________
Alsa-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/alsa-cvslog

Reply via email to