aboutsummaryrefslogtreecommitdiff
path: root/sys/i386/isa/sound/dmabuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/i386/isa/sound/dmabuf.c')
-rw-r--r--sys/i386/isa/sound/dmabuf.c1944
1 files changed, 1291 insertions, 653 deletions
diff --git a/sys/i386/isa/sound/dmabuf.c b/sys/i386/isa/sound/dmabuf.c
index 0e275b6a3aea..db1824efab15 100644
--- a/sys/i386/isa/sound/dmabuf.c
+++ b/sys/i386/isa/sound/dmabuf.c
@@ -1,10 +1,10 @@
/*
* sound/dmabuf.c
- *
+ *
* The DMA buffer manager for digitized voice applications
- *
- * Copyright by Hannu Savolainen 1993, 1994
- *
+ *
+ * Copyright by Hannu Savolainen 1993, 1994, 1995
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,941 +24,1579 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
-#include "sound_config.h"
+#include <i386/isa/sound/sound_config.h>
+#include <i386/include/md_var.h>
-#ifdef CONFIGURE_SOUNDCARD
+#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS)
+#ifdef ALLOW_POLL
-#include "sound_calls.h"
-
-#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)
+int
+DMAbuf_poll(int dev, struct fileinfo * file, int events, select_table * wait);
+#endif;
-DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_DEV]);
+static void
+reorganize_buffers(int dev, struct dma_buffparms * dmap);
-static struct dma_buffparms dmaps[MAX_AUDIO_DEV] =
-{0}; /*
- * Primitive way to allocate
- * such a large array.
- * Needs dynamic run-time alloction.
- */
+static int *in_sleeper[MAX_AUDIO_DEV] = {NULL};
+static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] = {{0}};
+static int *out_sleeper[MAX_AUDIO_DEV] = {NULL};
+static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] = {{0}};
-static void
-reorganize_buffers (int dev)
-{
- /*
- * This routine breaks the physical device buffers to logical ones.
- */
+static int ndmaps = 0;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
- struct audio_operations *dsp_dev = audio_devs[dev];
+#define MAX_DMAP (MAX_AUDIO_DEV*2)
- unsigned i, p, n;
- unsigned sr, nc, sz, bsz;
+static struct dma_buffparms dmaps[MAX_DMAP] = {{0}};
+/*
+ * Primitive way to allocate such a large array. Needs dynamic run-time
+ * alloction.
+ */
- if (dmap->fragment_size == 0)
- { /* Compute the fragment size using the default algorithm */
+static int space_in_queue(int dev);
- sr = dsp_dev->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1);
- nc = dsp_dev->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1);
- sz = dsp_dev->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1);
+static void dma_reset_output(int dev);
+static void dma_reset_input(int dev);
- if (sr < 1 || nc < 1 || sz < 1)
- {
- printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n",
- dev, sr, nc, sz);
- sr = DSP_DEFAULT_SPEED;
- nc = 1;
- sz = 8;
+static void
+reorganize_buffers(int dev, struct dma_buffparms * dmap)
+{
+ /*
+ * This routine breaks the physical device buffers to logical ones.
+ */
+
+ struct audio_operations *dsp_dev = audio_devs[dev];
+ u_int sr, nc;
+ int bsz, sz, n, i;
+
+ if (dmap->fragment_size == 0) {
+ /* Compute the fragment size using the default algorithm */
+
+ sr = dsp_dev->ioctl(dev, SOUND_PCM_READ_RATE, 0, 1);
+ nc = dsp_dev->ioctl(dev, SOUND_PCM_READ_CHANNELS, 0, 1);
+ sz = dsp_dev->ioctl(dev, SOUND_PCM_READ_BITS, 0, 1);
+
+ if (sz == 8)
+ dmap->neutral_byte = 254;
+ else
+ dmap->neutral_byte = 0x00;
+
+ if (sr < 1 || nc < 1 || sz < 1) {
+ printf("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n",
+ dev, sr, nc, sz);
+ sr = DSP_DEFAULT_SPEED;
+ nc = 1;
+ sz = 8;
}
+ sz = sr * nc * sz;
+
+ sz /= 8; /* #bits -> #bytes */
+
+ /*
+ * Compute a buffer size for time not exeeding 1 second.
+ * Usually this algorithm gives a buffer size for 0.5 to 1.0
+ * seconds of sound (using the current speed, sample size and
+ * #channels).
+ */
+
+ bsz = dsp_dev->buffsize;
+ while (bsz > sz)
+ bsz /= 2;
+
+ if (bsz == dsp_dev->buffsize)
+ bsz /= 2; /* Needs at least 2 buffers */
+
+ if (dmap->subdivision == 0) /* Not already set */
+ dmap->subdivision = 1; /* Init to default value */
+ else
+ bsz /= dmap->subdivision;
+
+ if (bsz < 16)
+ bsz = 16; /* Just a sanity check */
+
+ dmap->fragment_size = bsz;
+ } else {
+ /*
+ * The process has specified the buffer sice with
+ * SNDCTL_DSP_SETFRAGMENT or the buffer sice computation has
+ * already been done.
+ */
+
+ if (dmap->fragment_size > (audio_devs[dev]->buffsize / 2))
+ dmap->fragment_size = (audio_devs[dev]->buffsize / 2);
+ bsz = dmap->fragment_size;
+ }
- sz /= 8; /* #bits -> #bytes */
-
- sz = sr * nc * sz;
+ bsz &= ~0x03; /* Force size which is multiple of 4 bytes */
+#ifdef OS_DMA_ALIGN_CHECK
+ OS_DMA_ALIGN_CHECK(bsz);
+#endif
- /*
- * Compute a buffer size for time not exeeding 1 second.
- * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
- * of sound (using the current speed, sample size and #channels).
- */
+ n = dsp_dev->buffsize / bsz;
- bsz = dsp_dev->buffsize;
- while (bsz > sz)
- bsz /= 2;
+ if (n > MAX_SUB_BUFFERS)
+ n = MAX_SUB_BUFFERS;
- if (dsp_dev->buffcount == 1 && bsz == dsp_dev->buffsize)
- bsz /= 2; /* Needs at least 2 buffers */
+ if (n > dmap->max_fragments)
+ n = dmap->max_fragments;
+ dmap->nbufs = n;
+ dmap->bytes_in_use = n * bsz;
- if (dmap->subdivision == 0) /* Not already set */
- dmap->subdivision = 1; /* Init to default value */
+ for (i = 0; i < dmap->nbufs; i++) {
+ dmap->counts[i] = 0;
+ }
- bsz /= dmap->subdivision;
+ if (dmap->raw_buf)
+ fillw (dmap->neutral_byte, dmap->raw_buf,
+ dmap->bytes_in_use/2);
- if (bsz < 64)
- bsz = 4096; /* Just a sanity check */
+ dmap->flags |= DMA_ALLOC_DONE;
- while ((dsp_dev->buffsize * dsp_dev->buffcount) / bsz > MAX_SUB_BUFFERS)
- bsz *= 2;
+}
- dmap->fragment_size = bsz;
- }
- else
- {
- /*
- * The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or
- * the buffer sice computation has already been done.
- */
- if (dmap->fragment_size > audio_devs[dev]->buffsize)
- dmap->fragment_size = audio_devs[dev]->buffsize;
- bsz = dmap->fragment_size;
+static void
+dma_init_buffers(int dev, struct dma_buffparms * dmap)
+{
+ if (dmap == audio_devs[dev]->dmap_out) {
+ out_sleep_flag[dev].aborting = 0;
+ out_sleep_flag[dev].mode = WK_NONE;
+ } else {
+ in_sleep_flag[dev].aborting = 0;
+ in_sleep_flag[dev].mode = WK_NONE;
}
- /*
- * Now computing addresses for the logical buffers
- */
+ dmap->flags = DMA_BUSY; /* Other flags off */
+ dmap->qlen = dmap->qhead = dmap->qtail = 0;
+ dmap->nbufs = 1;
+ dmap->bytes_in_use = audio_devs[dev]->buffsize;
- n = 0;
- for (i = 0; i < dmap->raw_count &&
- n < dmap->max_fragments &&
- n < MAX_SUB_BUFFERS; i++)
+ dmap->dma_mode = DMODE_NONE;
+ dmap->mapping_flags = 0;
+ dmap->neutral_byte = 0x00;
+}
+
+static int
+open_dmap(int dev, int mode, struct dma_buffparms * dmap, int chan)
+{
+ if (dmap->flags & DMA_BUSY)
+ return -(EBUSY);
+
+#ifdef RUNTIME_DMA_ALLOC
{
- p = 0;
+ int err;
- while ((p + bsz) <= dsp_dev->buffsize &&
- n < dmap->max_fragments &&
- n < MAX_SUB_BUFFERS)
- {
- dmap->buf[n] = dmap->raw_buf[i] + p;
- dmap->buf_phys[n] = dmap->raw_buf_phys[i] + p;
- p += bsz;
- n++;
- }
+ if ((err = sound_alloc_dmap(dev, dmap, chan)) < 0)
+ return err;
}
+#endif
- dmap->nbufs = n;
- dmap->bytes_in_use = n * bsz;
+ if (dmap->raw_buf == NULL)
+ return -(ENOSPC); /* Memory allocation failed during boot */
- for (i = 0; i < dmap->nbufs; i++)
- {
- dmap->counts[i] = 0;
+ if (0) {
+ printf("Unable to grab(2) DMA%d for the audio driver\n", chan);
+ return -(EBUSY);
}
+ dmap->open_mode = mode;
+ dmap->subdivision = dmap->underrun_count = 0;
+ dmap->fragment_size = 0;
+ dmap->max_fragments = 65536; /* Just a large value */
+ dmap->byte_counter = 0;
+ isa_dma_acquire(chan);
- dmap->flags |= DMA_ALLOC_DONE;
+ dma_init_buffers(dev, dmap);
+
+ return 0;
}
static void
-dma_init_buffers (int dev)
+close_dmap(int dev, struct dma_buffparms * dmap, int chan)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap = &dmaps[dev];
-
- RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
-
- dmap->flags = DMA_BUSY; /* Other flags off */
- dmap->qlen = dmap->qhead = dmap->qtail = 0;
-
- dmap->qlen = dmap->qtail = dmap->qhead = 0;
- dmap->dma_mode = DMODE_NONE;
+ if (dmap->flags & DMA_BUSY)
+ dmap->dma_mode = DMODE_NONE;
+ dmap->flags &= ~DMA_BUSY;
+ isa_dma_release(chan);
+#ifdef RUNTIME_DMA_ALLOC
+ sound_free_dmap(dev, dmap);
+#endif
}
int
-DMAbuf_open (int dev, int mode)
+DMAbuf_open(int dev, int mode)
{
- int retval;
- struct dma_buffparms *dmap = NULL;
+ int retval;
+ struct dma_buffparms *dmap_in = NULL;
+ struct dma_buffparms *dmap_out = NULL;
- if (dev >= num_audiodevs)
- {
- printk ("PCM device %d not installed.\n", dev);
- return RET_ERROR (ENXIO);
+ if (dev >= num_audiodevs) {
+ printf("PCM device %d not installed.\n", dev);
+ return -(ENXIO);
}
-
- if (!audio_devs[dev])
- {
- printk ("PCM device %d not initialized\n", dev);
- return RET_ERROR (ENXIO);
+ if (!audio_devs[dev]) {
+ printf("PCM device %d not initialized\n", dev);
+ return -(ENXIO);
}
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX)) {
+ audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out;
+ audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1;
+ }
+ if ((retval = audio_devs[dev]->open(dev, mode)) < 0)
+ return retval;
- dmap = audio_devs[dev]->dmap = &dmaps[dev];
-
- if (dmap->flags & DMA_BUSY)
- return RET_ERROR (EBUSY);
+ dmap_out = audio_devs[dev]->dmap_out;
+ dmap_in = audio_devs[dev]->dmap_in;
-#ifdef USE_RUNTIME_DMAMEM
- dmap->raw_buf[0] = NULL;
- sound_dma_malloc (dev);
-#endif
+ if ((retval = open_dmap(dev, mode, dmap_out, audio_devs[dev]->dmachan1)) < 0) {
+ audio_devs[dev]->close(dev);
+ return retval;
+ }
+ audio_devs[dev]->enable_bits = mode;
- if (dmap->raw_buf[0] == NULL)
- return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */
+ if (audio_devs[dev]->flags & DMA_DUPLEX && dmap_out != dmap_in) {
+ if ((retval = open_dmap(dev, mode, dmap_in, audio_devs[dev]->dmachan2)) < 0) {
+ audio_devs[dev]->close(dev);
+ close_dmap(dev, dmap_out, audio_devs[dev]->dmachan1);
+ return retval;
+ }
+ }
+ audio_devs[dev]->open_mode = mode;
+ audio_devs[dev]->go = 1;
- if ((retval = audio_devs[dev]->open (dev, mode)) < 0)
- return retval;
+ in_sleep_flag[dev].aborting = 0;
+ in_sleep_flag[dev].mode = WK_NONE;
- dmap->open_mode = mode;
- dmap->subdivision = dmap->underrun_count = 0;
- dmap->fragment_size = 0;
- dmap->max_fragments = 65536; /* Just a large value */
+ out_sleep_flag[dev].aborting = 0;
+ out_sleep_flag[dev].mode = WK_NONE;
- dma_init_buffers (dev);
- audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1);
- audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1);
- audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1);
+ audio_devs[dev]->ioctl(dev, SOUND_PCM_WRITE_BITS, (ioctl_arg) 8, 1);
+ audio_devs[dev]->ioctl(dev, SOUND_PCM_WRITE_CHANNELS, (ioctl_arg) 1, 1);
+ audio_devs[dev]->ioctl(dev, SOUND_PCM_WRITE_RATE, (ioctl_arg) DSP_DEFAULT_SPEED, 1);
- return 0;
+ return 0;
}
static void
-dma_reset (int dev)
+dma_reset(int dev)
{
- int retval;
- unsigned long flags;
+ u_long flags;
- DISABLE_INTR (flags);
+ flags = splhigh();
+ audio_devs[dev]->reset(dev);
+ splx(flags);
- audio_devs[dev]->reset (dev);
- audio_devs[dev]->close (dev);
+ dma_reset_output(dev);
- if ((retval = audio_devs[dev]->open (dev, audio_devs[dev]->dmap->open_mode)) < 0)
- printk ("Sound: Reset failed - Can't reopen device\n");
- RESTORE_INTR (flags);
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ dma_reset_input(dev);
+}
- dma_init_buffers (dev);
- reorganize_buffers (dev);
+static void
+dma_reset_output(int dev)
+{
+ u_long flags;
+
+ flags = splhigh();
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
+ !audio_devs[dev]->halt_output)
+ audio_devs[dev]->reset(dev);
+ else
+ audio_devs[dev]->halt_output(dev);
+ splx(flags);
+
+ dma_init_buffers(dev, audio_devs[dev]->dmap_out);
+ reorganize_buffers(dev, audio_devs[dev]->dmap_out);
+}
+
+static void
+dma_reset_input(int dev)
+{
+ u_long flags;
+
+ flags = splhigh();
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
+ !audio_devs[dev]->halt_input)
+ audio_devs[dev]->reset(dev);
+ else
+ audio_devs[dev]->halt_input(dev);
+ splx(flags);
+
+ dma_init_buffers(dev, audio_devs[dev]->dmap_in);
+ reorganize_buffers(dev, audio_devs[dev]->dmap_in);
}
static int
-dma_sync (int dev)
+dma_sync(int dev)
{
- unsigned long flags;
+ u_long flags;
+ int i = 0;
+
+ if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))
+ return 0;
+
+ if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) {
+ flags = splhigh();
+
+ out_sleep_flag[dev].aborting = 0;
+#ifdef ALLOW_BUFFER_MAPPING
+ if(audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED &&
+ audio_devs[dev]->dmap_out->qlen) {
+ splx(flags);
+
+ return audio_devs[dev]->dmap_out->qlen;
+ }
- if (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT)
- {
- DISABLE_INTR (flags);
+#endif
+ while (!PROCESS_ABORTING (out_sleep_flag[dev])
+ && audio_devs[dev]->dmap_out->qlen){
+ int chn;
+
+ out_sleeper[dev] = &chn;
+ DO_SLEEP1(chn, out_sleep_flag[dev], 10 * hz);
+ if (TIMED_OUT (out_sleep_flag[dev]) ) {
+
+ splx(flags);
+
+ return audio_devs[dev]->dmap_out->qlen;
- while (!PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])
- && audio_devs[dev]->dmap->qlen)
- {
- DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ);
- if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- RESTORE_INTR (flags);
- return audio_devs[dev]->dmap->qlen;
- }
+ }
}
- RESTORE_INTR (flags);
- /*
- * Some devices such as GUS have huge amount of on board RAM for the
- * audio data. We have to wait util the device has finished playing.
- */
- DISABLE_INTR (flags);
- if (audio_devs[dev]->local_qlen) /* Device has hidden buffers */
- {
- while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
- && audio_devs[dev]->local_qlen (dev))
- {
- DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ);
+ splx(flags);
+
+ /*
+ * Some devices such as GUS have huge amount of on board RAM
+ * for the audio data. We have to wait until the device has
+ * finished playing.
+ */
+
+ flags = splhigh();
+ if (audio_devs[dev]->local_qlen) { /* Device has hidden buffers */
+ while (!(PROCESS_ABORTING (out_sleep_flag[dev]))
+ && audio_devs[dev]->local_qlen(dev)) {
+ int chn;
+ out_sleeper[dev] = &chn;
+ DO_SLEEP(chn, out_sleep_flag[dev], 10 * hz);
+
}
}
- RESTORE_INTR (flags);
+ splx(flags);
}
- return audio_devs[dev]->dmap->qlen;
+ return audio_devs[dev]->dmap_out->qlen;
}
int
-DMAbuf_release (int dev, int mode)
+DMAbuf_release(int dev, int mode)
{
- unsigned long flags;
+ u_long flags;
- if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
- && (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT))
- {
- dma_sync (dev);
+ if (!((out_sleep_flag[dev].aborting))
+ && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) {
+ dma_sync(dev);
}
+ flags = splhigh();
-#ifdef USE_RUNTIME_DMAMEM
- sound_dma_free (dev);
-#endif
+ audio_devs[dev]->close(dev);
- DISABLE_INTR (flags);
- audio_devs[dev]->reset (dev);
+ close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
- audio_devs[dev]->close (dev);
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ close_dmap(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
+ audio_devs[dev]->open_mode = 0;
- audio_devs[dev]->dmap->dma_mode = DMODE_NONE;
- audio_devs[dev]->dmap->flags &= ~DMA_BUSY;
- RESTORE_INTR (flags);
+ splx(flags);
- return 0;
+ return 0;
}
-int
-DMAbuf_getrdbuffer (int dev, char **buf, int *len)
+static int
+activate_recording(int dev, struct dma_buffparms * dmap)
{
- unsigned long flags;
- int err = EIO;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT))
+ return 0;
- DISABLE_INTR (flags);
- if (!dmap->qlen)
- {
- if (dmap->flags & DMA_RESTART)
- {
- dma_reset (dev);
- dmap->flags &= ~DMA_RESTART;
- }
+ if (dmap->flags & DMA_RESTART) {
+ dma_reset_input(dev);
+ dmap->flags &= ~DMA_RESTART;
+ }
+ if (dmap->dma_mode == DMODE_OUTPUT) { /* Direction change */
+ dma_sync(dev);
+ dma_reset(dev);
+ dmap->dma_mode = DMODE_NONE;
+ }
+ if (!(dmap->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap);
- if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */
- {
- dma_sync (dev);
- dma_reset (dev);
- dmap->dma_mode = DMODE_NONE;
- }
+ if (!dmap->dma_mode) {
+ int err;
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
+ if ((err = audio_devs[dev]->prepare_for_input(dev,
+ dmap->fragment_size, dmap->nbufs)) < 0) {
+ return err;
+ }
+ dmap->dma_mode = DMODE_INPUT;
+ }
+ if (!(dmap->flags & DMA_ACTIVE)) {
+ audio_devs[dev]->start_input(dev,
+ dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size,
+ dmap->fragment_size, 0,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
+ !(dmap->flags & DMA_STARTED));
+ dmap->flags |= DMA_ACTIVE | DMA_STARTED;
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+ return 0;
+}
- if (dmap->dma_mode)
- {
- int err;
+int
+DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
+{
+ u_long flags;
+ int err = EIO;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
+
+ flags = splhigh();
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) {
+ printf("Sound: Can't read from mmapped device (1)\n");
+ return -(EINVAL);
+ } else
+#endif
+ if (!dmap->qlen) {
+ int timeout;
- if ((err = audio_devs[dev]->prepare_for_input (dev,
- dmap->fragment_size, dmap->nbufs)) < 0)
- {
- RESTORE_INTR (flags);
- return err;
- }
- dmap->dma_mode = DMODE_INPUT;
+ if ((err = activate_recording(dev, dmap)) < 0) {
+ splx(flags);
+ return err;
}
+ /* Wait for the next block */
- if (!(dmap->flags & DMA_ACTIVE))
- {
- audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail],
- dmap->fragment_size, 0,
- !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
- !(dmap->flags & DMA_STARTED));
- dmap->flags |= DMA_ACTIVE | DMA_STARTED;
+ if (dontblock) {
+ splx(flags);
+ return -(EAGAIN);
}
+ if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) &
+ audio_devs[dev]->go) {
+ splx(flags);
+ return -(EAGAIN);
+ }
+ if (!audio_devs[dev]->go)
+ timeout = 0;
+ else
+ timeout = 2 * hz;
- /* Wait for the next block */
-
- DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
- if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
{
- printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
- err = EIO;
- SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
- }
- else
- err = EINTR;
+ int chn;
+
+ in_sleeper[dev] = &chn;
+ DO_SLEEP(chn, in_sleep_flag[dev], timeout);
+
+ };
+ /* XXX note -- nobody seems to set the mode to WK_TIMEOUT - lr */
+ if ((in_sleep_flag[dev].mode & WK_TIMEOUT)) {
+ /* XXX hey, we are in splhigh here ? lr 970705 */
+ printf("Sound: DMA (input) timed out - IRQ/DRQ config error?\n");
+ err = EIO;
+ audio_devs[dev]->reset(dev);
+ in_sleep_flag[dev].aborting = 1;
+ } else
+ err = EINTR;
}
- RESTORE_INTR (flags);
+ splx(flags);
- if (!dmap->qlen)
- return RET_ERROR (err);
+ if (!dmap->qlen)
+ return -(err);
- *buf = &dmap->buf[dmap->qhead][dmap->counts[dmap->qhead]];
- *len = dmap->fragment_size - dmap->counts[dmap->qhead];
+ *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]];
+ *len = dmap->fragment_size - dmap->counts[dmap->qhead];
- return dmap->qhead;
+ return dmap->qhead;
}
int
-DMAbuf_rmchars (int dev, int buff_no, int c)
+DMAbuf_rmchars(int dev, int buff_no, int c)
+{
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
+
+ int p = dmap->counts[dmap->qhead] + c;
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) {
+ printf("Sound: Can't read from mmapped device (2)\n");
+ return -(EINVAL);
+ } else
+#endif
+ if (p >= dmap->fragment_size) { /* This buffer is completely empty */
+ dmap->counts[dmap->qhead] = 0;
+ if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+ printf("\nSound: Audio queue1 corrupted for dev%d (%d/%d)\n",
+ dev, dmap->qlen, dmap->nbufs);
+ dmap->qlen--;
+ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+ } else
+ dmap->counts[dmap->qhead] = p;
+
+ return 0;
+}
+
+static int
+dma_subdivide(int dev, struct dma_buffparms * dmap, ioctl_arg arg, int fact)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ if (fact == 0) {
+ fact = dmap->subdivision;
+ if (fact == 0)
+ fact = 1;
+ return *(int *) arg = fact;
+ }
+ if (dmap->subdivision != 0 || dmap->fragment_size)/* Loo late to change */
+ return -(EINVAL);
- int p = dmap->counts[dmap->qhead] + c;
+ if (fact > MAX_REALTIME_FACTOR)
+ return -(EINVAL);
+
+ if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
+ return -(EINVAL);
+
+ dmap->subdivision = fact;
+ return *(int *) arg = fact;
+}
+
+static int
+dma_set_fragment(int dev, struct dma_buffparms * dmap, ioctl_arg arg, int fact)
+{
+ int bytes, count;
+
+ if (fact == 0)
+ return -(EIO);
+
+ if (dmap->subdivision != 0 || dmap->fragment_size)/* Loo late to change */
+ return -(EINVAL);
+
+ bytes = fact & 0xffff;
+ count = (fact >> 16) & 0xffff;
+
+ if (count == 0)
+ count = MAX_SUB_BUFFERS;
+
+#if amancio
+ if (bytes < 4 || bytes > 17) /* <16 || > 128k */
+ return -(EINVAL);
+#endif
+
+ if (count < 2)
+ return -(EINVAL);
+
+#ifdef OS_DMA_MINBITS
+ if (bytes < OS_DMA_MINBITS)
+ bytes = OS_DMA_MINBITS;
+#endif
+
+ dmap->fragment_size = (1 << bytes);
+
+ dmap->max_fragments = count;
+
+ if (dmap->fragment_size > audio_devs[dev]->buffsize)
+ dmap->fragment_size = audio_devs[dev]->buffsize;
+
+ if (dmap->fragment_size == audio_devs[dev]->buffsize &&
+ audio_devs[dev]->flags & DMA_AUTOMODE)
+ dmap->fragment_size /= 2; /* Needs at least 2 buffers */
+
+ dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */
+ return *(int *) arg = bytes | (count << 16);
+}
+
+static int
+get_buffer_pointer(int dev, int chan, struct dma_buffparms * dmap)
+{
+ int pos;
+ u_long flags;
+
+ flags = splhigh();
- if (p >= dmap->fragment_size)
- { /* This buffer is completely empty */
- dmap->counts[dmap->qhead] = 0;
- if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
- printk ("\nSound: Audio queue1 corrupted for dev%d (%d/%d)\n",
- dev, dmap->qlen, dmap->nbufs);
- dmap->qlen--;
- dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+ if (!(dmap->flags & DMA_ACTIVE))
+ pos = 0;
+ else
+ {
+ pos = isa_dmastatus(chan);
}
+
+ splx(flags);
+
+ pos = dmap->bytes_in_use - pos ;
+ if (audio_devs[dev]->flags & DMA_AUTOMODE)
+ return pos;
else
- dmap->counts[dmap->qhead] = p;
+ {
+ pos = dmap->fragment_size - pos;
+ if (pos < 0)
+ return 0;
+ return pos;
+ }
+
- return 0;
}
int
-DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+DMAbuf_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out;
+ struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in;
+
+ switch (cmd) {
+
- switch (cmd)
- {
case SNDCTL_DSP_RESET:
- dma_reset (dev);
- return 0;
- break;
+ dma_reset(dev);
+ return 0;
+ break;
case SNDCTL_DSP_SYNC:
- dma_sync (dev);
- dma_reset (dev);
- return 0;
- break;
+ dma_sync(dev);
+ dma_reset(dev);
+ return 0;
+ break;
case SNDCTL_DSP_GETBLKSIZE:
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
+ if (!(dmap_out->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap_out);
- return IOCTL_OUT (arg, dmap->fragment_size);
- break;
+ return *(int *) arg = dmap_out->fragment_size;
+ break;
- case SNDCTL_DSP_SUBDIVIDE:
- {
- int fact = IOCTL_IN (arg);
+ case SNDCTL_DSP_SETBLKSIZE:
+ {
+ int size = (*(int *) arg);
- if (fact == 0)
- {
- fact = dmap->subdivision;
- if (fact == 0)
- fact = 1;
- return IOCTL_OUT (arg, fact);
- }
+ if (!(dmap_out->flags & DMA_ALLOC_DONE) && size) {
+ if ((size >> 16) > 0 )
+ dmap_out->fragment_size = size >> 16;
+ else {
+ dmap_out->fragment_size = size;
+ }
+ dmap_out->max_fragments = 8888;
+
+ size &= 0xffff;
- if (dmap->subdivision != 0 ||
- dmap->fragment_size)/* Loo late to change */
- return RET_ERROR (EINVAL);
+ if (audio_devs[dev]->flags & DMA_DUPLEX) {
+ dmap_in->fragment_size = size;
+ dmap_in->max_fragments = 8888;
+ }
+ return 0;
- if (fact > MAX_REALTIME_FACTOR)
- return RET_ERROR (EINVAL);
+ } else
+ return -(EINVAL); /* Too late to change */
+
+ }
+ break;
+
+ case SNDCTL_DSP_SUBDIVIDE:
+ {
+ int fact = (*(int *) arg);
+ int ret;
- if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
- return RET_ERROR (EINVAL);
+ ret = dma_subdivide(dev, dmap_out, arg, fact);
+ if (ret < 0)
+ return ret;
- dmap->subdivision = fact;
- return IOCTL_OUT (arg, fact);
- }
- break;
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ ret = dma_subdivide(dev, dmap_in, arg, fact);
+
+ return ret;
+ }
+ break;
case SNDCTL_DSP_SETFRAGMENT:
- {
- int fact = IOCTL_IN (arg);
- int bytes, count;
+ {
+ int fact = (*(int *) arg);
+ int ret;
- if (fact == 0)
- return RET_ERROR (EIO);
+ ret = dma_set_fragment(dev, dmap_out, arg, fact);
+ if (ret < 0)
+ return ret;
- if (dmap->subdivision != 0 ||
- dmap->fragment_size)/* Loo late to change */
- return RET_ERROR (EINVAL);
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ ret = dma_set_fragment(dev, dmap_in, arg, fact);
- bytes = fact & 0xffff;
- count = (fact >> 16) & 0xffff;
+ return ret;
+ }
+ break;
- if (count == 0)
- count = MAX_SUB_BUFFERS;
+ case SNDCTL_DSP_GETISPACE:
+ case SNDCTL_DSP_GETOSPACE:
+ if (!local)
+ return -(EINVAL);
+ else {
+ struct dma_buffparms *dmap = dmap_out;
- if (bytes < 7 || bytes > 17) /* <64 || > 128k */
- return RET_ERROR (EINVAL);
+ audio_buf_info *info = (audio_buf_info *) arg;
- if (count < 2)
- return RET_ERROR (EINVAL);
+ if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
+ dmap = dmap_in;
- dmap->fragment_size = (1 << bytes);
- dmap->max_fragments = count;
+#ifdef ALLOW_BUFFER_MAPPING
+ if (dmap->mapping_flags & DMA_MAP_MAPPED)
+ return -(EINVAL);
+#endif
- if (dmap->fragment_size > audio_devs[dev]->buffsize)
- dmap->fragment_size = audio_devs[dev]->buffsize;
+ if (!(dmap->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap);
+
+ info->fragstotal = dmap->nbufs;
+
+ if (cmd == SNDCTL_DSP_GETISPACE)
+ info->fragments = dmap->qlen;
+ else {
+ if (!space_in_queue(dev))
+ info->fragments = 0;
+ else {
+ info->fragments = dmap->nbufs - dmap->qlen;
+ if (audio_devs[dev]->local_qlen) {
+ int tmp = audio_devs[dev]->local_qlen(dev);
+
+ if (tmp & info->fragments)
+ tmp--; /* This buffer has been counted twice */
+ info->fragments -= tmp;
+ }
+ }
+ }
- if (dmap->fragment_size == audio_devs[dev]->buffsize &&
- audio_devs[dev]->flags & DMA_AUTOMODE)
- dmap->fragment_size /= 2; /* Needs at least 2 buffers */
+ if (info->fragments < 0)
+ info->fragments = 0;
+ else if (info->fragments > dmap->nbufs)
+ info->fragments = dmap->nbufs;
- dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */
- return IOCTL_OUT (arg, bytes | (count << 16));
- }
- break;
+ info->fragsize = dmap->fragment_size;
+ info->bytes = info->fragments * dmap->fragment_size;
+
+ if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen)
+ info->bytes -= dmap->counts[dmap->qhead];
+ }
+ return 0;
+
+ case SNDCTL_DSP_SETTRIGGER:
+ {
+ u_long flags;
+
+ int bits = (*(int *) arg) & audio_devs[dev]->open_mode;
+ int changed;
+
+ if (audio_devs[dev]->trigger == NULL)
+ return -(EINVAL);
+
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX))
+ if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT)) {
+ printf("Sound: Device doesn't have full duplex capability\n");
+ return -(EINVAL);
+ }
+ flags = splhigh();
+ changed = audio_devs[dev]->enable_bits ^ bits;
+
+ if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) {
+ if (!(dmap_in->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap_in);
+ activate_recording(dev, dmap_in);
+ }
+#ifdef ALLOW_BUFFER_MAPPING
+ if ((changed & bits) & PCM_ENABLE_OUTPUT &&
+ dmap_out->mapping_flags & DMA_MAP_MAPPED &&
+ audio_devs[dev]->go) {
+ if (!(dmap_out->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap_out);
+
+ audio_devs[dev]->prepare_for_output (dev,
+ dmap_out->fragment_size, dmap_out->nbufs);
+
+ dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
+ DMAbuf_start_output(dev, 0, dmap_out->fragment_size);
+ dmap_out->dma_mode = DMODE_OUTPUT;
+ }
+#endif
+
+ audio_devs[dev]->enable_bits = bits;
+ if (changed && audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev, bits * audio_devs[dev]->go);
+ splx(flags);
+ }
+ case SNDCTL_DSP_GETTRIGGER:
+ return *(int *) arg = audio_devs[dev]->enable_bits;
+ break;
+
+ case SNDCTL_DSP_SETSYNCRO:
+
+ if (!audio_devs[dev]->trigger)
+ return -(EINVAL);
+
+ audio_devs[dev]->trigger(dev, 0);
+ audio_devs[dev]->go = 0;
+ return 0;
+ break;
+
+ case SNDCTL_DSP_GETIPTR:
+ {
+ count_info info;
+ u_long flags;
+
+ flags = splhigh();
+ info.bytes = audio_devs[dev]->dmap_in->byte_counter;
+ info.ptr = get_buffer_pointer(dev, audio_devs[dev]->dmachan2, audio_devs[dev]->dmap_in);
+ info.blocks = audio_devs[dev]->dmap_in->qlen;
+ info.bytes += info.ptr;
+
+ bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
+ audio_devs[dev]->dmap_in->qlen = 0; /* Ack interrupts */
+#endif
+ splx(flags);
+ return 0;
+ }
+ break;
+
+ case SNDCTL_DSP_GETOPTR:
+ {
+ count_info info;
+ u_long flags;
+
+ flags = splhigh();
+ info.bytes = audio_devs[dev]->dmap_out->byte_counter;
+ info.ptr = get_buffer_pointer(dev, audio_devs[dev]->dmachan1, audio_devs[dev]->dmap_out);
+ info.blocks = audio_devs[dev]->dmap_out->qlen;
+ info.bytes += info.ptr;
+ bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
+ audio_devs[dev]->dmap_out->qlen = 0; /* Ack interrupts */
+#endif
+ splx(flags);
+ return 0;
+ }
+ break;
default:
- return audio_devs[dev]->ioctl (dev, cmd, arg, local);
+ return audio_devs[dev]->ioctl(dev, cmd, arg, local);
}
+}
- return RET_ERROR (EIO);
+/*
+ * DMAbuf_start_devices() is called by the /dev/music driver to start one or
+ * more audio devices at desired moment.
+ */
+
+void
+DMAbuf_start_devices(u_int devmask)
+{
+ int dev;
+
+ for (dev = 0; dev < num_audiodevs; dev++)
+ if (devmask & (1 << dev))
+ if (audio_devs[dev]->open_mode != 0)
+ if (!audio_devs[dev]->go) {
+ /* OK to start the device */
+ audio_devs[dev]->go = 1;
+
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
}
static int
-space_in_queue (int dev)
+space_in_queue(int dev)
{
- int len, max, tmp;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
-
- if (dmap->qlen == dmap->nbufs)/* No space at all */
- return 0;
-
- /*
- * Verify that there are no more pending buffers than the limit
- * defined by the process.
- */
-
- max = dmap->max_fragments;
- len = dmap->qlen;
-
- if (audio_devs[dev]->local_qlen)
- {
- tmp = audio_devs[dev]->local_qlen (dev);
- if (tmp & len)
- tmp--; /*
- * This buffer has been counted twice
- */
- len += tmp;
+ int len, max, tmp;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+ if (dmap->qlen >= dmap->nbufs) /* No space at all */
+ return 0;
+
+ /*
+ * Verify that there are no more pending buffers than the limit
+ * defined by the process.
+ */
+
+ max = dmap->max_fragments;
+ len = dmap->qlen;
+
+ if (audio_devs[dev]->local_qlen) {
+ tmp = audio_devs[dev]->local_qlen(dev);
+ if (tmp & len)
+ tmp--; /* This buffer has been counted twice */
+ len += tmp;
}
- if (len >= max)
- return 0;
- return 1;
+ if (len >= max)
+ return 0;
+ return 1;
}
int
-DMAbuf_getwrbuffer (int dev, char **buf, int *size)
+DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock)
{
- unsigned long flags;
- int abort, err = EIO;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
-
- if (dmap->dma_mode == DMODE_INPUT) /* Direction change */
- {
- dma_reset (dev);
- dmap->dma_mode = DMODE_NONE;
- }
- else if (dmap->flags & DMA_RESTART) /* Restart buffering */
- {
- dma_sync (dev);
- dma_reset (dev);
+ u_long flags;
+ int abort, err = EIO;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) {
+ printf("Sound: Can't write to mmapped device (3)\n");
+ return -(EINVAL);
}
+#endif
- dmap->flags &= ~DMA_RESTART;
+ if (dmap->dma_mode == DMODE_INPUT) { /* Direction change */
+ dma_reset(dev);
+ dmap->dma_mode = DMODE_NONE;
+ } else if (dmap->flags & DMA_RESTART) { /* Restart buffering */
+ dma_sync(dev);
+ dma_reset_output(dev);
+ }
+ dmap->flags &= ~DMA_RESTART;
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
+ if (!(dmap->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap);
- if (!dmap->dma_mode)
- {
- int err;
+ if (!dmap->dma_mode) {
+ int err;
- dmap->dma_mode = DMODE_OUTPUT;
- if ((err = audio_devs[dev]->prepare_for_output (dev,
- dmap->fragment_size, dmap->nbufs)) < 0)
- return err;
+ dmap->dma_mode = DMODE_OUTPUT;
+ if ((err = audio_devs[dev]->prepare_for_output(dev,
+ dmap->fragment_size, dmap->nbufs)) < 0)
+ return err;
}
+ flags = splhigh();
+ abort = 0;
+ while (!space_in_queue(dev) && !abort) {
+ int timeout;
- DISABLE_INTR (flags);
+ if (dontblock) {
+ splx(flags);
+ return -(EAGAIN);
+ }
+ if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT) &&
+ audio_devs[dev]->go) {
+ splx(flags);
+ return -(EAGAIN);
+ }
+ /*
+ * Wait for free space
+ */
+ if (!audio_devs[dev]->go)
+ timeout = 0;
+ else
+ timeout = 2 * hz;
- abort = 0;
- while (!space_in_queue (dev) &&
- !abort)
- {
- /*
- * Wait for free space
- */
- DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
- if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
{
- printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
- err = EIO;
- abort = 1;
- SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
+ int chn;
+
+ out_sleep_flag[dev].mode = WK_SLEEP;
+ out_sleeper[dev] = &chn;
+ DO_SLEEP2(chn, out_sleep_flag[dev], timeout);
+
+ if ((out_sleep_flag[dev].mode & WK_TIMEOUT)) {
+ printf("Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
+ err = EIO;
+ abort = 1;
+ out_sleep_flag[dev].aborting = 1;
+ audio_devs[dev]->reset(dev);
+ } else if ((out_sleep_flag[dev].aborting) ||
+ CURSIG(curproc)) {
+ err = EINTR;
+ abort = 1;
}
- else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- err = EINTR;
- abort = 1;
}
}
- RESTORE_INTR (flags);
+ splx(flags);
- if (!space_in_queue (dev))
- {
- return RET_ERROR (err); /* Caught a signal ? */
+ if (!space_in_queue(dev)) {
+ return -(err); /* Caught a signal ? */
}
-
- *buf = dmap->buf[dmap->qtail];
- *size = dmap->fragment_size;
- dmap->counts[dmap->qtail] = 0;
-
- return dmap->qtail;
+ *buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;
+ *size = dmap->fragment_size;
+ dmap->counts[dmap->qtail] = 0;
+ return dmap->qtail;
}
int
-DMAbuf_start_output (int dev, int buff_no, int l)
+DMAbuf_start_output(int dev, int buff_no, int l)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
- if (buff_no != dmap->qtail)
- printk ("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail);
+ /*
+ * Bypass buffering if using mmaped access
+ */
- dmap->qlen++;
- if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
- printk ("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n",
- dev, dmap->qlen, dmap->nbufs);
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) {
+ l = dmap->fragment_size;
+ dmap->counts[dmap->qtail] = l;
+ dmap->flags &= ~DMA_RESTART;
+ dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ } else
+#else
+ if (dmap != NULL)
+#endif
+ {
- dmap->counts[dmap->qtail] = l;
+ if (buff_no != dmap->qtail)
+ printf("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail);
- if ((l != dmap->fragment_size) &&
- ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
- audio_devs[dev]->flags & NEEDS_RESTART))
- dmap->flags |= DMA_RESTART;
- else
- dmap->flags &= ~DMA_RESTART;
+ dmap->qlen++;
+ if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+ printf("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n",
+ dev, dmap->qlen, dmap->nbufs);
- dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ dmap->counts[dmap->qtail] = l;
- if (!(dmap->flags & DMA_ACTIVE))
- {
- dmap->flags |= DMA_ACTIVE;
- audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead],
- dmap->counts[dmap->qhead], 0,
- !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
- !(dmap->flags & DMA_STARTED));
- dmap->flags |= DMA_STARTED;
- }
+ if ((l != dmap->fragment_size) &&
+ ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
+ audio_devs[dev]->flags & NEEDS_RESTART))
+ dmap->flags |= DMA_RESTART;
+ else
+ dmap->flags &= ~DMA_RESTART;
- return 0;
+ dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ }
+ if (!(dmap->flags & DMA_ACTIVE)) {
+ dmap->flags |= DMA_ACTIVE;
+ audio_devs[dev]->output_block(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 0,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
+ !(dmap->flags & DMA_STARTED));
+ dmap->flags |= DMA_STARTED;
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+ return 0;
}
int
-DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
+DMAbuf_start_dma(int dev, u_long physaddr, int count, int dma_mode)
{
- int chan = audio_devs[dev]->dmachan;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
- unsigned long flags;
+ int chan;
+ struct dma_buffparms *dmap;
- /*
- * This function is not as portable as it should be.
- */
+ if (dma_mode == 1) {
+ chan = audio_devs[dev]->dmachan1;
+ dmap = audio_devs[dev]->dmap_out;
- /*
- * The count must be one less than the actual size. This is handled by
- * set_dma_addr()
- */
+ } else {
+ chan = audio_devs[dev]->dmachan2;
+ dmap = audio_devs[dev]->dmap_in;
+ }
- if (audio_devs[dev]->flags & DMA_AUTOMODE)
- { /*
- * Auto restart mode. Transfer the whole *
- * buffer
- */
-#ifdef linux
- DISABLE_INTR (flags);
- disable_dma (chan);
- clear_dma_ff (chan);
- set_dma_mode (chan, dma_mode | DMA_AUTOINIT);
- set_dma_addr (chan, dmap->raw_buf_phys[0]);
- set_dma_count (chan, dmap->bytes_in_use);
- enable_dma (chan);
- RESTORE_INTR (flags);
-#else
+ /*
+ * The count must be one less than the actual size. This is handled
+ * by set_dma_addr()
+ */
-#ifdef __386BSD__
- printk ("sound: Invalid DMA mode for device %d\n", dev);
+#ifndef PSEUDO_DMA_AUTOINIT
+ if (audio_devs[dev]->flags & DMA_AUTOMODE) {
+ /* Auto restart mode. Transfer the whole buffer */
+ isa_dmastart(B_RAW | ((dma_mode == 0) ? B_READ : B_WRITE),
+ (caddr_t) dmap->raw_buf_phys, dmap->bytes_in_use, chan);
- isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
- dmap->raw_buf_phys[0],
- dmap->bytes_in_use,
- chan);
-#else
-#if defined(GENERIC_SYSV)
-#ifndef DMAMODE_AUTO
- printk ("sound: Invalid DMA mode for device %d\n", dev);
-#endif
- dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
-#ifdef DMAMODE_AUTO
- | DMAMODE_AUTO
+ } else
#endif
- ,
- dmap->raw_buf_phys[0], dmap->bytes_in_use);
- dma_enable (chan);
-#else
-#error This routine is not valid for this OS.
+ {
+ isa_dmastart((dma_mode == 0) ? B_READ : B_WRITE,
+ (caddr_t) physaddr, count, chan);
+ }
+ return count;
+}
+
+void
+DMAbuf_init()
+{
+ int dev;
+
+ /*
+ * NOTE! This routine could be called several times.
+ * XXX is it ok to make it run only the first time ? -- lr970710
+ */
+
+ for (dev = 0; dev < num_audiodevs; dev++)
+ if (audio_devs[dev]->dmap_out == NULL) {
+ audio_devs[dev]->dmap_out =
+ audio_devs[dev]->dmap_in = &dmaps[ndmaps++];
+
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ audio_devs[dev]->dmap_in = &dmaps[ndmaps++];
+ }
+}
+
+void
+DMAbuf_outputintr(int dev, int event_type)
+{
+ /*
+ * Event types: 0 = DMA transfer done. Device still has more data in
+ * the local buffer. 1 = DMA transfer done. Device doesn't have local
+ * buffer or it's empty now. 2 = No DMA transfer but the device has
+ * now more space in it's local buffer.
+ */
+
+ u_long flags;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+ dmap->byte_counter += dmap->counts[dmap->qhead];
+#ifdef OS_DMA_INTR
+ sound_dma_intr(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
#endif
+#ifdef ALLOW_BUFFER_MAPPING
+ if (dmap->mapping_flags & DMA_MAP_MAPPED) {
+ /* mmapped access */
+
+ int p = dmap->fragment_size * dmap->qhead;
+
+ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+ dmap->qlen++; /* Yes increment it (don't decrement) */
+ dmap->flags &= ~DMA_ACTIVE;
+ dmap->counts[dmap->qhead] = dmap->fragment_size;
+
+ if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) {
+ audio_devs[dev]->output_block(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 1,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE));
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+#ifdef PSEUDO_DMA_AUTOINIT
+ else {
+ DMAbuf_start_dma(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 1);
+ }
#endif
+ dmap->flags |= DMA_ACTIVE;
+ } else
#endif
- }
- else
- {
-#ifdef linux
- DISABLE_INTR (flags);
- disable_dma (chan);
- clear_dma_ff (chan);
- set_dma_mode (chan, dma_mode);
- set_dma_addr (chan, physaddr);
- set_dma_count (chan, count);
- enable_dma (chan);
- RESTORE_INTR (flags);
-#else
-#ifdef __386BSD__
- isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
- physaddr,
- count,
- chan);
-#else
+ if (event_type != 2) {
+ if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) {
+ printf("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n",
+ dev, dmap->qlen, dmap->nbufs);
+ return;
+ }
+ isa_dmadone(0, 0, 0, audio_devs[dev]->dmachan1);
-#if defined(GENERIC_SYSV)
- dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
- physaddr, count);
- dma_enable (chan);
-#else
-#error This routine is not valid for this OS.
-#endif /* GENERIC_SYSV */
-#endif
+ dmap->qlen--;
+ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+ dmap->flags &= ~DMA_ACTIVE;
+ if (dmap->qlen) {
+ /* if (!(audio_devs[dev]->flags & NEEDS_RESTART)) */
+ {
+ audio_devs[dev]->output_block(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 1,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE));
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+#ifdef PSEUDO_DMA_AUTOINIT
+ /* else */
+ {
+ DMAbuf_start_dma(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 1);
+ }
#endif
- }
-
- return count;
-}
+ dmap->flags |= DMA_ACTIVE;
+ } else if (event_type == 1) {
+ dmap->underrun_count++;
+ if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
+ audio_devs[dev]->halt_output)
+ audio_devs[dev]->halt_output(dev);
+ else
+ audio_devs[dev]->halt_xfer(dev);
+
+ if ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
+ audio_devs[dev]->flags & NEEDS_RESTART)
+ dmap->flags |= DMA_RESTART;
+ else
+ dmap->flags &= ~DMA_RESTART;
+ }
+ } /* event_type != 2 */
+ flags = splhigh();
-long
-DMAbuf_init (long mem_start)
-{
- int dev;
+ if ((out_sleep_flag[dev].mode & WK_SLEEP)) {
+ out_sleep_flag[dev].mode = WK_WAKEUP;
+ wakeup(out_sleeper[dev]);
+ }
- /*
- * NOTE! This routine could be called several times.
- */
+ if(selinfo[dev].si_pid) {
+ selwakeup(&selinfo[dev]);
+ }
- for (dev = 0; dev < num_audiodevs; dev++)
- audio_devs[dev]->dmap = &dmaps[dev];
- return mem_start;
+ splx(flags);
}
void
-DMAbuf_outputintr (int dev, int event_type)
-{
- /*
- * Event types:
- * 0 = DMA transfer done. Device still has more data in the local
- * buffer.
- * 1 = DMA transfer done. Device doesn't have local buffer or it's
- * empty now.
- * 2 = No DMA transfer but the device has now more space in it's local
- * buffer.
- */
+DMAbuf_inputintr(int dev)
+{
+ u_long flags;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
- unsigned long flags;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ dmap->byte_counter += dmap->fragment_size;
- if (event_type != 2)
- {
- if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
- {
- printk ("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n",
- dev, dmap->qlen, dmap->nbufs);
- return;
+#ifdef OS_DMA_INTR
+ sound_dma_intr(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
+#endif
+ isa_dmadone(0, 0, 0, audio_devs[dev]->dmachan2);
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (dmap->mapping_flags & DMA_MAP_MAPPED) {
+ dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ dmap->qlen++;
+
+ if (!(audio_devs[dev]->flags & NEEDS_RESTART)) {
+ audio_devs[dev]->start_input(dev, dmap->raw_buf_phys +
+ dmap->qtail * dmap->fragment_size,
+ dmap->fragment_size, 1,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE));
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
}
+#ifdef PSEUDO_DMA_AUTOINIT
+ else {
+ DMAbuf_start_dma(dev, dmap->raw_buf_phys +
+ dmap->qtail * dmap->fragment_size,
+ dmap->counts[dmap->qtail], 0);
+ }
+#endif
- dmap->qlen--;
- dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
- dmap->flags &= ~DMA_ACTIVE;
-
- if (dmap->qlen)
+ dmap->flags |= DMA_ACTIVE;
+ } else
+#endif
+ if (dmap->qlen == (dmap->nbufs - 1)) {
+ /* printf ("Sound: Recording overrun\n"); */
+ dmap->underrun_count++;
+ if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
+ audio_devs[dev]->halt_input)
+ audio_devs[dev]->halt_input(dev);
+ else
+ audio_devs[dev]->halt_xfer(dev);
+
+ dmap->flags &= ~DMA_ACTIVE;
+ if (audio_devs[dev]->flags & DMA_AUTOMODE)
+ dmap->flags |= DMA_RESTART;
+ else
+ dmap->flags &= ~DMA_RESTART;
+ } else {
+ dmap->qlen++;
+ if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+ printf("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n",
+ dev, dmap->qlen, dmap->nbufs);
+ dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+
+ /* if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) */
{
- audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead],
- dmap->counts[dmap->qhead], 1,
- !(audio_devs[dev]->flags & DMA_AUTOMODE));
- dmap->flags |= DMA_ACTIVE;
+ audio_devs[dev]->start_input(dev, dmap->raw_buf_phys +
+ dmap->qtail * dmap->fragment_size,
+ dmap->fragment_size, 1,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE));
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
}
- else if (event_type == 1)
+#ifdef PSEUDO_DMA_AUTOINIT
+ /* else */
{
- dmap->underrun_count++;
- audio_devs[dev]->halt_xfer (dev);
- if ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
- audio_devs[dev]->flags & NEEDS_RESTART)
- dmap->flags |= DMA_RESTART;
- else
- dmap->flags &= ~DMA_RESTART;
+ DMAbuf_start_dma(dev, dmap->raw_buf_phys +
+ dmap->qtail * dmap->fragment_size,
+ dmap->counts[dmap->qtail], 0);
}
- } /* event_type != 2 */
+#endif
- DISABLE_INTR (flags);
- if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
+ dmap->flags |= DMA_ACTIVE;
+ }
+
+ flags = splhigh();
+ if ((in_sleep_flag[dev].mode & WK_SLEEP)) {
+ in_sleep_flag[dev].mode = WK_WAKEUP;
+ wakeup(in_sleeper[dev]);
}
- RESTORE_INTR (flags);
+ if (selinfo[dev].si_pid)
+ selwakeup(&selinfo[dev]);
+ splx(flags);
+}
+
+int
+DMAbuf_open_dma(int dev)
+{
+ int err;
+ u_long flags;
+ flags = splhigh();
+
+ if ((err = open_dmap(dev, OPEN_READWRITE, audio_devs[dev]->dmap_out,
+ audio_devs[dev]->dmachan1)) < 0) {
+ splx(flags);
+ return -(EBUSY);
+ }
+ dma_init_buffers(dev, audio_devs[dev]->dmap_out);
+ /* audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; */
+ audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->buffsize;
+ /* reorganize_buffers (dev, audio_devs[dev]->dmap_out); */
+
+ if (audio_devs[dev]->flags & DMA_DUPLEX) {
+ if ((err = open_dmap(dev, OPEN_READWRITE,
+ audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2)) < 0) {
+ printf("Unable to grab DMA%d for the audio driver\n",
+ audio_devs[dev]->dmachan2);
+ close_dmap(dev, audio_devs[dev]->dmap_out,
+ audio_devs[dev]->dmachan1);
+ splx(flags);
+ return -(EBUSY);
+ }
+ dma_init_buffers(dev, audio_devs[dev]->dmap_in);
+ /* audio_devs[dev]->dmap_in->flags |= DMA_ALLOC_DONE; */
+ audio_devs[dev]->dmap_in->fragment_size = audio_devs[dev]->buffsize;
+ /* reorganize_buffers (dev, audio_devs[dev]->dmap_in); */
+ } else {
+ audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out;
+ audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1;
+ }
+
+ splx(flags);
+ return 0;
}
void
-DMAbuf_inputintr (int dev)
+DMAbuf_close_dma(int dev)
{
- unsigned long flags;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ DMAbuf_reset_dma(dev);
+ close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
- if (dmap->qlen == (dmap->nbufs - 1))
- {
- printk ("Sound: Recording overrun\n");
- dmap->underrun_count++;
- audio_devs[dev]->halt_xfer (dev);
- dmap->flags &= ~DMA_ACTIVE;
- if (audio_devs[dev]->flags & DMA_AUTOMODE)
- dmap->flags |= DMA_RESTART;
- else
- dmap->flags &= ~DMA_RESTART;
- }
- else
- {
- dmap->qlen++;
- if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
- printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n",
- dev, dmap->qlen, dmap->nbufs);
- dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ close_dmap(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
- audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail],
- dmap->fragment_size, 1,
- !(audio_devs[dev]->flags & DMA_AUTOMODE));
- dmap->flags |= DMA_ACTIVE;
- }
+}
- DISABLE_INTR (flags);
- if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
- }
- RESTORE_INTR (flags);
+void
+DMAbuf_reset_dma(int dev)
+{
}
+#ifdef ALLOW_POLL
+
int
-DMAbuf_open_dma (int dev)
+DMAbuf_poll(int dev, struct fileinfo * file, int events, select_table * wait)
{
- unsigned long flags;
- int chan = audio_devs[dev]->dmachan;
+ struct dma_buffparms *dmap;
+ u_long flags;
+ int revents = 0;
+
+ dmap = audio_devs[dev]->dmap_in;
+
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (dmap->dma_mode != DMODE_INPUT) {
+ if ((audio_devs[dev]->flags & DMA_DUPLEX) && !dmap->qlen &&
+ audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT &&
+ audio_devs[dev]->go) {
+ u_long flags;
+
+ flags = splhigh();
+
+ activate_recording(dev, dmap);
+ splx(flags);
+
+ }
+ return 0;
+ }
+ if (!dmap->qlen) {
+ flags = splhigh();
+
+ selrecord(wait, &selinfo[dev]);
+
+ splx(flags);
+
+ return 0;
+ } else
+ revents |= events & (POLLIN | POLLRDNORM);
- if (ALLOC_DMA_CHN (chan))
- {
- printk ("Unable to grab DMA%d for the audio driver\n", chan);
- return RET_ERROR (EBUSY);
}
- DISABLE_INTR (flags);
-#ifdef linux
- disable_dma (chan);
- clear_dma_ff (chan);
-#endif
- RESTORE_INTR (flags);
+ if (events & (POLLOUT | POLLWRNORM)) {
+
+ dmap = audio_devs[dev]->dmap_out;
+ if (dmap->dma_mode == DMODE_INPUT)
+ return 0;
+
+ if (dmap->dma_mode == DMODE_NONE)
+ return ( events & (POLLOUT | POLLWRNORM));
+
+ if (dmap->mapping_flags & DMA_MAP_MAPPED) {
+
+ if(dmap->qlen)
+ return 1;
+ flags = splhigh();
+ selrecord(wait, &selinfo[dev]);
+
+ splx(flags);
+
+ return 0;
+
+ }
+ if (!space_in_queue(dev)) {
+ flags = splhigh();
+ selrecord(wait, &selinfo[dev]);
+ splx(flags);
- return 0;
-}
+ } else
+ revents |= events & (POLLOUT | POLLWRNORM);
-void
-DMAbuf_close_dma (int dev)
-{
- int chan = audio_devs[dev]->dmachan;
- DMAbuf_reset_dma (chan);
- RELEASE_DMA_CHN (chan);
+ }
+
+ return (revents);
}
-void
-DMAbuf_reset_dma (int chan)
+
+#ifdef amancio
+int
+DMAbuf_select(int dev, struct fileinfo * file, int sel_type, select_table * wait)
{
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+ struct dma_buffparms *dmapin = audio_devs[dev]->dmap_in;
+ u_long flags;
+
+ switch (sel_type) {
+ case FREAD:
+ if (dmapin->dma_mode != DMODE_INPUT)
+ return 0;
+
+ if (!dmap->qlen) {
+ flags = splhigh();
+ selrecord(wait, &selinfo[dev]);
+ splx(flags);
+
+ return 0;
+ }
+ return 1;
+ break;
+
+ case FWRITE:
+ if (dmap->dma_mode == DMODE_INPUT)
+ return 0;
+
+ if (dmap->dma_mode == DMODE_NONE)
+ return 1;
+
+ if (!space_in_queue(dev)) {
+ flags = splhigh();
+
+ selrecord(wait, &selinfo[dev]);
+ splx(flags);
+
+ return 0;
+ }
+ return 1;
+ break;
+
+ }
+
+ return 0;
}
-/*
- * The sound_mem_init() is called by mem_init() immediately after mem_map is
- * initialized and before free_page_list is created.
- *
- * This routine allocates DMA buffers at the end of available physical memory (
- * <16M) and marks pages reserved at mem_map.
- */
+#endif /* ALLOW_POLL */
+#endif
-#else
+#else /* CONFIG_AUDIO */
/*
* Stub versions if audio services not included
*/
int
-DMAbuf_open (int dev, int mode)
+DMAbuf_open(int dev, int mode)
{
- return RET_ERROR (ENXIO);
+ return -(ENXIO);
}
int
-DMAbuf_release (int dev, int mode)
+DMAbuf_release(int dev, int mode)
{
- return 0;
+ return 0;
}
int
-DMAbuf_getwrbuffer (int dev, char **buf, int *size)
+DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_getrdbuffer (int dev, char **buf, int *len)
+DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_rmchars (int dev, int buff_no, int c)
+DMAbuf_rmchars(int dev, int buff_no, int c)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_start_output (int dev, int buff_no, int l)
+DMAbuf_start_output(int dev, int buff_no, int l)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+DMAbuf_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
-long
-DMAbuf_init (long mem_start)
+void
+DMAbuf_init()
{
- return mem_start;
}
int
-DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
+DMAbuf_start_dma(int dev, u_long physaddr, int count, int dma_mode)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_open_dma (int chan)
+DMAbuf_open_dma(int dev)
{
- return RET_ERROR (ENXIO);
+ return -(ENXIO);
}
void
-DMAbuf_close_dma (int chan)
+DMAbuf_close_dma(int dev)
{
- return;
+ return;
}
void
-DMAbuf_reset_dma (int chan)
+DMAbuf_reset_dma(int dev)
{
- return;
+ return;
}
void
-DMAbuf_inputintr (int dev)
+DMAbuf_inputintr(int dev)
{
- return;
+ return;
}
void
-DMAbuf_outputintr (int dev, int underrun_flag)
+DMAbuf_outputintr(int dev, int underrun_flag)
{
- return;
+ return;
}
-
-#endif
-
-#endif
+#endif /* CONFIG_AUDIO */