summaryrefslogtreecommitdiffstats
path: root/drivers/sound/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sound/audio.c')
-rw-r--r--drivers/sound/audio.c1386
1 files changed, 646 insertions, 740 deletions
diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c
index 3ccdc5892..b27b1999a 100644
--- a/drivers/sound/audio.c
+++ b/drivers/sound/audio.c
@@ -11,62 +11,61 @@
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
-#include <linux/config.h>
+/*
+ * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
+ * Thomas Sailer : moved several static variables into struct audio_operations
+ * (which is grossly misnamed btw.) because they have the same
+ * lifetime as the rest in there and dynamic allocation saves
+ * 12k or so
+ */
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kerneld.h>
#include "sound_config.h"
#if defined(CONFIG_AUDIO) || defined(MODULE)
-
#include "ulaw.h"
#include "coproc.h"
#define NEUTRAL8 0x80
#define NEUTRAL16 0x00
-static int audio_mode[MAX_AUDIO_DEV];
-static int dev_nblock[MAX_AUDIO_DEV]; /* 1 if in nonblocking mode */
-#define AM_NONE 0
-#define AM_WRITE OPEN_WRITE
-#define AM_READ OPEN_READ
int dma_ioctl(int dev, unsigned int cmd, caddr_t arg);
-
-static int local_format[MAX_AUDIO_DEV], audio_format[MAX_AUDIO_DEV];
-static int local_conversion[MAX_AUDIO_DEV];
-
-#define CNV_MU_LAW 0x00000001
-static int
-set_format(int dev, int fmt)
+static int set_format(int dev, int fmt)
{
if (fmt != AFMT_QUERY)
- {
- local_conversion[dev] = 0;
-
- if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */
- if (fmt == AFMT_MU_LAW)
- {
- fmt = AFMT_U8;
- local_conversion[dev] = CNV_MU_LAW;
- } else
- fmt = AFMT_U8; /* This is always supported */
-
- audio_format[dev] = audio_devs[dev]->d->set_bits(dev, fmt);
- local_format[dev] = fmt;
- } else
- return local_format[dev];
-
- return local_format[dev];
+ {
+ audio_devs[dev]->local_conversion = 0;
+
+ if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */
+ {
+ if (fmt == AFMT_MU_LAW)
+ {
+ fmt = AFMT_U8;
+ audio_devs[dev]->local_conversion = CNV_MU_LAW;
+ }
+ else
+ fmt = AFMT_U8; /* This is always supported */
+ }
+ audio_devs[dev]->audio_format = audio_devs[dev]->d->set_bits(dev, fmt);
+ audio_devs[dev]->local_format = fmt;
+ }
+ else
+ return audio_devs[dev]->local_format;
+
+ return audio_devs[dev]->local_format;
}
-int
-audio_open(int dev, struct fileinfo *file)
+int audio_open(int dev, struct file *file)
{
- int ret;
- int bits;
- int dev_type = dev & 0x0f;
- int mode = file->mode & O_ACCMODE;
+ int ret;
+ int bits;
+ int dev_type = dev & 0x0f;
+ int mode = translate_mode(file);
dev = dev >> 4;
@@ -82,31 +81,31 @@ audio_open(int dev, struct fileinfo *file)
return ret;
if (audio_devs[dev]->coproc)
+ {
if ((ret = audio_devs[dev]->coproc->
- open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0)
- {
- audio_release(dev, file);
- printk("Sound: Can't access coprocessor device\n");
-
- return ret;
- }
- local_conversion[dev] = 0;
+ open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0)
+ {
+ audio_release(dev, file);
+ printk(KERN_WARNING "Sound: Can't access coprocessor device\n");
+ return ret;
+ }
+ }
+
+ audio_devs[dev]->local_conversion = 0;
if (dev_type == SND_DEV_AUDIO)
- {
- set_format(dev, AFMT_MU_LAW);
- } else
+ set_format(dev, AFMT_MU_LAW);
+ else
set_format(dev, bits);
- audio_mode[dev] = AM_NONE;
- dev_nblock[dev] = 0;
+ audio_devs[dev]->audio_mode = AM_NONE;
+ audio_devs[dev]->dev_nblock = 0;
return ret;
}
-static void
-sync_output(int dev)
+static void sync_output(int dev)
{
int p, i;
int l;
@@ -117,44 +116,44 @@ sync_output(int dev)
dmap->flags |= DMA_POST;
/* Align the write pointer with fragment boundaries */
+
if ((l = dmap->user_counter % dmap->fragment_size) > 0)
- {
- int len;
- unsigned long offs = dmap->user_counter % dmap->bytes_in_use;
-
- len = dmap->fragment_size - l;
- memset(dmap->raw_buf + offs, dmap->neutral_byte, len);
- DMAbuf_move_wrpointer(dev, len);
- }
-/*
- * Clean all unused buffer fragments.
- */
+ {
+ int len;
+ unsigned long offs = dmap->user_counter % dmap->bytes_in_use;
+
+ len = dmap->fragment_size - l;
+ memset(dmap->raw_buf + offs, dmap->neutral_byte, len);
+ DMAbuf_move_wrpointer(dev, len);
+ }
+
+ /*
+ * Clean all unused buffer fragments.
+ */
p = dmap->qtail;
dmap->flags |= DMA_POST;
for (i = dmap->qlen + 1; i < dmap->nbufs; i++)
- {
- p = (p + 1) % dmap->nbufs;
- if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) >
- (dmap->raw_buf + dmap->buffsize))
- printk("audio: Buffer error 2\n");
+ {
+ p = (p + 1) % dmap->nbufs;
+ if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) >
+ (dmap->raw_buf + dmap->buffsize))
+ printk(KERN_ERR "audio: Buffer error 2\n");
- memset(dmap->raw_buf + p * dmap->fragment_size,
- dmap->neutral_byte,
- dmap->fragment_size);
- }
+ memset(dmap->raw_buf + p * dmap->fragment_size,
+ dmap->neutral_byte,
+ dmap->fragment_size);
+ }
dmap->flags |= DMA_DIRTY;
}
-void
-audio_release(int dev, struct fileinfo *file)
+void audio_release(int dev, struct file *file)
{
- int mode;
+ int mode = translate_mode(file);
dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
audio_devs[dev]->dmap_out->closing = 1;
audio_devs[dev]->dmap_in->closing = 1;
@@ -167,8 +166,8 @@ audio_release(int dev, struct fileinfo *file)
}
#if defined(NO_INLINE_ASM) || !defined(i386)
-static void
-translate_bytes(const unsigned char *table, unsigned char *buff, int n)
+
+static void translate_bytes(const unsigned char *table, unsigned char *buff, int n)
{
unsigned long i;
@@ -184,25 +183,24 @@ extern inline void
translate_bytes(const void *table, void *buff, int n)
{
if (n > 0)
- {
- __asm__("cld\n"
- "1:\tlodsb\n\t"
- "xlatb\n\t"
- "stosb\n\t"
+ {
+ __asm__("cld\n"
+ "1:\tlodsb\n\t"
+ "xlatb\n\t"
+ "stosb\n\t"
"loop 1b\n\t":
: "b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff)
: "bx", "cx", "di", "si", "ax");
- }
+ }
}
#endif
-int
-audio_write(int dev, struct fileinfo *file, const char *buf, int count)
+int audio_write(int dev, struct file *file, const char *buf, int count)
{
- int c, p, l, buf_size;
- int err;
- char *dma_buf;
+ int c, p, l, buf_size;
+ int err;
+ char *dma_buf;
dev = dev >> 4;
@@ -213,66 +211,66 @@ audio_write(int dev, struct fileinfo *file, const char *buf, int count)
return -EPERM;
if (audio_devs[dev]->flags & DMA_DUPLEX)
- audio_mode[dev] |= AM_WRITE;
+ audio_devs[dev]->audio_mode |= AM_WRITE;
else
- audio_mode[dev] = AM_WRITE;
+ audio_devs[dev]->audio_mode = AM_WRITE;
if (!count) /* Flush output */
- {
+ {
sync_output(dev);
return 0;
- }
+ }
+
while (c)
- {
- if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, dev_nblock[dev])) < 0)
- {
+ {
+ if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, audio_devs[dev]->dev_nblock)) < 0)
+ {
/* Handle nonblocking mode */
- if (dev_nblock[dev] && err == -EAGAIN)
- return p; /* No more space. Return # of accepted bytes */
- return err;
- }
- l = c;
-
- if (l > buf_size)
- l = buf_size;
-
- if (!audio_devs[dev]->d->copy_user)
- {
- if ((dma_buf + l) >
+ if (audio_devs[dev]->dev_nblock && err == -EAGAIN)
+ return p; /* No more space. Return # of accepted bytes */
+ return err;
+ }
+ l = c;
+
+ if (l > buf_size)
+ l = buf_size;
+
+ if (!audio_devs[dev]->d->copy_user)
+ {
+ if ((dma_buf + l) >
(audio_devs[dev]->dmap_out->raw_buf + audio_devs[dev]->dmap_out->buffsize))
- {
- printk("audio: Buffer error 3 (%lx,%d), (%lx, %d)\n", (long) dma_buf, l, (long) audio_devs[dev]->dmap_out->raw_buf, (int) audio_devs[dev]->dmap_out->buffsize);
- return -EDOM;
- }
- if (dma_buf < audio_devs[dev]->dmap_out->raw_buf)
- {
- printk("audio: Buffer error 13 (%lx<%lx)\n", (long) dma_buf, (long) audio_devs[dev]->dmap_out->raw_buf);
- return -EDOM;
- }
- copy_from_user(dma_buf, &(buf)[p], l);
- } else
- audio_devs[dev]->d->copy_user(dev,
- dma_buf, 0, buf, p, l);
-
- if (local_conversion[dev] & CNV_MU_LAW)
- {
- /*
- * This just allows interrupts while the conversion is running
- */
- sti();
- translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l);
- }
- c -= l;
- p += l;
- DMAbuf_move_wrpointer(dev, l);
-
- }
+ {
+ printk(KERN_ERR "audio: Buffer error 3 (%lx,%d), (%lx, %d)\n", (long) dma_buf, l, (long) audio_devs[dev]->dmap_out->raw_buf, (int) audio_devs[dev]->dmap_out->buffsize);
+ return -EDOM;
+ }
+ if (dma_buf < audio_devs[dev]->dmap_out->raw_buf)
+ {
+ printk(KERN_ERR "audio: Buffer error 13 (%lx<%lx)\n", (long) dma_buf, (long) audio_devs[dev]->dmap_out->raw_buf);
+ return -EDOM;
+ }
+ if(copy_from_user(dma_buf, &(buf)[p], l))
+ return -EFAULT;
+ }
+ else audio_devs[dev]->d->copy_user(dev, dma_buf, 0, buf, p, l);
+
+ if (audio_devs[dev]->local_conversion & CNV_MU_LAW)
+ {
+ /*
+ * This just allows interrupts while the conversion is running
+ */
+ sti();
+ translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l);
+ }
+ c -= l;
+ p += l;
+ DMAbuf_move_wrpointer(dev, l);
+
+ }
return count;
}
-int
-audio_read(int dev, struct fileinfo *file, char *buf, int count)
+int audio_read(int dev, struct file *file, char *buf, int count)
{
int c, p, l;
char *dmabuf;
@@ -285,252 +283,235 @@ audio_read(int dev, struct fileinfo *file, char *buf, int count)
if (!(audio_devs[dev]->open_mode & OPEN_READ))
return -EPERM;
- if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
- {
- sync_output(dev);
- }
+ if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
+ sync_output(dev);
+
if (audio_devs[dev]->flags & DMA_DUPLEX)
- audio_mode[dev] |= AM_READ;
+ audio_devs[dev]->audio_mode |= AM_READ;
else
- audio_mode[dev] = AM_READ;
+ audio_devs[dev]->audio_mode = AM_READ;
- while (c)
- {
- if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l,
- dev_nblock[dev])) < 0)
- {
- /* Nonblocking mode handling. Return current # of bytes */
+ while(c)
+ {
+ if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l,
+ audio_devs[dev]->dev_nblock)) < 0)
+ {
+ /*
+ * Nonblocking mode handling. Return current # of bytes
+ */
- if (dev_nblock[dev] && buf_no == -EAGAIN)
- return p;
+ if (audio_devs[dev]->dev_nblock && buf_no == -EAGAIN)
+ return p;
- if (p > 0) /* Avoid throwing away data */
+ if (p > 0) /* Avoid throwing away data */
return p; /* Return it instead */
- return buf_no;
- }
- if (l > c)
- l = c;
+ return buf_no;
+ }
+ if (l > c)
+ l = c;
- /*
- * Insert any local processing here.
- */
+ /*
+ * Insert any local processing here.
+ */
- if (local_conversion[dev] & CNV_MU_LAW)
- {
- /*
- * This just allows interrupts while the conversion is running
- */
- sti();
+ if (audio_devs[dev]->local_conversion & CNV_MU_LAW)
+ {
+ /*
+ * This just allows interrupts while the conversion is running
+ */
+ sti();
- translate_bytes(dsp_ulaw, (unsigned char *) dmabuf, l);
- }
- {
- char *fixit = dmabuf;
+ translate_bytes(dsp_ulaw, (unsigned char *) dmabuf, l);
+ }
+
+ {
+ char *fixit = dmabuf;
- copy_to_user(&(buf)[p], fixit, l);
- };
+ if(copy_to_user(&(buf)[p], fixit, l))
+ return -EFAULT;
+ };
- DMAbuf_rmchars(dev, buf_no, l);
+ DMAbuf_rmchars(dev, buf_no, l);
- p += l;
- c -= l;
- }
+ p += l;
+ c -= l;
+ }
return count - c;
}
-int
-audio_ioctl(int dev, struct fileinfo *file_must_not_be_used,
- unsigned int cmd, caddr_t arg)
+int audio_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg)
{
- int val;
-
- /* printk( "audio_ioctl(%x, %x)\n", (int)cmd, (int)arg); */
+ int val, count;
+ unsigned long flags;
+ struct dma_buffparms *dmap;
dev = dev >> 4;
- if (((cmd >> 8) & 0xff) == 'C')
- {
- if (audio_devs[dev]->coproc) /* Coprocessor ioctl */
- return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0);
- else
- printk("/dev/dsp%d: No coprocessor for this device\n", dev);
-
- return -ENXIO;
- } else
- switch (cmd)
- {
- case SNDCTL_DSP_SYNC:
- if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
- return 0;
-
- if (audio_devs[dev]->dmap_out->fragment_size == 0)
- return 0;
- sync_output(dev);
- DMAbuf_sync(dev);
- DMAbuf_reset(dev);
- return 0;
- break;
-
- case SNDCTL_DSP_POST:
- if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
- return 0;
- if (audio_devs[dev]->dmap_out->fragment_size == 0)
- return 0;
- audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY;
- sync_output(dev);
- dma_ioctl(dev, SNDCTL_DSP_POST, (caddr_t) 0);
- return 0;
- break;
-
- case SNDCTL_DSP_RESET:
- audio_mode[dev] = AM_NONE;
- DMAbuf_reset(dev);
- return 0;
- break;
-
- case SNDCTL_DSP_GETFMTS:
- return (*(int *) arg = audio_devs[dev]->format_mask);
- break;
-
- case SNDCTL_DSP_SETFMT:
- val = *(int *) arg;
- return (*(int *) arg = set_format(dev, val));
-
- case SNDCTL_DSP_GETISPACE:
- if (!(audio_devs[dev]->open_mode & OPEN_READ))
- return 0;
- if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
- return -EBUSY;
-
- {
- audio_buf_info info;
-
- int err = dma_ioctl(dev, cmd, (caddr_t) & info);
-
- if (err < 0)
- return err;
-
- memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
- return 0;
- }
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
- return -EPERM;
- if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
- return -EBUSY;
-
- {
- audio_buf_info info;
-
- int err = dma_ioctl(dev, cmd, (caddr_t) & info);
-
- if (err < 0)
- return err;
-
- memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
- return 0;
- }
-
- case SNDCTL_DSP_NONBLOCK:
- dev_nblock[dev] = 1;
- return 0;
- break;
-
- case SNDCTL_DSP_GETCAPS:
- {
- int info = 1; /* Revision level of this ioctl() */
-
- if (audio_devs[dev]->flags & DMA_DUPLEX &&
- audio_devs[dev]->open_mode == OPEN_READWRITE)
- info |= DSP_CAP_DUPLEX;
-
- if (audio_devs[dev]->coproc)
- info |= DSP_CAP_COPROC;
-
- if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */
- info |= DSP_CAP_BATCH;
-
- if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */
- info |= DSP_CAP_TRIGGER;
-
- info |= DSP_CAP_MMAP;
-
- memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
- return 0;
- }
- break;
-
- case SOUND_PCM_WRITE_RATE:
- val = *(int *) arg;
- return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, val));
-
- case SOUND_PCM_READ_RATE:
- return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, 0));
-
- case SNDCTL_DSP_STEREO:
- {
- int n;
-
- n = *(int *) arg;
- if (n > 1)
- {
- printk("sound: SNDCTL_DSP_STEREO called with invalid argument %d\n", n);
- return -EINVAL;
- }
- if (n < 0)
- return -EINVAL;
-
- return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, n + 1) - 1);
- }
-
- case SOUND_PCM_WRITE_CHANNELS:
- val = *(int *) arg;
- return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, val));
-
- case SOUND_PCM_READ_CHANNELS:
- return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, 0));
-
- case SOUND_PCM_READ_BITS:
- return (*(int *) arg = audio_devs[dev]->d->set_bits(dev, 0));
-
- case SNDCTL_DSP_SETDUPLEX:
- if (audio_devs[dev]->open_mode != OPEN_READWRITE)
- return -EPERM;
- if (audio_devs[dev]->flags & DMA_DUPLEX)
- return 0;
- else
- return -EIO;
- break;
-
- case SNDCTL_DSP_PROFILE:
- if (audio_devs[dev]->open_mode & OPEN_WRITE)
- audio_devs[dev]->dmap_out->applic_profile = *(int *) arg;
- if (audio_devs[dev]->open_mode & OPEN_READ)
- audio_devs[dev]->dmap_in->applic_profile = *(int *) arg;
- return 0;
- break;
-
- default:
- return dma_ioctl(dev, cmd, arg);
- }
+ if (_IOC_TYPE(cmd) == 'C') {
+ if (audio_devs[dev]->coproc) /* Coprocessor ioctl */
+ return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0);
+ /* else
+ printk(KERN_DEBUG"/dev/dsp%d: No coprocessor for this device\n", dev); */
+ return -ENXIO;
+ }
+ else switch (cmd)
+ {
+ case SNDCTL_DSP_SYNC:
+ if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+ return 0;
+ if (audio_devs[dev]->dmap_out->fragment_size == 0)
+ return 0;
+ sync_output(dev);
+ DMAbuf_sync(dev);
+ DMAbuf_reset(dev);
+ return 0;
+
+ case SNDCTL_DSP_POST:
+ if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+ return 0;
+ if (audio_devs[dev]->dmap_out->fragment_size == 0)
+ return 0;
+ audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY;
+ sync_output(dev);
+ dma_ioctl(dev, SNDCTL_DSP_POST, (caddr_t) 0);
+ return 0;
+
+ case SNDCTL_DSP_RESET:
+ audio_devs[dev]->audio_mode = AM_NONE;
+ DMAbuf_reset(dev);
+ return 0;
+
+ case SNDCTL_DSP_GETFMTS:
+ val = audio_devs[dev]->format_mask;
+ break;
+
+ case SNDCTL_DSP_SETFMT:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ val = set_format(dev, val);
+ break;
+
+ case SNDCTL_DSP_GETISPACE:
+ if (!(audio_devs[dev]->open_mode & OPEN_READ))
+ return 0;
+ if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
+ return -EBUSY;
+ return dma_ioctl(dev, cmd, arg);
+
+ case SNDCTL_DSP_GETOSPACE:
+ if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+ return -EPERM;
+ if ((audio_devs[dev]->audio_mode & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
+ return -EBUSY;
+ return dma_ioctl(dev, cmd, arg);
+
+ case SNDCTL_DSP_NONBLOCK:
+ audio_devs[dev]->dev_nblock = 1;
+ return 0;
+
+ case SNDCTL_DSP_GETCAPS:
+ val = 1 | DSP_CAP_MMAP; /* Revision level of this ioctl() */
+ if (audio_devs[dev]->flags & DMA_DUPLEX &&
+ audio_devs[dev]->open_mode == OPEN_READWRITE)
+ val |= DSP_CAP_DUPLEX;
+ if (audio_devs[dev]->coproc)
+ val |= DSP_CAP_COPROC;
+ if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */
+ val |= DSP_CAP_BATCH;
+ if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */
+ val |= DSP_CAP_TRIGGER;
+ break;
+
+ case SOUND_PCM_WRITE_RATE:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ val = audio_devs[dev]->d->set_speed(dev, val);
+ break;
+
+ case SOUND_PCM_READ_RATE:
+ val = audio_devs[dev]->d->set_speed(dev, 0);
+ break;
+
+ case SNDCTL_DSP_STEREO:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val > 1 || val < 0)
+ return -EINVAL;
+ val = audio_devs[dev]->d->set_channels(dev, val + 1) - 1;
+ break;
+
+ case SOUND_PCM_WRITE_CHANNELS:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ val = audio_devs[dev]->d->set_channels(dev, val);
+ break;
+
+ case SOUND_PCM_READ_CHANNELS:
+ val = audio_devs[dev]->d->set_channels(dev, 0);
+ break;
+
+ case SOUND_PCM_READ_BITS:
+ val = audio_devs[dev]->d->set_bits(dev, 0);
+ break;
+
+ case SNDCTL_DSP_SETDUPLEX:
+ if (audio_devs[dev]->open_mode != OPEN_READWRITE)
+ return -EPERM;
+ return (audio_devs[dev]->flags & DMA_DUPLEX) ? 0 : -EIO;
+
+ case SNDCTL_DSP_PROFILE:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (audio_devs[dev]->open_mode & OPEN_WRITE)
+ audio_devs[dev]->dmap_out->applic_profile = val;
+ if (audio_devs[dev]->open_mode & OPEN_READ)
+ audio_devs[dev]->dmap_in->applic_profile = val;
+ return 0;
+
+ case SNDCTL_DSP_GETODELAY:
+ dmap = audio_devs[dev]->dmap_out;
+ if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+ return -EINVAL;
+ if (!(dmap->flags & DMA_ALLOC_DONE))
+ {
+ val=0;
+ break;
+ }
+
+ save_flags (flags);
+ cli();
+ /* Compute number of bytes that have been played */
+ count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT);
+ if (count < dmap->fragment_size && dmap->qhead != 0)
+ count += dmap->bytes_in_use; /* Pointer wrap not handled yet */
+ count += dmap->byte_counter;
+
+ /* Substract current count from the number of bytes written by app */
+ count = dmap->user_counter - count;
+ if (count < 0)
+ count = 0;
+ restore_flags (flags);
+ val = count;
+ break;
+
+ default:
+ return dma_ioctl(dev, cmd, arg);
+ }
+ return put_user(val, (int *)arg);
}
-void
-audio_init_devices(void)
+void audio_init_devices(void)
{
/*
* NOTE! This routine could be called several times during boot.
*/
}
-
#endif
-void
-reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
+void reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
{
/*
* This routine breaks the physical device buffers to logical ones.
@@ -538,8 +519,8 @@ reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
struct audio_operations *dsp_dev = audio_devs[dev];
- unsigned i, n;
- unsigned sr, nc, sz, bsz;
+ unsigned i, n;
+ unsigned sr, nc, sz, bsz;
sr = dsp_dev->d->set_speed(dev, 0);
nc = dsp_dev->d->set_channels(dev, 0);
@@ -551,12 +532,13 @@ reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
dmap->neutral_byte = NEUTRAL16;
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;
- }
+ {
+/* printk(KERN_DEBUG "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 */
@@ -567,52 +549,54 @@ reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
dmap->needs_reorg = 0;
if (dmap->fragment_size == 0)
- { /* Compute the fragment size using the default algorithm */
-
- /*
- * Compute a buffer size for time not exceeding 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 = dmap->buffsize;
- while (bsz > sz)
- bsz /= 2;
-
- if (bsz == dmap->buffsize)
- bsz /= 2; /* Needs at least 2 buffers */
-
-/*
- * Split the computed fragment to smaller parts. After 3.5a9
- * the default subdivision is 4 which should give better
- * results when recording.
- */
-
- if (dmap->subdivision == 0) /* Not already set */
- {
- dmap->subdivision = 4; /* Init to the default value */
-
- if ((bsz / dmap->subdivision) > 4096)
- dmap->subdivision *= 2;
- if ((bsz / dmap->subdivision) < 4096)
- dmap->subdivision = 1;
- }
- bsz /= dmap->subdivision;
-
- if (bsz < 16)
- bsz = 16; /* Just a sanity check */
-
- dmap->fragment_size = bsz;
- } else
- {
- /*
- * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or
- * the buffer size computation has already been done.
- */
- if (dmap->fragment_size > (dmap->buffsize / 2))
- dmap->fragment_size = (dmap->buffsize / 2);
- bsz = dmap->fragment_size;
- }
+ {
+ /* Compute the fragment size using the default algorithm */
+
+ /*
+ * Compute a buffer size for time not exceeding 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 = dmap->buffsize;
+ while (bsz > sz)
+ bsz /= 2;
+
+ if (bsz == dmap->buffsize)
+ bsz /= 2; /* Needs at least 2 buffers */
+
+ /*
+ * Split the computed fragment to smaller parts. After 3.5a9
+ * the default subdivision is 4 which should give better
+ * results when recording.
+ */
+
+ if (dmap->subdivision == 0) /* Not already set */
+ {
+ dmap->subdivision = 4; /* Init to the default value */
+
+ if ((bsz / dmap->subdivision) > 4096)
+ dmap->subdivision *= 2;
+ if ((bsz / dmap->subdivision) < 4096)
+ dmap->subdivision = 1;
+ }
+ bsz /= dmap->subdivision;
+
+ if (bsz < 16)
+ bsz = 16; /* Just a sanity check */
+
+ dmap->fragment_size = bsz;
+ }
+ else
+ {
+ /*
+ * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or
+ * the buffer size computation has already been done.
+ */
+ if (dmap->fragment_size > (dmap->buffsize / 2))
+ dmap->fragment_size = (dmap->buffsize / 2);
+ bsz = dmap->fragment_size;
+ }
if (audio_devs[dev]->min_fragment)
if (bsz < (1 << audio_devs[dev]->min_fragment))
@@ -632,42 +616,39 @@ reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
n = dmap->max_fragments;
if (n < 2)
- {
- n = 2;
- bsz /= 2;
- }
+ {
+ n = 2;
+ bsz /= 2;
+ }
dmap->nbufs = n;
dmap->bytes_in_use = n * bsz;
dmap->fragment_size = bsz;
dmap->max_byte_counter = (dmap->data_rate * 60 * 60) +
- dmap->bytes_in_use; /* Approximately one hour */
+ dmap->bytes_in_use; /* Approximately one hour */
if (dmap->raw_buf)
- {
- memset(dmap->raw_buf,
- dmap->neutral_byte,
- dmap->bytes_in_use);
- }
+ {
+ memset(dmap->raw_buf, dmap->neutral_byte, dmap->bytes_in_use);
+ }
+
for (i = 0; i < dmap->nbufs; i++)
- {
- dmap->counts[i] = 0;
- }
+ {
+ dmap->counts[i] = 0;
+ }
dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY;
}
-static int
-dma_subdivide(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
+static int dma_subdivide(int dev, struct dma_buffparms *dmap, int fact)
{
- if (fact == 0)
- {
- fact = dmap->subdivision;
- if (fact == 0)
- fact = 1;
- return (*(int *) arg = fact);
- }
- if (dmap->subdivision != 0 ||
- dmap->fragment_size) /* Too late to change */
+ if (fact == 0)
+ {
+ fact = dmap->subdivision;
+ if (fact == 0)
+ fact = 1;
+ return fact;
+ }
+ if (dmap->subdivision != 0 || dmap->fragment_size) /* Too late to change */
return -EINVAL;
if (fact > MAX_REALTIME_FACTOR)
@@ -677,13 +658,12 @@ dma_subdivide(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
return -EINVAL;
dmap->subdivision = fact;
- return (*(int *) arg = fact);
+ return fact;
}
-static int
-dma_set_fragment(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
+static int dma_set_fragment(int dev, struct dma_buffparms *dmap, int fact)
{
- int bytes, count;
+ int bytes, count;
if (fact == 0)
return -EIO;
@@ -730,315 +710,241 @@ dma_set_fragment(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
dmap->fragment_size /= 2; /* Needs at least 2 buffers */
dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */
- if (arg)
- return (*(int *) arg = bytes | ((count - 1) << 16));
- else
- return 0;
+ return bytes | ((count - 1) << 16);
}
-int
-dma_ioctl(int dev, unsigned int cmd, caddr_t arg)
+int dma_ioctl(int dev, unsigned int cmd, caddr_t arg)
{
-
struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out;
struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in;
-
- switch (cmd)
- {
-
- case SNDCTL_DSP_SUBDIVIDE:
- {
- int fact;
- int ret = 0;
-
- fact = *(int *) arg;
-
- if (audio_devs[dev]->open_mode & OPEN_WRITE)
- ret = dma_subdivide(dev, dmap_out, arg, fact);
- if (ret < 0)
- return ret;
-
- if (audio_devs[dev]->open_mode != OPEN_WRITE ||
- (audio_devs[dev]->flags & DMA_DUPLEX &&
- audio_devs[dev]->open_mode & OPEN_READ))
- ret = dma_subdivide(dev, dmap_in, arg, fact);
-
- return ret;
- }
- break;
-
- case SNDCTL_DSP_GETISPACE:
- case SNDCTL_DSP_GETOSPACE:
- {
- struct dma_buffparms *dmap = dmap_out;
-
- audio_buf_info *info = (audio_buf_info *) arg;
-
- if (cmd == SNDCTL_DSP_GETISPACE &&
- !(audio_devs[dev]->open_mode & OPEN_READ))
- return -EINVAL;
-
- if (cmd == SNDCTL_DSP_GETOSPACE &&
- !(audio_devs[dev]->open_mode & OPEN_WRITE))
- return -EINVAL;
-
- 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, dmap, (cmd == SNDCTL_DSP_GETISPACE));
-
- info->fragstotal = dmap->nbufs;
-
- if (cmd == SNDCTL_DSP_GETISPACE)
- info->fragments = dmap->qlen;
- else
- {
- if (!DMAbuf_space_in_queue(dev))
- info->fragments = 0;
- else
- {
- info->fragments = DMAbuf_space_in_queue(dev);
- if (audio_devs[dev]->d->local_qlen)
- {
- int tmp = audio_devs[dev]->d->local_qlen(dev);
-
- if (tmp && info->fragments)
- tmp--; /*
- * This buffer has been counted twice
- */
- info->fragments -= tmp;
- }
- }
- }
-
- if (info->fragments < 0)
- info->fragments = 0;
- else if (info->fragments > dmap->nbufs)
- info->fragments = dmap->nbufs;
-
- 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];
- else
- {
- info->fragments = info->bytes / dmap->fragment_size;
- info->bytes -= dmap->user_counter % dmap->fragment_size;
- }
- }
- return 0;
-
- case SNDCTL_DSP_SETTRIGGER:
- {
- unsigned long flags;
-
- int bits;
- int changed;
-
- bits = *(int *) arg;
- bits &= audio_devs[dev]->open_mode;
-
- if (audio_devs[dev]->d->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)
- {
- int err;
-
- reorganize_buffers(dev, dmap_in, 1);
-
- if ((err = audio_devs[dev]->d->prepare_for_input(dev,
- dmap_in->fragment_size, dmap_in->nbufs)) < 0)
- return -err;
-
- dmap_in->dma_mode = DMODE_INPUT;
- audio_devs[dev]->enable_bits = bits;
- DMAbuf_activate_recording(dev, dmap_in);
- }
- if ((changed & bits) & PCM_ENABLE_OUTPUT &&
- (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) &&
- audio_devs[dev]->go)
- {
-
- if (!(dmap_out->flags & DMA_ALLOC_DONE))
- {
- reorganize_buffers(dev, dmap_out, 0);
- }
- dmap_out->dma_mode = DMODE_OUTPUT;
- ;
- audio_devs[dev]->enable_bits = bits;
- dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
- DMAbuf_launch_output(dev, dmap_out);
- ;
- }
- audio_devs[dev]->enable_bits = bits;
- if (changed && audio_devs[dev]->d->trigger)
- {
- audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go);
- }
- restore_flags(flags);
- }
- case SNDCTL_DSP_GETTRIGGER:
- return (*(int *) arg = audio_devs[dev]->enable_bits);
- break;
-
- case SNDCTL_DSP_SETSYNCRO:
-
- if (!audio_devs[dev]->d->trigger)
- return -EINVAL;
-
- audio_devs[dev]->d->trigger(dev, 0);
- audio_devs[dev]->go = 0;
- return 0;
- break;
-
- case SNDCTL_DSP_GETIPTR:
- {
- count_info info;
- unsigned long flags;
- struct dma_buffparms *dmap = dmap_in;
-
- if (!(audio_devs[dev]->open_mode & OPEN_READ))
- return -EINVAL;
-
- save_flags(flags);
- cli();
- info.bytes = dmap->byte_counter;
- info.ptr = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_INPUT) & ~3;
- if (info.ptr < dmap->fragment_size && dmap->qtail != 0)
- info.bytes += dmap->bytes_in_use; /* Pointer wrap not handled yet */
-
- info.blocks = dmap->qlen;
- info.bytes += info.ptr;
- memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-
- if (dmap->mapping_flags & DMA_MAP_MAPPED)
- dmap->qlen = 0; /* Reset interrupt counter */
- restore_flags(flags);
- return 0;
- }
- break;
-
- case SNDCTL_DSP_GETOPTR:
- {
- count_info info;
- unsigned long flags;
- struct dma_buffparms *dmap = dmap_out;
-
- if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
- return -EINVAL;
-
- save_flags(flags);
- cli();
- info.bytes = dmap->byte_counter;
- info.ptr = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT) & ~3;
- if (info.ptr < dmap->fragment_size && dmap->qhead != 0)
- info.bytes += dmap->bytes_in_use; /* Pointer wrap not handled yet */
- info.blocks = dmap->qlen;
- info.bytes += info.ptr;
- memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-
- if (dmap->mapping_flags & DMA_MAP_MAPPED)
- dmap->qlen = 0; /* Reset interrupt counter */
-
- restore_flags(flags);
- return 0;
- }
- break;
-
- case SNDCTL_DSP_GETODELAY:
- {
- int count;
- unsigned long flags;
- struct dma_buffparms *dmap = dmap_out;
-
- if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
- return -EINVAL;
- if (!(dmap->flags & DMA_ALLOC_DONE))
- return (*(int *) arg = 0);
-
- save_flags (flags);
- cli ();
- /* Compute number of bytes that have been played */
- count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT);
- if (count < dmap->fragment_size && dmap->qhead != 0)
- count += dmap->bytes_in_use; /* Pointer wrap not handled yet */
- count += dmap->byte_counter;
-
- /* Substract current count from the number of bytes written by app */
- count = dmap->user_counter - count;
- if (count < 0)
- count = 0;
- restore_flags (flags);
-
- return (*(int *) arg = count);
- }
- break;
-
- case SNDCTL_DSP_POST:
- ;
- if (audio_devs[dev]->dmap_out->qlen > 0)
- if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE))
- DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out);
- ;
- return 0;
- break;
-
- case SNDCTL_DSP_GETBLKSIZE:
- {
- int fragment_size;
- struct dma_buffparms *dmap = dmap_out;
-
- if (audio_devs[dev]->open_mode & OPEN_WRITE)
- reorganize_buffers(dev, dmap_out,
- (audio_devs[dev]->open_mode == OPEN_READ));
- if (audio_devs[dev]->open_mode != OPEN_WRITE ||
- (audio_devs[dev]->flags & DMA_DUPLEX &&
- audio_devs[dev]->open_mode & OPEN_READ))
- reorganize_buffers(dev, dmap_in,
- (audio_devs[dev]->open_mode == OPEN_READ));
- if (audio_devs[dev]->open_mode == OPEN_READ)
- dmap = dmap_in;
- fragment_size = dmap->fragment_size;
- return (*(int *) arg = fragment_size);
- }
- break;
-
- case SNDCTL_DSP_SETFRAGMENT:
- {
- int fact;
- int ret;
-
- fact = *(int *) arg;
- ret = dma_set_fragment(dev, dmap_out, arg, fact);
- if (ret < 0)
- return ret;
-
- if (audio_devs[dev]->flags & DMA_DUPLEX &&
- audio_devs[dev]->open_mode & OPEN_READ)
- ret = dma_set_fragment(dev, dmap_in, arg, fact);
-
- return ret;
- }
- break;
-
- default:
- return audio_devs[dev]->d->ioctl(dev, cmd, arg);
- }
-
+ struct dma_buffparms *dmap;
+ audio_buf_info info;
+ count_info cinfo;
+ int fact, ret, changed, bits, count, err;
+ unsigned long flags;
+
+ switch (cmd)
+ {
+ case SNDCTL_DSP_SUBDIVIDE:
+ ret = 0;
+ if (get_user(fact, (int *)arg))
+ return -EFAULT;
+ if (audio_devs[dev]->open_mode & OPEN_WRITE)
+ ret = dma_subdivide(dev, dmap_out, fact);
+ if (ret < 0)
+ return ret;
+ if (audio_devs[dev]->open_mode != OPEN_WRITE ||
+ (audio_devs[dev]->flags & DMA_DUPLEX &&
+ audio_devs[dev]->open_mode & OPEN_READ))
+ ret = dma_subdivide(dev, dmap_in, fact);
+ if (ret < 0)
+ return ret;
+ break;
+
+ case SNDCTL_DSP_GETISPACE:
+ case SNDCTL_DSP_GETOSPACE:
+ dmap = dmap_out;
+ if (cmd == SNDCTL_DSP_GETISPACE && !(audio_devs[dev]->open_mode & OPEN_READ))
+ return -EINVAL;
+ if (cmd == SNDCTL_DSP_GETOSPACE && !(audio_devs[dev]->open_mode & OPEN_WRITE))
+ return -EINVAL;
+ 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, dmap, (cmd == SNDCTL_DSP_GETISPACE));
+ info.fragstotal = dmap->nbufs;
+ if (cmd == SNDCTL_DSP_GETISPACE)
+ info.fragments = dmap->qlen;
+ else
+ {
+ if (!DMAbuf_space_in_queue(dev))
+ info.fragments = 0;
+ else
+ {
+ info.fragments = DMAbuf_space_in_queue(dev);
+ if (audio_devs[dev]->d->local_qlen)
+ {
+ int tmp = audio_devs[dev]->d->local_qlen(dev);
+ if (tmp && info.fragments)
+ tmp--; /*
+ * This buffer has been counted twice
+ */
+ info.fragments -= tmp;
+ }
+ }
+ }
+ if (info.fragments < 0)
+ info.fragments = 0;
+ else if (info.fragments > dmap->nbufs)
+ info.fragments = dmap->nbufs;
+
+ 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];
+ else
+ {
+ info.fragments = info.bytes / dmap->fragment_size;
+ info.bytes -= dmap->user_counter % dmap->fragment_size;
+ }
+ if (copy_to_user(arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+
+ case SNDCTL_DSP_SETTRIGGER:
+ if (get_user(bits, (int *)arg))
+ return -EFAULT;
+ bits &= audio_devs[dev]->open_mode;
+ if (audio_devs[dev]->d->trigger == NULL)
+ return -EINVAL;
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX) && (bits & PCM_ENABLE_INPUT) &&
+ (bits & PCM_ENABLE_OUTPUT))
+ return -EINVAL;
+ save_flags(flags);
+ cli();
+ changed = audio_devs[dev]->enable_bits ^ bits;
+ if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go)
+ {
+ reorganize_buffers(dev, dmap_in, 1);
+ if ((err = audio_devs[dev]->d->prepare_for_input(dev,
+ dmap_in->fragment_size, dmap_in->nbufs)) < 0)
+ return -err;
+ dmap_in->dma_mode = DMODE_INPUT;
+ audio_devs[dev]->enable_bits = bits;
+ DMAbuf_activate_recording(dev, dmap_in);
+ }
+ if ((changed & bits) & PCM_ENABLE_OUTPUT &&
+ (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) &&
+ audio_devs[dev]->go)
+ {
+ if (!(dmap_out->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap_out, 0);
+ dmap_out->dma_mode = DMODE_OUTPUT;
+ audio_devs[dev]->enable_bits = bits;
+ dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
+ DMAbuf_launch_output(dev, dmap_out);
+ }
+ audio_devs[dev]->enable_bits = bits;
+ if (changed && audio_devs[dev]->d->trigger)
+ audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go);
+ restore_flags(flags);
+ /* Falls through... */
+
+ case SNDCTL_DSP_GETTRIGGER:
+ ret = audio_devs[dev]->enable_bits;
+ break;
+
+ case SNDCTL_DSP_SETSYNCRO:
+ if (!audio_devs[dev]->d->trigger)
+ return -EINVAL;
+ audio_devs[dev]->d->trigger(dev, 0);
+ audio_devs[dev]->go = 0;
+ return 0;
+
+ case SNDCTL_DSP_GETIPTR:
+ if (!(audio_devs[dev]->open_mode & OPEN_READ))
+ return -EINVAL;
+ save_flags(flags);
+ cli();
+ cinfo.bytes = dmap_in->byte_counter;
+ cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_in, DMODE_INPUT) & ~3;
+ if (cinfo.ptr < dmap_in->fragment_size && dmap_in->qtail != 0)
+ cinfo.bytes += dmap_in->bytes_in_use; /* Pointer wrap not handled yet */
+ cinfo.blocks = dmap_in->qlen;
+ cinfo.bytes += cinfo.ptr;
+ if (dmap_in->mapping_flags & DMA_MAP_MAPPED)
+ dmap_in->qlen = 0; /* Reset interrupt counter */
+ restore_flags(flags);
+ if (copy_to_user(arg, &cinfo, sizeof(cinfo)))
+ return -EFAULT;
+ return 0;
+
+ case SNDCTL_DSP_GETOPTR:
+ if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+ return -EINVAL;
+
+ save_flags(flags);
+ cli();
+ cinfo.bytes = dmap_out->byte_counter;
+ cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_out, DMODE_OUTPUT) & ~3;
+ if (cinfo.ptr < dmap_out->fragment_size && dmap_out->qhead != 0)
+ cinfo.bytes += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */
+ cinfo.blocks = dmap_out->qlen;
+ cinfo.bytes += cinfo.ptr;
+ if (dmap_out->mapping_flags & DMA_MAP_MAPPED)
+ dmap_out->qlen = 0; /* Reset interrupt counter */
+ restore_flags(flags);
+ if (copy_to_user(arg, &cinfo, sizeof(cinfo)))
+ return -EFAULT;
+ return 0;
+
+ case SNDCTL_DSP_GETODELAY:
+ if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+ return -EINVAL;
+ if (!(dmap_out->flags & DMA_ALLOC_DONE))
+ {
+ ret=0;
+ break;
+ }
+ save_flags(flags);
+ cli();
+ /* Compute number of bytes that have been played */
+ count = DMAbuf_get_buffer_pointer (dev, dmap_out, DMODE_OUTPUT);
+ if (count < dmap_out->fragment_size && dmap_out->qhead != 0)
+ count += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */
+ count += dmap_out->byte_counter;
+ /* Substract current count from the number of bytes written by app */
+ count = dmap_out->user_counter - count;
+ if (count < 0)
+ count = 0;
+ restore_flags (flags);
+ ret = count;
+ break;
+
+ case SNDCTL_DSP_POST:
+ if (audio_devs[dev]->dmap_out->qlen > 0)
+ if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE))
+ DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out);
+ return 0;
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ dmap = dmap_out;
+ if (audio_devs[dev]->open_mode & OPEN_WRITE)
+ reorganize_buffers(dev, dmap_out, (audio_devs[dev]->open_mode == OPEN_READ));
+ if (audio_devs[dev]->open_mode == OPEN_READ ||
+ (audio_devs[dev]->flags & DMA_DUPLEX &&
+ audio_devs[dev]->open_mode & OPEN_READ))
+ reorganize_buffers(dev, dmap_in, (audio_devs[dev]->open_mode == OPEN_READ));
+ if (audio_devs[dev]->open_mode == OPEN_READ)
+ dmap = dmap_in;
+ ret = dmap->fragment_size;
+ break;
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ ret = 0;
+ if (get_user(fact, (int *)arg))
+ return -EFAULT;
+ if (audio_devs[dev]->open_mode & OPEN_WRITE)
+ ret = dma_set_fragment(dev, dmap_out, fact);
+ if (ret < 0)
+ return ret;
+ if (audio_devs[dev]->open_mode == OPEN_READ ||
+ (audio_devs[dev]->flags & DMA_DUPLEX &&
+ audio_devs[dev]->open_mode & OPEN_READ))
+ ret = dma_set_fragment(dev, dmap_in, fact);
+ if (ret < 0)
+ return ret;
+ if (!arg) /* don't know what this is good for, but preserve old semantics */
+ return 0;
+ break;
+
+ default:
+ if (!audio_devs[dev]->d->ioctl)
+ return -EINVAL;
+ return audio_devs[dev]->d->ioctl(dev, cmd, arg);
+ }
+ return put_user(ret, (int *)arg);
}