patch-1.3.34 linux/drivers/sound/dmabuf.c
Next file: linux/drivers/sound/gus_card.c
Previous file: linux/drivers/sound/dev_table.h
Back to the patch index
Back to the overall index
- Lines: 1790
- Date:
Wed Oct 11 07:55:39 1995
- Orig file:
v1.3.33/linux/drivers/sound/dmabuf.c
- Orig date:
Mon Sep 18 14:54:04 1995
diff -u --recursive --new-file v1.3.33/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
@@ -31,15 +31,24 @@
#ifdef CONFIGURE_SOUNDCARD
-#include "sound_calls.h"
-
#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)
-static int space_in_queue (int dev);
+static struct wait_queue *in_sleeper[MAX_AUDIO_DEV] =
+{NULL};
+static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] =
+{
+ {0}};
+static struct wait_queue *out_sleeper[MAX_AUDIO_DEV] =
+{NULL};
+static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] =
+{
+ {0}};
+
+static int ndmaps = 0;
-DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_DEV]);
+#define MAX_DMAP (MAX_AUDIO_DEV*2)
-static struct dma_buffparms dmaps[MAX_AUDIO_DEV] =
+static struct dma_buffparms dmaps[MAX_DMAP] =
{
{0}}; /*
@@ -47,18 +56,21 @@
* such a large array.
* Needs dynamic run-time alloction.
*/
+static int space_in_queue (int dev);
+
+static void dma_reset_output (int dev);
+static void dma_reset_input (int dev);
static void
-reorganize_buffers (int dev)
+reorganize_buffers (int dev, struct dma_buffparms *dmap)
{
/*
* This routine breaks the physical device buffers to logical ones.
*/
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
struct audio_operations *dsp_dev = audio_devs[dev];
- unsigned i, p, n;
+ unsigned i, n;
unsigned sr, nc, sz, bsz;
if (dmap->fragment_size == 0)
@@ -68,6 +80,11 @@
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 = 0x80;
+ else
+ dmap->neutral_byte = 0x00;
+
if (sr < 1 || nc < 1 || sz < 1)
{
printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n",
@@ -77,10 +94,10 @@
sz = 8;
}
- sz /= 8; /* #bits -> #bytes */
-
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
@@ -91,19 +108,16 @@
while (bsz > sz)
bsz /= 2;
- if (dsp_dev->buffcount == 1 && bsz == dsp_dev->buffsize)
+ 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;
- bsz /= dmap->subdivision;
-
- if (bsz < 64)
- bsz = 4096; /* Just a sanity check */
-
- while ((dsp_dev->buffsize * dsp_dev->buffcount) / bsz > MAX_SUB_BUFFERS)
- bsz *= 2;
+ if (bsz < 16)
+ bsz = 16; /* Just a sanity check */
dmap->fragment_size = bsz;
}
@@ -113,33 +127,18 @@
* 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;
+ if (dmap->fragment_size > (audio_devs[dev]->buffsize / 2))
+ dmap->fragment_size = (audio_devs[dev]->buffsize / 2);
bsz = dmap->fragment_size;
}
- /*
- * Now computing addresses for the logical buffers
- */
-
- n = 0;
- for (i = 0; i < dmap->raw_count &&
- n < dmap->max_fragments &&
- n < MAX_SUB_BUFFERS; i++)
- {
- p = 0;
-
- 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++;
- }
- }
+ bsz &= ~0x03; /* Force size which is multiple of 4 bytes */
+ n = dsp_dev->buffsize / bsz;
+ if (n > MAX_SUB_BUFFERS)
+ n = MAX_SUB_BUFFERS;
+ if (n > dmap->max_fragments)
+ n = dmap->max_fragments;
dmap->nbufs = n;
dmap->bytes_in_use = n * bsz;
@@ -152,61 +151,127 @@
}
static void
-dma_init_buffers (int dev)
+dma_init_buffers (int dev, struct dma_buffparms *dmap)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap = &dmaps[dev];
-
- RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
+ 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;
+ };
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;
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;
+
+ {
+ int err;
+
+ if ((err = sound_alloc_dmap (dev, dmap, chan)) < 0)
+ return err;
+ }
+
+ if (dmap->raw_buf == NULL)
+ return -ENOSPC; /* Memory allocation failed during boot */
+
+ if (sound_open_dma (chan, audio_devs[dev]->name))
+ {
+ printk ("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;
+
+ dma_init_buffers (dev, dmap);
+
+ return 0;
+}
+
+static void
+close_dmap (int dev, struct dma_buffparms *dmap, int chan)
+{
+ sound_close_dma (chan);
+
+ if (dmap->flags & DMA_BUSY)
+ dmap->dma_mode = DMODE_NONE;
+ dmap->flags &= ~DMA_BUSY;
+
+ sound_free_dmap (dev, dmap);
}
int
DMAbuf_open (int dev, int mode)
{
int retval;
- struct dma_buffparms *dmap = NULL;
+ 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);
+ return -ENXIO;
}
if (!audio_devs[dev])
{
printk ("PCM device %d not initialized\n", dev);
- return RET_ERROR (ENXIO);
+ return -ENXIO;
}
- dmap = audio_devs[dev]->dmap = &dmaps[dev];
-
- if (dmap->flags & DMA_BUSY)
- return RET_ERROR (EBUSY);
-
-#ifdef USE_RUNTIME_DMAMEM
- dmap->raw_buf[0] = NULL;
- sound_dma_malloc (dev);
-#endif
-
- if (dmap->raw_buf[0] == NULL)
- return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */
+ 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->open_mode = mode;
- dmap->subdivision = dmap->underrun_count = 0;
- dmap->fragment_size = 0;
- dmap->max_fragments = 65536; /* Just a large value */
+ dmap_out = audio_devs[dev]->dmap_out;
+ dmap_in = audio_devs[dev]->dmap_in;
- 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);
+ 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 (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;
+
+ 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;
}
@@ -214,20 +279,53 @@
static void
dma_reset (int dev)
{
- int retval;
unsigned long flags;
- DISABLE_INTR (flags);
-
+ save_flags (flags);
+ cli ();
audio_devs[dev]->reset (dev);
- audio_devs[dev]->close (dev);
+ restore_flags (flags);
+
+ dma_reset_output (dev);
+
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ dma_reset_input (dev);
+}
+
+static void
+dma_reset_output (int dev)
+{
+ unsigned long flags;
- 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);
+ save_flags (flags);
+ cli ();
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
+ !audio_devs[dev]->halt_output)
+ audio_devs[dev]->reset (dev);
+ else
+ audio_devs[dev]->halt_output (dev);
+ restore_flags (flags);
- dma_init_buffers (dev);
- reorganize_buffers (dev);
+ dma_init_buffers (dev, audio_devs[dev]->dmap_out);
+ reorganize_buffers (dev, audio_devs[dev]->dmap_out);
+}
+
+static void
+dma_reset_input (int dev)
+{
+ unsigned long flags;
+
+ save_flags (flags);
+ cli ();
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
+ !audio_devs[dev]->halt_input)
+ audio_devs[dev]->reset (dev);
+ else
+ audio_devs[dev]->halt_input (dev);
+ restore_flags (flags);
+
+ dma_init_buffers (dev, audio_devs[dev]->dmap_in);
+ reorganize_buffers (dev, audio_devs[dev]->dmap_in);
}
static int
@@ -235,39 +333,80 @@
{
unsigned long flags;
- if (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT)
+ 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)
{
- DISABLE_INTR (flags);
+ save_flags (flags);
+ cli ();
- while (!PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])
- && audio_devs[dev]->dmap->qlen)
+ while (!((current->signal & ~current->blocked))
+ && audio_devs[dev]->dmap_out->qlen)
{
- DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ);
- if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
+
+ {
+ unsigned long tl;
+
+ if (10 * HZ)
+ tl = current->timeout = jiffies + (10 * HZ);
+ else
+ tl = 0xffffffff;
+ out_sleep_flag[dev].mode = WK_SLEEP;
+ interruptible_sleep_on (&out_sleeper[dev]);
+ if (!(out_sleep_flag[dev].mode & WK_WAKEUP))
+ {
+ if (current->signal & ~current->blocked)
+ out_sleep_flag[dev].aborting = 1;
+ else if (jiffies >= tl)
+ out_sleep_flag[dev].mode |= WK_TIMEOUT;
+ }
+ out_sleep_flag[dev].mode &= ~WK_SLEEP;
+ };
+ if ((out_sleep_flag[dev].mode & WK_TIMEOUT))
{
- RESTORE_INTR (flags);
- return audio_devs[dev]->dmap->qlen;
+ restore_flags (flags);
+ return audio_devs[dev]->dmap_out->qlen;
}
}
- RESTORE_INTR (flags);
+ restore_flags (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.
*/
- DISABLE_INTR (flags);
+ save_flags (flags);
+ cli ();
if (audio_devs[dev]->local_qlen) /* Device has hidden buffers */
{
- while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
+ while (!(((current->signal & ~current->blocked)))
&& audio_devs[dev]->local_qlen (dev))
{
- DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ);
+
+ {
+ unsigned long tl;
+
+ if (HZ)
+ tl = current->timeout = jiffies + (HZ);
+ else
+ tl = 0xffffffff;
+ out_sleep_flag[dev].mode = WK_SLEEP;
+ interruptible_sleep_on (&out_sleeper[dev]);
+ if (!(out_sleep_flag[dev].mode & WK_WAKEUP))
+ {
+ if (current->signal & ~current->blocked)
+ out_sleep_flag[dev].aborting = 1;
+ else if (jiffies >= tl)
+ out_sleep_flag[dev].mode |= WK_TIMEOUT;
+ }
+ out_sleep_flag[dev].mode &= ~WK_SLEEP;
+ };
}
}
- RESTORE_INTR (flags);
+ restore_flags (flags);
}
- return audio_devs[dev]->dmap->qlen;
+ return audio_devs[dev]->dmap_out->qlen;
}
int
@@ -275,25 +414,75 @@
{
unsigned long flags;
- if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
- && (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT))
+ if (!(((current->signal & ~current->blocked)))
+ && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT))
{
dma_sync (dev);
}
-#ifdef USE_RUNTIME_DMAMEM
- sound_dma_free (dev);
-#endif
-
- DISABLE_INTR (flags);
+ save_flags (flags);
+ cli ();
audio_devs[dev]->reset (dev);
audio_devs[dev]->close (dev);
- audio_devs[dev]->dmap->dma_mode = DMODE_NONE;
- audio_devs[dev]->dmap->flags &= ~DMA_BUSY;
- RESTORE_INTR (flags);
+ close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
+
+ 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;
+
+ restore_flags (flags);
+
+ return 0;
+}
+
+static int
+activate_recording (int dev, struct dma_buffparms *dmap)
+{
+ if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT))
+ return 0;
+
+ 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)
+ {
+ int err;
+
+ 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;
}
@@ -302,73 +491,79 @@
{
unsigned long flags;
int err = EIO;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
- DISABLE_INTR (flags);
- if (!dmap->qlen)
+ save_flags (flags);
+ cli ();
+ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
{
- if (dmap->flags & DMA_RESTART)
- {
- dma_reset (dev);
- dmap->flags &= ~DMA_RESTART;
- }
+ printk ("Sound: Can't read from mmapped device (1)\n");
+ return -EINVAL;
+ }
+ else if (!dmap->qlen)
+ {
+ int timeout;
- if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */
+ if ((err = activate_recording (dev, dmap)) < 0)
{
- dma_sync (dev);
- dma_reset (dev);
- dmap->dma_mode = DMODE_NONE;
+ restore_flags (flags);
+ return err;
}
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
+ /* Wait for the next block */
- if (!dmap->dma_mode)
+ if (dontblock)
{
- int err;
-
- 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;
+ restore_flags (flags);
+ return -EAGAIN;
}
- if (!(dmap->flags & DMA_ACTIVE))
+ if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) &
+ audio_devs[dev]->go)
{
- 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;
+ restore_flags (flags);
+ return -EAGAIN;
}
- if (dontblock)
- {
- RESTORE_INTR (flags);
- return RET_ERROR (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]))
+ {
+ unsigned long tl;
+
+ if (timeout)
+ tl = current->timeout = jiffies + (timeout);
+ else
+ tl = 0xffffffff;
+ in_sleep_flag[dev].mode = WK_SLEEP;
+ interruptible_sleep_on (&in_sleeper[dev]);
+ if (!(in_sleep_flag[dev].mode & WK_WAKEUP))
+ {
+ if (current->signal & ~current->blocked)
+ in_sleep_flag[dev].aborting = 1;
+ else if (jiffies >= tl)
+ in_sleep_flag[dev].mode |= WK_TIMEOUT;
+ }
+ in_sleep_flag[dev].mode &= ~WK_SLEEP;
+ };
+ if ((in_sleep_flag[dev].mode & WK_TIMEOUT))
{
- printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
+ printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n");
err = EIO;
- SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
+ in_sleep_flag[dev].aborting = 1;
}
else
err = EINTR;
}
- RESTORE_INTR (flags);
+ restore_flags (flags);
if (!dmap->qlen)
- return RET_ERROR (err);
+ return -err;
- *buf = &dmap->buf[dmap->qhead][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;
@@ -377,11 +572,16 @@
int
DMAbuf_rmchars (int dev, int buff_no, int c)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
int p = dmap->counts[dmap->qhead] + c;
- if (p >= dmap->fragment_size)
+ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
+ {
+ printk ("Sound: Can't read from mmapped device (2)\n");
+ return -EINVAL;
+ }
+ else if (p >= dmap->fragment_size)
{ /* This buffer is completely empty */
dmap->counts[dmap->qhead] = 0;
if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
@@ -396,10 +596,105 @@
return 0;
}
+static int
+dma_subdivide (int dev, struct dma_buffparms *dmap, ioctl_arg arg, int fact)
+{
+ if (fact == 0)
+ {
+ fact = dmap->subdivision;
+ if (fact == 0)
+ fact = 1;
+ return snd_ioctl_return ((int *) arg, fact);
+ }
+
+ if (dmap->subdivision != 0 ||
+ dmap->fragment_size) /* Loo late to change */
+ return -EINVAL;
+
+ if (fact > MAX_REALTIME_FACTOR)
+ return -EINVAL;
+
+ if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
+ return -EINVAL;
+
+ dmap->subdivision = fact;
+ return snd_ioctl_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 (bytes < 4 || bytes > 17) /* <16 || > 128k */
+ return -EINVAL;
+
+ if (count < 2)
+ return -EINVAL;
+
+ 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 snd_ioctl_return ((int *) arg, bytes | (count << 16));
+}
+
+static int
+get_buffer_pointer (int dev, int chan, struct dma_buffparms *dmap)
+{
+ int pos;
+ unsigned long flags;
+
+ save_flags (flags);
+ cli ();
+ if (!(dmap->flags & DMA_ACTIVE))
+ pos = 0;
+ else
+ {
+ clear_dma_ff (chan);
+ disable_dma (chan);
+ pos = get_dma_residue (chan);
+ enable_dma (chan);
+ }
+ restore_flags (flags);
+ /* printk ("%04x ", pos); */
+
+ if (audio_devs[dev]->flags & DMA_AUTOMODE)
+ return dmap->bytes_in_use - pos;
+ else
+ {
+ pos = dmap->fragment_size - pos;
+ if (pos < 0)
+ return 0;
+ return pos;
+ }
+}
+
int
-DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+DMAbuf_ioctl (int dev, unsigned 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)
{
@@ -415,88 +710,64 @@
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);
+ return snd_ioctl_return ((int *) arg, dmap_out->fragment_size);
break;
case SNDCTL_DSP_SUBDIVIDE:
{
- int fact = IOCTL_IN (arg);
-
- if (fact == 0)
- {
- fact = dmap->subdivision;
- if (fact == 0)
- fact = 1;
- return IOCTL_OUT (arg, fact);
- }
+ int fact = get_fs_long ((long *) arg);
+ int ret;
- if (dmap->subdivision != 0 ||
- dmap->fragment_size) /* Loo late to change */
- return RET_ERROR (EINVAL);
+ ret = dma_subdivide (dev, dmap_out, arg, fact);
+ if (ret < 0)
+ return ret;
- if (fact > MAX_REALTIME_FACTOR)
- return RET_ERROR (EINVAL);
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ ret = dma_subdivide (dev, dmap_in, arg, fact);
- if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
- return RET_ERROR (EINVAL);
-
- dmap->subdivision = fact;
- return IOCTL_OUT (arg, fact);
+ return ret;
}
break;
case SNDCTL_DSP_SETFRAGMENT:
{
- int fact = IOCTL_IN (arg);
- int bytes, count;
-
- if (fact == 0)
- return RET_ERROR (EIO);
-
- if (dmap->subdivision != 0 ||
- dmap->fragment_size) /* Loo late to change */
- return RET_ERROR (EINVAL);
-
- bytes = fact & 0xffff;
- count = (fact >> 16) & 0xffff;
-
- if (count == 0)
- count = MAX_SUB_BUFFERS;
-
- if (bytes < 7 || bytes > 17) /* <64 || > 128k */
- return RET_ERROR (EINVAL);
+ int fact = get_fs_long ((long *) arg);
+ int ret;
- if (count < 2)
- return RET_ERROR (EINVAL);
+ ret = dma_set_fragment (dev, dmap_out, arg, fact);
+ if (ret < 0)
+ return ret;
- dmap->fragment_size = (1 << bytes);
- dmap->max_fragments = count;
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ ret = dma_set_fragment (dev, dmap_in, arg, fact);
- 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 IOCTL_OUT (arg, bytes | (count << 16));
+ return ret;
}
break;
case SNDCTL_DSP_GETISPACE:
case SNDCTL_DSP_GETOSPACE:
if (!local)
- return RET_ERROR (EINVAL);
+ return -EINVAL;
else
{
+ struct dma_buffparms *dmap = dmap_out;
+
audio_buf_info *info = (audio_buf_info *) arg;
+ if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
+ dmap = dmap_in;
+
+ if (dmap->mapping_flags & DMA_MAP_MAPPED)
+ return -EINVAL;
+
if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
+ reorganize_buffers (dev, dmap);
+
+ info->fragstotal = dmap->nbufs;
if (cmd == SNDCTL_DSP_GETISPACE)
info->fragments = dmap->qlen;
@@ -533,17 +804,127 @@
}
return 0;
+ case SNDCTL_DSP_SETTRIGGER:
+ {
+ unsigned long flags;
+
+ int bits = get_fs_long ((long *) 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))
+ {
+ printk ("Sound: Device doesn't have full duplex capability\n");
+ return -EINVAL;
+ }
+
+ save_flags (flags);
+ cli ();
+ 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);
+ }
+
+ 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);
+
+ dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
+ DMAbuf_start_output (dev, 0, dmap_out->fragment_size);
+ }
+
+ audio_devs[dev]->enable_bits = bits;
+ if (changed && audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger (dev, bits * audio_devs[dev]->go);
+ restore_flags (flags);
+ }
+ case SNDCTL_DSP_GETTRIGGER:
+ return snd_ioctl_return ((int *) arg, audio_devs[dev]->enable_bits);
+ break;
+
+ case SNDCTL_DSP_GETIPTR:
+ {
+ count_info info;
+ unsigned long flags;
+
+ save_flags (flags);
+ cli ();
+ 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;
+ memcpy_tofs (&(((char *) arg)[0]), ((char *) &info), (sizeof (info)));
+
+ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
+ audio_devs[dev]->dmap_in->qlen = 0; /* Acknowledge interrupts */
+ restore_flags (flags);
+ return 0;
+ }
+ break;
+
+ case SNDCTL_DSP_GETOPTR:
+ {
+ count_info info;
+ unsigned long flags;
+
+ save_flags (flags);
+ cli ();
+ 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;
+ memcpy_tofs (&(((char *) arg)[0]), ((char *) &info), (sizeof (info)));
+
+ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
+ audio_devs[dev]->dmap_out->qlen = 0; /* Acknowledge interrupts */
+ restore_flags (flags);
+ return 0;
+ }
+ break;
+
+
default:
return audio_devs[dev]->ioctl (dev, cmd, arg, local);
}
}
+/*
+ * DMAbuf_start_devices() is called by the /dev/music driver to start
+ * one or more audio devices at desired moment.
+ */
+
+void
+DMAbuf_start_devices (unsigned 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;
+ }
+}
+
static int
space_in_queue (int dev)
{
int len, max, tmp;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
if (dmap->qlen >= dmap->nbufs) /* No space at all */
return 0;
@@ -576,7 +957,13 @@
{
unsigned long flags;
int abort, err = EIO;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+
+ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
+ {
+ printk ("Sound: Can't write to mmapped device (3)\n");
+ return -EINVAL;
+ }
if (dmap->dma_mode == DMODE_INPUT) /* Direction change */
{
@@ -586,13 +973,13 @@
else if (dmap->flags & DMA_RESTART) /* Restart buffering */
{
dma_sync (dev);
- dma_reset (dev);
+ dma_reset_output (dev);
}
dmap->flags &= ~DMA_RESTART;
if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
+ reorganize_buffers (dev, dmap);
if (!dmap->dma_mode)
{
@@ -604,41 +991,76 @@
return err;
}
-
- if (dontblock)
- return RET_ERROR (EAGAIN);
-
- DISABLE_INTR (flags);
+ save_flags (flags);
+ cli ();
abort = 0;
while (!space_in_queue (dev) &&
!abort)
{
+ int timeout;
+
+ if (dontblock)
+ {
+ restore_flags (flags);
+ return -EAGAIN;
+ }
+
+ if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT) &&
+ audio_devs[dev]->go)
+ {
+ restore_flags (flags);
+ return -EAGAIN;
+ }
+
/*
* 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]))
+ if (!audio_devs[dev]->go)
+ timeout = 0;
+ else
+ timeout = 2 * HZ;
+
+
+ {
+ unsigned long tl;
+
+ if (timeout)
+ tl = current->timeout = jiffies + (timeout);
+ else
+ tl = 0xffffffff;
+ out_sleep_flag[dev].mode = WK_SLEEP;
+ interruptible_sleep_on (&out_sleeper[dev]);
+ if (!(out_sleep_flag[dev].mode & WK_WAKEUP))
+ {
+ if (current->signal & ~current->blocked)
+ out_sleep_flag[dev].aborting = 1;
+ else if (jiffies >= tl)
+ out_sleep_flag[dev].mode |= WK_TIMEOUT;
+ }
+ out_sleep_flag[dev].mode &= ~WK_SLEEP;
+ };
+ if ((out_sleep_flag[dev].mode & WK_TIMEOUT))
{
- printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
+ printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
err = EIO;
abort = 1;
- SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
+ out_sleep_flag[dev].aborting = 1;
}
- else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
+ else if (((current->signal & ~current->blocked)))
{
err = EINTR;
abort = 1;
}
}
- RESTORE_INTR (flags);
+ restore_flags (flags);
if (!space_in_queue (dev))
{
- return RET_ERROR (err); /* Caught a signal ? */
+ return -err; /* Caught a signal ? */
}
- *buf = dmap->buf[dmap->qtail];
+ *buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;
*size = dmap->fragment_size;
dmap->counts[dmap->qtail] = 0;
@@ -648,35 +1070,54 @@
int
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);
-
- dmap->counts[dmap->qtail] = l;
-
- if ((l != dmap->fragment_size) &&
- ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
- audio_devs[dev]->flags & NEEDS_RESTART))
- dmap->flags |= DMA_RESTART;
+ 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
- dmap->flags &= ~DMA_RESTART;
+ {
+
+ if (buff_no != dmap->qtail)
+ printk ("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail);
+
+ 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);
+
+ dmap->counts[dmap->qtail] = l;
- dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ 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->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ }
if (!(dmap->flags & DMA_ACTIVE))
{
dmap->flags |= DMA_ACTIVE;
- audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead],
+ 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;
@@ -685,13 +1126,20 @@
int
DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
{
- int chan = audio_devs[dev]->dmachan;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ int chan;
+ struct dma_buffparms *dmap;
unsigned long flags;
- /*
- * This function is not as portable as it should be.
- */
+ if (dma_mode == DMA_MODE_WRITE)
+ {
+ chan = audio_devs[dev]->dmachan1;
+ dmap = audio_devs[dev]->dmap_out;
+ }
+ else
+ {
+ chan = audio_devs[dev]->dmachan2;
+ dmap = audio_devs[dev]->dmap_in;
+ }
/*
* The count must be one less than the actual size. This is handled by
@@ -703,89 +1151,27 @@
* Auto restart mode. Transfer the whole *
* buffer
*/
-#ifdef linux
- DISABLE_INTR (flags);
+ save_flags (flags);
+ cli ();
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_addr (chan, dmap->raw_buf_phys);
set_dma_count (chan, dmap->bytes_in_use);
enable_dma (chan);
- RESTORE_INTR (flags);
-#else
-
-#ifdef __386BSD__
- printk ("sound: Invalid DMA mode for device %d\n", dev);
-
- 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
-#if defined(SVR42)
-
- /*
- ** send full count to snd_dma_prog, it will take care of subtracting
- ** one if it is required.
- */
- snd_dma_prog (chan, dmap->raw_buf_phys[0], dmap->bytes_in_use,
- dma_mode, TRUE);
-
-#else /* !SVR42 */
- dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
-#ifdef DMAMODE_AUTO
- | DMAMODE_AUTO
-#endif
- ,
- dmap->raw_buf_phys[0], dmap->bytes_in_use - 1);
- dma_enable (chan);
-#endif /* ! SVR42 */
-#else
-#error This routine is not valid for this OS.
-#endif
-#endif
-
-#endif
+ restore_flags (flags);
}
else
{
-#ifdef linux
- DISABLE_INTR (flags);
+ save_flags (flags);
+ cli ();
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 defined(GENERIC_SYSV)
-#if defined(SVR42)
-
- snd_dma_prog (chan, physaddr, count, dma_mode, FALSE);
-
-#else /* ! SVR42 */
- dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
- physaddr, count);
- dma_enable (chan);
-#endif /* SVR42 */
-#else
-#error This routine is not valid for this OS.
-#endif /* GENERIC_SYSV */
-#endif
-
-#endif
+ restore_flags (flags);
}
return count;
@@ -796,16 +1182,22 @@
{
int dev;
-#if defined(SVR42)
- snd_dma_init ();
-#endif /* SVR42 */
/*
* NOTE! This routine could be called several times.
*/
for (dev = 0; dev < num_audiodevs; dev++)
- audio_devs[dev]->dmap = &dmaps[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++];
+ }
return mem_start;
}
@@ -823,13 +1215,39 @@
*/
unsigned long flags;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-#if defined(SVR42)
- snd_dma_intr (audio_devs[dev]->dmachan);
-#endif /* SVR42 */
+ dmap->byte_counter += dmap->counts[dmap->qhead];
+
+
+ if (dmap->mapping_flags & DMA_MAP_MAPPED)
+ {
+ /* mmapped access */
- if (event_type != 2)
+ int p = dmap->fragment_size * dmap->qhead;
+
+ memset (dmap->raw_buf + p,
+ dmap->neutral_byte,
+ dmap->fragment_size);
+
+ 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);
+ }
+ dmap->flags |= DMA_ACTIVE;
+ }
+ else if (event_type != 2)
{
if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
{
@@ -844,15 +1262,27 @@
if (dmap->qlen)
{
- audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead],
- dmap->counts[dmap->qhead], 1,
+ 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);
+ }
dmap->flags |= DMA_ACTIVE;
}
else if (event_type == 1)
{
dmap->underrun_count++;
- audio_devs[dev]->halt_xfer (dev);
+ 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;
@@ -861,29 +1291,55 @@
}
} /* event_type != 2 */
- DISABLE_INTR (flags);
- if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
+ save_flags (flags);
+ cli ();
+ if ((out_sleep_flag[dev].mode & WK_SLEEP))
{
- WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
+ {
+ out_sleep_flag[dev].mode = WK_WAKEUP;
+ wake_up (&out_sleeper[dev]);
+ };
}
- RESTORE_INTR (flags);
+ restore_flags (flags);
}
void
DMAbuf_inputintr (int dev)
{
unsigned long flags;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
-#if defined(SVR42)
- snd_dma_intr (audio_devs[dev]->dmachan);
-#endif /* SVR42 */
+ dmap->byte_counter += dmap->fragment_size;
- if (dmap->qlen == (dmap->nbufs - 1))
+
+ if (dmap->mapping_flags & DMA_MAP_MAPPED)
+ {
+ dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ dmap->qlen++;
+
+ if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
+ {
+ 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);
+ }
+
+ dmap->flags |= DMA_ACTIVE;
+ }
+ else if (dmap->qlen == (dmap->nbufs - 1))
{
printk ("Sound: Recording overrun\n");
dmap->underrun_count++;
- audio_devs[dev]->halt_xfer (dev);
+ 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;
@@ -898,38 +1354,74 @@
dev, dmap->qlen, dmap->nbufs);
dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
- audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail],
- dmap->fragment_size, 1,
+ if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
+ {
+ 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);
+ }
+
dmap->flags |= DMA_ACTIVE;
}
- DISABLE_INTR (flags);
- if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
+ save_flags (flags);
+ cli ();
+ if ((in_sleep_flag[dev].mode & WK_SLEEP))
{
- WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
+ {
+ in_sleep_flag[dev].mode = WK_WAKEUP;
+ wake_up (&in_sleeper[dev]);
+ };
}
- RESTORE_INTR (flags);
+ restore_flags (flags);
}
int
DMAbuf_open_dma (int dev)
{
+ int chan = audio_devs[dev]->dmachan1;
+ int err;
unsigned long flags;
- int chan = audio_devs[dev]->dmachan;
- if (ALLOC_DMA_CHN (chan, audio_devs[dev]->name))
+ if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1)) < 0)
{
- printk ("Unable to grab DMA%d for the audio driver\n", chan);
- return RET_ERROR (EBUSY);
+ 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); */
- DISABLE_INTR (flags);
-#ifdef linux
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ {
+ if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2)) < 0)
+ {
+ printk ("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);
+ 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;
+ }
+
+
+ save_flags (flags);
+ cli ();
disable_dma (chan);
clear_dma_ff (chan);
-#endif
- RESTORE_INTR (flags);
+ restore_flags (flags);
return 0;
}
@@ -937,48 +1429,60 @@
void
DMAbuf_close_dma (int dev)
{
- int chan = audio_devs[dev]->dmachan;
-
DMAbuf_reset_dma (dev);
- RELEASE_DMA_CHN (chan);
+ close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
+
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
+
}
void
DMAbuf_reset_dma (int dev)
{
-#if 0
- int chan = audio_devs[dev]->dmachan;
-
- disable_dma (chan);
-#endif
}
-#ifdef ALLOW_SELECT
int
DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ struct dma_buffparms *dmap;
unsigned long flags;
switch (sel_type)
{
case SEL_IN:
+ dmap = audio_devs[dev]->dmap_in;
if (dmap->dma_mode != DMODE_INPUT)
- return 0;
+ {
+ if ((audio_devs[dev]->flags & DMA_DUPLEX) && !dmap->qlen &&
+ audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT &&
+ audio_devs[dev]->go)
+ {
+ unsigned long flags;
+
+ save_flags (flags);
+ cli ();
+ activate_recording (dev, dmap);
+ restore_flags (flags);
+ }
+ return 0;
+ }
if (!dmap->qlen)
{
- DISABLE_INTR (flags);
- dev_sleep_flag[dev].mode = WK_SLEEP;
- select_wait (&dev_sleeper[dev], wait);
- RESTORE_INTR (flags);
+ save_flags (flags);
+ cli ();
+ in_sleep_flag[dev].mode = WK_SLEEP;
+ select_wait (&in_sleeper[dev], wait);
+ restore_flags (flags);
return 0;
}
return 1;
break;
case SEL_OUT:
+ dmap = audio_devs[dev]->dmap_out;
if (dmap->dma_mode == DMODE_INPUT)
{
return 0;
@@ -991,10 +1495,11 @@
if (!space_in_queue (dev))
{
- DISABLE_INTR (flags);
- dev_sleep_flag[dev].mode = WK_SLEEP;
- select_wait (&dev_sleeper[dev], wait);
- RESTORE_INTR (flags);
+ save_flags (flags);
+ cli ();
+ out_sleep_flag[dev].mode = WK_SLEEP;
+ select_wait (&out_sleeper[dev], wait);
+ restore_flags (flags);
return 0;
}
return 1;
@@ -1007,7 +1512,6 @@
return 0;
}
-#endif /* ALLOW_SELECT */
#else /* EXCLUDE_AUDIO */
/*
@@ -1017,7 +1521,7 @@
int
DMAbuf_open (int dev, int mode)
{
- return RET_ERROR (ENXIO);
+ return -ENXIO;
}
int
@@ -1029,31 +1533,31 @@
int
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, int dontblock)
{
- return RET_ERROR (EIO);
+ return -EIO;
}
int
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)
{
- return RET_ERROR (EIO);
+ return -EIO;
}
int
-DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+DMAbuf_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local)
{
- return RET_ERROR (EIO);
+ return -EIO;
}
long
@@ -1065,13 +1569,13 @@
int
DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
{
- return RET_ERROR (EIO);
+ return -EIO;
}
int
DMAbuf_open_dma (int dev)
{
- return RET_ERROR (ENXIO);
+ return -ENXIO;
}
void
@@ -1097,7 +1601,6 @@
{
return;
}
-
#endif
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this