patch-2.1.77 linux/drivers/sound/audio.c
Next file: linux/drivers/sound/dmabuf.c
Previous file: linux/drivers/sound/ad1848.c
Back to the patch index
Back to the overall index
- Lines: 877
- Date:
Tue Dec 30 11:04:27 1997
- Orig file:
v2.1.76/linux/drivers/sound/audio.c
- Orig date:
Sun Dec 21 22:36:15 1997
diff -u --recursive --new-file v2.1.76/linux/drivers/sound/audio.c linux/drivers/sound/audio.c
@@ -11,6 +11,9 @@
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
+/*
+ * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
+ */
#include <linux/config.h>
@@ -345,197 +348,157 @@
}
int audio_ioctl(int dev, struct fileinfo *file_must_not_be_used,
- unsigned int cmd, caddr_t arg)
+ unsigned int cmd, caddr_t arg)
{
- int val;
+ int val, info, count;
+ unsigned long flags;
+ struct dma_buffparms *dmap;
dev = dev >> 4;
- if (((cmd >> 8) & 0xff) == 'C')
- {
+ 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(KERN_DEBUG"/dev/dsp%d: No coprocessor for this device\n", dev); */
+ 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);
+ } else switch (cmd) {
+ case SNDCTL_DSP_SYNC:
+ if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
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);
+ 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_RESET:
- audio_mode[dev] = AM_NONE;
- DMAbuf_reset(dev);
+ 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_GETFMTS:
- return (*(int *) arg = audio_devs[dev]->format_mask);
-
- 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;
+ case SNDCTL_DSP_RESET:
+ audio_mode[dev] = AM_NONE;
+ DMAbuf_reset(dev);
+ return 0;
- memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
- return 0;
- }
+ case SNDCTL_DSP_GETFMTS:
+ val = audio_devs[dev]->format_mask;
+ return __put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_SETFMT:
+ if (__get_user(val, (int *)arg))
+ return -EFAULT;
+ val = set_format(dev, val);
+ return __put_user(val, (int *)arg);
- case SNDCTL_DSP_NONBLOCK:
- dev_nblock[dev] = 1;
+ 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;
+ return dma_ioctl(dev, cmd, arg);
+
+ 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 dma_ioctl(dev, cmd, arg);
+
+ case SNDCTL_DSP_NONBLOCK:
+ dev_nblock[dev] = 1;
+ return 0;
- case SNDCTL_DSP_GETCAPS:
- {
- int info = 1; /* Revision level of this ioctl() */
-
+ case SNDCTL_DSP_GETCAPS:
+ info = 1 | DSP_CAP_MMAP; /* Revision level of this ioctl() */
if (audio_devs[dev]->flags & DMA_DUPLEX &&
- audio_devs[dev]->open_mode == OPEN_READWRITE)
- info |= DSP_CAP_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;
- }
-
- 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(KERN_DENUG "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;
-
- 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;
-
- case SNDCTL_DSP_GETODELAY:
- {
- int count;
- unsigned long flags;
- struct dma_buffparms *dmap = audio_devs[dev]->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;
-
- default:
- return dma_ioctl(dev, cmd, arg);
+ return __put_user(info, (int *)arg);
+
+ case SOUND_PCM_WRITE_RATE:
+ if (__get_user(val, (int *)arg))
+ return -EFAULT;
+ val = audio_devs[dev]->d->set_speed(dev, val);
+ return __put_user(val, (int *)arg);
+
+ case SOUND_PCM_READ_RATE:
+ val = audio_devs[dev]->d->set_speed(dev, 0);
+ return __put_user(val, (int *)arg);
+
+ 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;
+ return __put_user(val, (int *)arg);
+
+ case SOUND_PCM_WRITE_CHANNELS:
+ if (__get_user(val, (int *)arg))
+ return -EFAULT;
+ val = audio_devs[dev]->d->set_channels(dev, val);
+ return __put_user(val, (int *)arg);
+
+ case SOUND_PCM_READ_CHANNELS:
+ val = audio_devs[dev]->d->set_channels(dev, 0);
+ return __put_user(val, (int *)arg);
+
+ case SOUND_PCM_READ_BITS:
+ val = audio_devs[dev]->d->set_bits(dev, 0);
+ return __put_user(val, (int *)arg);
+
+ 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))
+ return __put_user(0, (int *)arg);
+
+ 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 __put_user(count, (int *)arg);
+
+ default:
+ return dma_ioctl(dev, cmd, arg);
}
}
@@ -676,14 +639,13 @@
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)
- {
+ if (fact == 0) {
fact = dmap->subdivision;
if (fact == 0)
fact = 1;
- return (*(int *) arg = fact);
+ return fact;
}
if (dmap->subdivision != 0 || dmap->fragment_size) /* Too late to change */
return -EINVAL;
@@ -695,10 +657,10 @@
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;
@@ -747,311 +709,223 @@
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)
{
-
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);
-
+ 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;
- }
- 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 (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;
+ return __put_user(ret, (int *)arg);
- 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;
- }
+ 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;
- }
}
- 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(KERN_WARNING "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);
- }
+ 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 __copy_to_user(arg, &info, sizeof(info));
+
+ 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;
-
- 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:
- return (*(int *) arg = audio_devs[dev]->enable_bits);
-
- 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);
+ DMAbuf_activate_recording(dev, dmap_in);
}
-
- 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:
- {
- 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);
+ 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_SETFRAGMENT:
- {
- int fact;
- int ret = 0;
+ case SNDCTL_DSP_GETTRIGGER:
+ ret = audio_devs[dev]->enable_bits;
+ return __put_user(ret, (int *)arg);
+
+ 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;
- fact = *(int *) arg;
- if (audio_devs[dev]->open_mode & OPEN_WRITE)
- ret = dma_set_fragment(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_set_fragment(dev, dmap_in, arg, fact);
+ 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);
+ return __copy_to_user(arg, &cinfo, sizeof(cinfo));
+
+ 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);
+ return __copy_to_user(arg, &cinfo, sizeof(cinfo));
+
+ case SNDCTL_DSP_GETODELAY:
+ if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+ return -EINVAL;
+ if (!(dmap_out->flags & DMA_ALLOC_DONE))
+ return __put_user(0, (int *)arg);
+ 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);
+ return __put_user(count, (int *)arg);
+
+ 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;
+ return __put_user(ret, (int *)arg);
+
+ 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;
- }
- break;
+ 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;
+ return __put_user(ret, (int *)arg);
- default:
- return audio_devs[dev]->d->ioctl(dev, cmd, arg);
+ default:
+ if (!audio_devs[dev]->d->ioctl)
+ return -EINVAL;
+ 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