patch-2.1.67 linux/drivers/sound/audio.c
Next file: linux/drivers/sound/configure.c
Previous file: linux/drivers/sound/adlib_card.c
Back to the patch index
Back to the overall index
- Lines: 1833
- Date:
Sat Nov 29 10:33:20 1997
- Orig file:
v2.1.66/linux/drivers/sound/audio.c
- Orig date:
Wed Nov 12 13:34:26 1997
diff -u --recursive --new-file v2.1.66/linux/drivers/sound/audio.c linux/drivers/sound/audio.c
@@ -16,7 +16,7 @@
#include "sound_config.h"
-#ifdef CONFIG_AUDIO
+#if defined(CONFIG_AUDIO) || defined(MODULE)
#include "ulaw.h"
#include "coproc.h"
@@ -30,7 +30,7 @@
#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);
+int dma_ioctl(int dev, unsigned int cmd, caddr_t arg);
static int local_format[MAX_AUDIO_DEV], audio_format[MAX_AUDIO_DEV];
@@ -38,562 +38,546 @@
#define CNV_MU_LAW 0x00000001
static int
-set_format (int dev, int fmt)
+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)
+ if (fmt != AFMT_QUERY)
{
- fmt = AFMT_U8;
- local_conversion[dev] = CNV_MU_LAW;
- }
- else
- fmt = AFMT_U8; /* This is always supported */
+ local_conversion[dev] = 0;
- audio_format[dev] = audio_devs[dev]->d->set_bits (dev, fmt);
- local_format[dev] = fmt;
- }
- else
- return local_format[dev];
+ 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];
+ return local_format[dev];
}
int
-audio_open (int dev, struct fileinfo *file)
+audio_open(int dev, struct fileinfo *file)
{
- int ret;
- int bits;
- int dev_type = dev & 0x0f;
- int mode = file->mode & O_ACCMODE;
-
- dev = dev >> 4;
-
- if (dev_type == SND_DEV_DSP16)
- bits = 16;
- else
- bits = 8;
-
- if (dev < 0 || dev >= num_audiodevs)
- return -ENXIO;
-
- if ((ret = DMAbuf_open (dev, mode)) < 0)
- 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");
+ int ret;
+ int bits;
+ int dev_type = dev & 0x0f;
+ int mode = file->mode & O_ACCMODE;
- return ret;
- }
+ dev = dev >> 4;
- local_conversion[dev] = 0;
+ if (dev_type == SND_DEV_DSP16)
+ bits = 16;
+ else
+ bits = 8;
- if (dev_type == SND_DEV_AUDIO)
- {
- set_format (dev, AFMT_MU_LAW);
- }
- else
- set_format (dev, bits);
+ if (dev < 0 || dev >= num_audiodevs)
+ return -ENXIO;
- audio_mode[dev] = AM_NONE;
- dev_nblock[dev] = 0;
+ if ((ret = DMAbuf_open(dev, mode)) < 0)
+ 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;
+ return ret;
+ }
+ local_conversion[dev] = 0;
+
+ if (dev_type == SND_DEV_AUDIO)
+ {
+ set_format(dev, AFMT_MU_LAW);
+ } else
+ set_format(dev, bits);
+
+ audio_mode[dev] = AM_NONE;
+ dev_nblock[dev] = 0;
+
+
+ return ret;
}
static void
-sync_output (int dev)
+sync_output(int dev)
{
- int p, i;
- int l;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-
- if (dmap->fragment_size <= 0)
- return;
- 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);
- }
+ int p, i;
+ int l;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+
+ if (dmap->fragment_size <= 0)
+ return;
+ 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.
*/
- p = dmap->qtail;
- dmap->flags |= DMA_POST;
+ 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");
-
- memset (dmap->raw_buf + p * dmap->fragment_size,
- dmap->neutral_byte,
- dmap->fragment_size);
- }
+ 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");
+
+ memset(dmap->raw_buf + p * dmap->fragment_size,
+ dmap->neutral_byte,
+ dmap->fragment_size);
+ }
- dmap->flags |= DMA_DIRTY;
+ dmap->flags |= DMA_DIRTY;
}
void
-audio_release (int dev, struct fileinfo *file)
+audio_release(int dev, struct fileinfo *file)
{
- int mode;
+ int mode;
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
- audio_devs[dev]->dmap_out->closing = 1;
- audio_devs[dev]->dmap_in->closing = 1;
+ audio_devs[dev]->dmap_out->closing = 1;
+ audio_devs[dev]->dmap_in->closing = 1;
- sync_output (dev);
+ sync_output(dev);
- if (audio_devs[dev]->coproc)
- audio_devs[dev]->coproc->close (audio_devs[dev]->coproc->devc, COPR_PCM);
- DMAbuf_release (dev, mode);
+ if (audio_devs[dev]->coproc)
+ audio_devs[dev]->coproc->close(audio_devs[dev]->coproc->devc, COPR_PCM);
+ DMAbuf_release(dev, mode);
}
#if defined(NO_INLINE_ASM) || !defined(i386)
static void
-translate_bytes (const unsigned char *table, unsigned char *buff, int n)
+translate_bytes(const unsigned char *table, unsigned char *buff, int n)
{
- unsigned long i;
+ unsigned long i;
- if (n <= 0)
- return;
+ if (n <= 0)
+ return;
- for (i = 0; i < n; ++i)
- buff[i] = table[buff[i]];
+ for (i = 0; i < n; ++i)
+ buff[i] = table[buff[i]];
}
#else
extern inline void
-translate_bytes (const void *table, void *buff, int n)
+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"
- "loop 1b\n\t":
- : "b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
- : "bx", "cx", "di", "si", "ax");
- }
+ if (n > 0)
+ {
+ __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 c, p, l, buf_size;
- int err;
- char *dma_buf;
-
- dev = dev >> 4;
-
- p = 0;
- c = count;
-
- if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
- return -EPERM;
-
- if (audio_devs[dev]->flags & DMA_DUPLEX)
- audio_mode[dev] |= AM_WRITE;
- else
- audio_mode[dev] = 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)
- {
- /* 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) >
- (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);
-
- }
-
- return count;
-}
-
-int
-audio_read (int dev, struct fileinfo *file, char *buf, int count)
+audio_write(int dev, struct fileinfo *file, const char *buf, int count)
{
- int c, p, l;
- char *dmabuf;
- int buf_no;
-
- dev = dev >> 4;
- p = 0;
- c = count;
-
- if (!(audio_devs[dev]->open_mode & OPEN_READ))
- return -EPERM;
+ int c, p, l, buf_size;
+ int err;
+ char *dma_buf;
- if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
- {
- sync_output (dev);
- }
+ dev = dev >> 4;
- if (audio_devs[dev]->flags & DMA_DUPLEX)
- audio_mode[dev] |= AM_READ;
- else
- audio_mode[dev] = AM_READ;
+ p = 0;
+ c = count;
- while (c)
- {
- if ((buf_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l,
- dev_nblock[dev])) < 0)
- {
- /* Nonblocking mode handling. Return current # of bytes */
-
- if (dev_nblock[dev] && buf_no == -EAGAIN)
- return p;
-
- return buf_no;
- }
-
- if (l > c)
- l = c;
-
- /*
- * Insert any local processing here.
- */
-
- if (local_conversion[dev] & CNV_MU_LAW)
- {
- /*
- * This just allows interrupts while the conversion is running
- */
- sti ();
-
- translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l);
- }
-
- {
- char *fixit = dmabuf;
+ if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+ return -EPERM;
- copy_to_user (&(buf)[p], fixit, l);
- };
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ audio_mode[dev] |= AM_WRITE;
+ else
+ audio_mode[dev] = AM_WRITE;
- DMAbuf_rmchars (dev, buf_no, l);
+ if (!count) /* Flush output */
+ {
+ sync_output(dev);
+ return 0;
+ }
+ while (c)
+ {
+ if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, dev_nblock[dev])) < 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) >
+ (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);
- p += l;
- c -= l;
- }
+ }
- return count - c;
+ return count;
}
int
-audio_ioctl (int dev, struct fileinfo *file_must_not_be_used,
- unsigned int cmd, caddr_t arg)
+audio_read(int dev, struct fileinfo *file, char *buf, int count)
{
- int val;
-
- /* printk( "audio_ioctl(%x, %x)\n", (int)cmd, (int)arg); */
-
- 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));
+ int c, p, l;
+ char *dmabuf;
+ int buf_no;
+
+ dev = dev >> 4;
+ p = 0;
+ c = count;
- 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;
+ return -EPERM;
- {
- audio_buf_info info;
-
- int err = dma_ioctl (dev, cmd, (caddr_t) & info);
-
- if (err < 0)
- return err;
+ if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
+ {
+ sync_output(dev);
+ }
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ audio_mode[dev] |= AM_READ;
+ else
+ audio_mode[dev] = AM_READ;
- memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info));
- return 0;
- }
+ while (c)
+ {
+ if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l,
+ dev_nblock[dev])) < 0)
+ {
+ /* Nonblocking mode handling. Return current # of bytes */
+
+ if (dev_nblock[dev] && buf_no == -EAGAIN)
+ return p;
+
+ return buf_no;
+ }
+ if (l > c)
+ l = c;
+
+ /*
+ * Insert any local processing here.
+ */
+
+ if (local_conversion[dev] & CNV_MU_LAW)
+ {
+ /*
+ * This just allows interrupts while the conversion is running
+ */
+ sti();
- case SNDCTL_DSP_NONBLOCK:
- dev_nblock[dev] = 1;
- return 0;
- break;
+ translate_bytes(dsp_ulaw, (unsigned char *) dmabuf, l);
+ }
+ {
+ char *fixit = dmabuf;
- case SNDCTL_DSP_GETCAPS:
- {
- int info = 1; /* Revision level of this ioctl() */
+ copy_to_user(&(buf)[p], fixit, l);
+ };
- if (audio_devs[dev]->flags & DMA_DUPLEX &&
- audio_devs[dev]->open_mode == OPEN_READWRITE)
- info |= DSP_CAP_DUPLEX;
+ DMAbuf_rmchars(dev, buf_no, l);
- if (audio_devs[dev]->coproc)
- info |= DSP_CAP_COPROC;
+ p += l;
+ c -= l;
+ }
- if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */
- info |= DSP_CAP_BATCH;
+ return count - c;
+}
- if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */
- info |= DSP_CAP_TRIGGER;
+int
+audio_ioctl(int dev, struct fileinfo *file_must_not_be_used,
+ unsigned int cmd, caddr_t arg)
+{
+ int val;
- info |= DSP_CAP_MMAP;
+ /* printk( "audio_ioctl(%x, %x)\n", (int)cmd, (int)arg); */
- memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info));
- return 0;
- }
- break;
+ dev = dev >> 4;
- case SOUND_PCM_WRITE_RATE:
- val = *(int *) arg;
- return (*(int *) arg = audio_devs[dev]->d->set_speed (dev, val));
+ 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;
- case SOUND_PCM_READ_RATE:
- return (*(int *) arg = audio_devs[dev]->d->set_speed (dev, 0));
+ default:
+ return dma_ioctl(dev, cmd, arg);
+ }
+}
- case SNDCTL_DSP_STEREO:
- {
- int n;
+void
+audio_init_devices(void)
+{
+ /*
+ * NOTE! This routine could be called several times during boot.
+ */
+}
- 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;
+#endif
- return (*(int *) arg = audio_devs[dev]->d->set_channels (dev, n + 1) - 1);
- }
+void
+reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
+{
+ /*
+ * This routine breaks the physical device buffers to logical ones.
+ */
- case SOUND_PCM_WRITE_CHANNELS:
- val = *(int *) arg;
- return (*(int *) arg = audio_devs[dev]->d->set_channels (dev, val));
+ struct audio_operations *dsp_dev = audio_devs[dev];
- case SOUND_PCM_READ_CHANNELS:
- return (*(int *) arg = audio_devs[dev]->d->set_channels (dev, 0));
+ unsigned i, n;
+ unsigned sr, nc, sz, bsz;
- case SOUND_PCM_READ_BITS:
- return (*(int *) arg = audio_devs[dev]->d->set_bits (dev, 0));
+ sr = dsp_dev->d->set_speed(dev, 0);
+ nc = dsp_dev->d->set_channels(dev, 0);
+ sz = dsp_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;
+ if (sz == 8)
+ dmap->neutral_byte = NEUTRAL8;
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);
- }
-}
-
-void
-audio_init_devices (void)
-{
- /*
- * NOTE! This routine could be called several times during boot.
- */
-}
+ 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;
+ }
+ sz = sr * nc * sz;
-#endif
+ sz /= 8; /* #bits -> #bytes */
+ dmap->data_rate = sz;
-void
-reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording)
-{
- /*
- * This routine breaks the physical device buffers to logical ones.
- */
-
- struct audio_operations *dsp_dev = audio_devs[dev];
-
- unsigned i, n;
- unsigned sr, nc, sz, bsz;
-
- sr = dsp_dev->d->set_speed (dev, 0);
- nc = dsp_dev->d->set_channels (dev, 0);
- sz = dsp_dev->d->set_bits (dev, 0);
-
- if (sz == 8)
- dmap->neutral_byte = NEUTRAL8;
- else
- 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;
- }
-
- sz = sr * nc * sz;
-
- sz /= 8; /* #bits -> #bytes */
- dmap->data_rate = sz;
-
- if (!dmap->needs_reorg)
- return;
- 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 (!dmap->needs_reorg)
+ return;
+ 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 */
+ if (bsz == dmap->buffsize)
+ bsz /= 2; /* Needs at least 2 buffers */
/*
* Split the computed fragment to smaller parts. After 3.5a9
@@ -601,439 +585,429 @@
* 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))
- bsz = 1 << audio_devs[dev]->min_fragment;
- if (audio_devs[dev]->max_fragment)
- if (bsz > (1 << audio_devs[dev]->max_fragment))
- bsz = 1 << audio_devs[dev]->max_fragment;
- bsz &= ~0x07; /* Force size which is multiple of 8 bytes */
+ 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))
+ bsz = 1 << audio_devs[dev]->min_fragment;
+ if (audio_devs[dev]->max_fragment)
+ if (bsz > (1 << audio_devs[dev]->max_fragment))
+ bsz = 1 << audio_devs[dev]->max_fragment;
+ bsz &= ~0x07; /* Force size which is multiple of 8 bytes */
#ifdef OS_DMA_ALIGN_CHECK
- OS_DMA_ALIGN_CHECK (bsz);
+ OS_DMA_ALIGN_CHECK(bsz);
#endif
- n = dmap->buffsize / bsz;
- if (n > MAX_SUB_BUFFERS)
- n = MAX_SUB_BUFFERS;
- if (n > dmap->max_fragments)
- n = dmap->max_fragments;
-
- if (n < 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 */
-
- if (dmap->raw_buf)
- {
- memset (dmap->raw_buf,
- dmap->neutral_byte,
- dmap->bytes_in_use);
- }
-
- for (i = 0; i < dmap->nbufs; i++)
- {
- dmap->counts[i] = 0;
- }
+ n = dmap->buffsize / bsz;
+ if (n > MAX_SUB_BUFFERS)
+ n = MAX_SUB_BUFFERS;
+ if (n > dmap->max_fragments)
+ n = dmap->max_fragments;
- dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY;
+ if (n < 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 */
+
+ if (dmap->raw_buf)
+ {
+ memset(dmap->raw_buf,
+ dmap->neutral_byte,
+ dmap->bytes_in_use);
+ }
+ for (i = 0; i < dmap->nbufs; i++)
+ {
+ 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)
+dma_subdivide(int dev, struct dma_buffparms *dmap, caddr_t arg, 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 */
- return -EINVAL;
+ 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 */
+ return -EINVAL;
- if (fact > MAX_REALTIME_FACTOR)
- return -EINVAL;
+ if (fact > MAX_REALTIME_FACTOR)
+ return -EINVAL;
- if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
- return -EINVAL;
+ if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
+ return -EINVAL;
- dmap->subdivision = fact;
- return (*(int *) arg = fact);
+ dmap->subdivision = fact;
+ return (*(int *) arg = fact);
}
static int
-dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
+dma_set_fragment(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
{
- int bytes, count;
+ int bytes, count;
- if (fact == 0)
- return -EIO;
+ if (fact == 0)
+ return -EIO;
- if (dmap->subdivision != 0 ||
- dmap->fragment_size) /* Too late to change */
- return -EINVAL;
+ if (dmap->subdivision != 0 ||
+ dmap->fragment_size) /* Too late to change */
+ return -EINVAL;
- bytes = fact & 0xffff;
- count = (fact >> 16) & 0x7fff;
+ bytes = fact & 0xffff;
+ count = (fact >> 16) & 0x7fff;
- if (count == 0)
- count = MAX_SUB_BUFFERS;
- else if (count < MAX_SUB_BUFFERS)
- count++;
+ if (count == 0)
+ count = MAX_SUB_BUFFERS;
+ else if (count < MAX_SUB_BUFFERS)
+ count++;
- if (bytes < 4 || bytes > 17) /* <16 || > 512k */
- return -EINVAL;
+ if (bytes < 4 || bytes > 17) /* <16 || > 512k */
+ return -EINVAL;
- if (count < 2)
- return -EINVAL;
+ if (count < 2)
+ return -EINVAL;
- if (audio_devs[dev]->min_fragment > 0)
- if (bytes < audio_devs[dev]->min_fragment)
- bytes = audio_devs[dev]->min_fragment;
+ if (audio_devs[dev]->min_fragment > 0)
+ if (bytes < audio_devs[dev]->min_fragment)
+ bytes = audio_devs[dev]->min_fragment;
- if (audio_devs[dev]->max_fragment > 0)
- if (bytes > audio_devs[dev]->max_fragment)
- bytes = audio_devs[dev]->max_fragment;
+ if (audio_devs[dev]->max_fragment > 0)
+ if (bytes > audio_devs[dev]->max_fragment)
+ bytes = audio_devs[dev]->max_fragment;
#ifdef OS_DMA_MINBITS
- if (bytes < OS_DMA_MINBITS)
- bytes = OS_DMA_MINBITS;
+ if (bytes < OS_DMA_MINBITS)
+ bytes = OS_DMA_MINBITS;
#endif
- dmap->fragment_size = (1 << bytes);
- dmap->max_fragments = count;
+ dmap->fragment_size = (1 << bytes);
+ dmap->max_fragments = count;
- if (dmap->fragment_size > dmap->buffsize)
- dmap->fragment_size = dmap->buffsize;
+ if (dmap->fragment_size > dmap->buffsize)
+ dmap->fragment_size = dmap->buffsize;
- if (dmap->fragment_size == dmap->buffsize &&
- audio_devs[dev]->flags & DMA_AUTOMODE)
- 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;
+ if (dmap->fragment_size == dmap->buffsize &&
+ audio_devs[dev]->flags & DMA_AUTOMODE)
+ 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;
}
int
-dma_ioctl (int dev, unsigned int cmd, caddr_t arg)
+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;
+ 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;
+ switch (cmd)
+ {
- audio_buf_info *info = (audio_buf_info *) arg;
+ case SNDCTL_DSP_SUBDIVIDE:
+ {
+ int fact;
+ int ret = 0;
- if (cmd == SNDCTL_DSP_GETISPACE &&
- !(audio_devs[dev]->open_mode & OPEN_READ))
- return -EINVAL;
+ fact = *(int *) arg;
- if (cmd == SNDCTL_DSP_GETOSPACE &&
- !(audio_devs[dev]->open_mode & OPEN_WRITE))
- return -EINVAL;
+ 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);
- if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
- dmap = dmap_in;
+ return ret;
+ }
+ break;
- if (dmap->mapping_flags & DMA_MAP_MAPPED)
- return -EINVAL;
+ case SNDCTL_DSP_GETISPACE:
+ case SNDCTL_DSP_GETOSPACE:
+ {
+ struct dma_buffparms *dmap = dmap_out;
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev, dmap, (cmd == SNDCTL_DSP_GETISPACE));
+ audio_buf_info *info = (audio_buf_info *) arg;
- info->fragstotal = dmap->nbufs;
+ 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;
- 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)
+ case SNDCTL_DSP_SETTRIGGER:
{
- int tmp = audio_devs[dev]->d->local_qlen (dev);
-
- if (tmp && info->fragments)
- tmp--; /*
- * This buffer has been counted twice
- */
- info->fragments -= tmp;
- }
- }
- }
+ unsigned long flags;
- if (info->fragments < 0)
- info->fragments = 0;
- else if (info->fragments > dmap->nbufs)
- info->fragments = dmap->nbufs;
+ int bits;
+ int changed;
- info->fragsize = dmap->fragment_size;
- info->bytes = info->fragments * dmap->fragment_size;
+ bits = *(int *) arg;
+ bits &= audio_devs[dev]->open_mode;
- 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;
+ 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_SETTRIGGER:
- {
- unsigned long flags;
+ case SNDCTL_DSP_SETSYNCRO:
- int bits;
- int changed;
+ if (!audio_devs[dev]->d->trigger)
+ return -EINVAL;
- bits = *(int *) arg;
- bits &= audio_devs[dev]->open_mode;
+ audio_devs[dev]->d->trigger(dev, 0);
+ audio_devs[dev]->go = 0;
+ return 0;
+ break;
- if (audio_devs[dev]->d->trigger == NULL)
- return -EINVAL;
+ 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;
- 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;
- }
+ 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));
- save_flags (flags);
- cli ();
- changed = audio_devs[dev]->enable_bits ^ bits;
+ if (dmap->mapping_flags & DMA_MAP_MAPPED)
+ dmap->qlen = 0; /* Reset interrupt counter */
- if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go)
- {
- int err;
+ restore_flags(flags);
+ return 0;
+ }
+ break;
- 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;
+ 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;
- dmap_in->dma_mode = DMODE_INPUT;
- audio_devs[dev]->enable_bits = bits;
- DMAbuf_activate_recording (dev, dmap_in);
- }
+ 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;
- if ((changed & bits) & PCM_ENABLE_OUTPUT &&
- (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) &&
- audio_devs[dev]->go)
- {
+ case SNDCTL_DSP_SETFRAGMENT:
+ {
+ int fact;
+ int ret;
- if (!(dmap_out->flags & DMA_ALLOC_DONE))
- {
- reorganize_buffers (dev, dmap_out, 0);
- }
+ 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);
- 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);
- ;
- }
+ return ret;
+ }
+ break;
- audio_devs[dev]->enable_bits = bits;
- if (changed && audio_devs[dev]->d->trigger)
- {
- audio_devs[dev]->d->trigger (dev, bits * audio_devs[dev]->go);
+ default:
+ return audio_devs[dev]->d->ioctl(dev, cmd, arg);
}
- 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_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);
- }
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov