extractedLnx/linux-2.6.9/drivers/usb/class/audio.c_usb_audio_ioctl.c
static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
struct usb_audio_state *s = as->state;
int __user *user_arg = (int __user *)arg;
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
int val = 0;
int val2, mapped, ret;
if (!s->usbdev)
return -EIO;
mapped = ((file->f_mode & FMODE_WRITE) && as->usbout.dma.mapped) ||
((file->f_mode & FMODE_READ) && as->usbin.dma.mapped);
#if 0
if (arg)
get_user(val, (int *)arg);
printk(KERN_DEBUG "usbaudio: usb_audio_ioctl cmd=%x arg=%lx *arg=%d\n", cmd, arg, val)
#endif
switch (cmd) {
case OSS_GETVERSION:
return put_user(SOUND_VERSION, user_arg);
case SNDCTL_DSP_SYNC:
if (file->f_mode & FMODE_WRITE)
return drain_out(as, 0/*file->f_flags & O_NONBLOCK*/);
return 0;
case SNDCTL_DSP_SETDUPLEX:
return 0;
case SNDCTL_DSP_GETCAPS:
return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER |
DSP_CAP_MMAP | DSP_CAP_BATCH, user_arg);
case SNDCTL_DSP_RESET:
if (file->f_mode & FMODE_WRITE) {
usbout_stop(as);
as->usbout.dma.rdptr = as->usbout.dma.wrptr = as->usbout.dma.count = as->usbout.dma.total_bytes = 0;
}
if (file->f_mode & FMODE_READ) {
usbin_stop(as);
as->usbin.dma.rdptr = as->usbin.dma.wrptr = as->usbin.dma.count = as->usbin.dma.total_bytes = 0;
}
return 0;
case SNDCTL_DSP_SPEED:
if (get_user(val, user_arg))
return -EFAULT;
if (val >= 0) {
if (val < 4000)
val = 4000;
if (val > 100000)
val = 100000;
if (set_format(as, file->f_mode, AFMT_QUERY, val))
return -EIO;
}
return put_user((file->f_mode & FMODE_READ) ?
as->usbin.dma.srate : as->usbout.dma.srate,
user_arg);
case SNDCTL_DSP_STEREO:
if (get_user(val, user_arg))
return -EFAULT;
val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
if (val)
val2 |= AFMT_STEREO;
else
val2 &= ~AFMT_STEREO;
if (set_format(as, file->f_mode, val2, 0))
return -EIO;
return 0;
case SNDCTL_DSP_CHANNELS:
if (get_user(val, user_arg))
return -EFAULT;
if (val != 0) {
val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
if (val == 1)
val2 &= ~AFMT_STEREO;
else
val2 |= AFMT_STEREO;
if (set_format(as, file->f_mode, val2, 0))
return -EIO;
}
val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, user_arg);
case SNDCTL_DSP_GETFMTS: /* Returns a mask */
return put_user(AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE, user_arg);
case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
if (get_user(val, user_arg))
return -EFAULT;
if (val != AFMT_QUERY) {
if (hweight32(val) != 1)
return -EINVAL;
if (!(val & (AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE)))
return -EINVAL;
val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
val |= val2 & AFMT_STEREO;
if (set_format(as, file->f_mode, val, 0))
return -EIO;
}
val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
return put_user(val2 & ~AFMT_STEREO, user_arg);
case SNDCTL_DSP_POST:
return 0;
case SNDCTL_DSP_GETTRIGGER:
val = 0;
if (file->f_mode & FMODE_READ && as->usbin.flags & FLG_RUNNING)
val |= PCM_ENABLE_INPUT;
if (file->f_mode & FMODE_WRITE && as->usbout.flags & FLG_RUNNING)
val |= PCM_ENABLE_OUTPUT;
return put_user(val, user_arg);
case SNDCTL_DSP_SETTRIGGER:
if (get_user(val, user_arg))
return -EFAULT;
if (file->f_mode & FMODE_READ) {
if (val & PCM_ENABLE_INPUT) {
if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
return ret;
if (usbin_start(as))
return -ENODEV;
} else
usbin_stop(as);
}
if (file->f_mode & FMODE_WRITE) {
if (val & PCM_ENABLE_OUTPUT) {
if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))
return ret;
if (usbout_start(as))
return -ENODEV;
} else
usbout_stop(as);
}
return 0;
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
if (!(as->usbout.flags & FLG_RUNNING) && (val = prog_dmabuf_out(as)) != 0)
return val;
spin_lock_irqsave(&as->lock, flags);
abinfo.fragsize = as->usbout.dma.fragsize;
abinfo.bytes = as->usbout.dma.dmasize - as->usbout.dma.count;
abinfo.fragstotal = as->usbout.dma.numfrag;
abinfo.fragments = abinfo.bytes >> as->usbout.dma.fragshift;
spin_unlock_irqrestore(&as->lock, flags);
return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
if (!(as->usbin.flags & FLG_RUNNING) && (val = prog_dmabuf_in(as)) != 0)
return val;
spin_lock_irqsave(&as->lock, flags);
abinfo.fragsize = as->usbin.dma.fragsize;
abinfo.bytes = as->usbin.dma.count;
abinfo.fragstotal = as->usbin.dma.numfrag;
abinfo.fragments = abinfo.bytes >> as->usbin.dma.fragshift;
spin_unlock_irqrestore(&as->lock, flags);
return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_NONBLOCK:
file->f_flags |= O_NONBLOCK;
return 0;
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
spin_lock_irqsave(&as->lock, flags);
val = as->usbout.dma.count;
spin_unlock_irqrestore(&as->lock, flags);
return put_user(val, user_arg);
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
spin_lock_irqsave(&as->lock, flags);
cinfo.bytes = as->usbin.dma.total_bytes;
cinfo.blocks = as->usbin.dma.count >> as->usbin.dma.fragshift;
cinfo.ptr = as->usbin.dma.wrptr;
if (as->usbin.dma.mapped)
as->usbin.dma.count &= as->usbin.dma.fragsize-1;
spin_unlock_irqrestore(&as->lock, flags);
if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo)))
return -EFAULT;
return 0;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
spin_lock_irqsave(&as->lock, flags);
cinfo.bytes = as->usbout.dma.total_bytes;
cinfo.blocks = as->usbout.dma.count >> as->usbout.dma.fragshift;
cinfo.ptr = as->usbout.dma.rdptr;
if (as->usbout.dma.mapped)
as->usbout.dma.count &= as->usbout.dma.fragsize-1;
spin_unlock_irqrestore(&as->lock, flags);
if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo)))
return -EFAULT;
return 0;
case SNDCTL_DSP_GETBLKSIZE:
if (file->f_mode & FMODE_WRITE) {
if ((val = prog_dmabuf_out(as)))
return val;
return put_user(as->usbout.dma.fragsize, user_arg);
}
if ((val = prog_dmabuf_in(as)))
return val;
return put_user(as->usbin.dma.fragsize, user_arg);
case SNDCTL_DSP_SETFRAGMENT:
if (get_user(val, user_arg))
return -EFAULT;
if (file->f_mode & FMODE_READ) {
as->usbin.dma.ossfragshift = val & 0xffff;
as->usbin.dma.ossmaxfrags = (val >> 16) & 0xffff;
if (as->usbin.dma.ossfragshift < 4)
as->usbin.dma.ossfragshift = 4;
if (as->usbin.dma.ossfragshift > 15)
as->usbin.dma.ossfragshift = 15;
if (as->usbin.dma.ossmaxfrags < 4)
as->usbin.dma.ossmaxfrags = 4;
}
if (file->f_mode & FMODE_WRITE) {
as->usbout.dma.ossfragshift = val & 0xffff;
as->usbout.dma.ossmaxfrags = (val >> 16) & 0xffff;
if (as->usbout.dma.ossfragshift < 4)
as->usbout.dma.ossfragshift = 4;
if (as->usbout.dma.ossfragshift > 15)
as->usbout.dma.ossfragshift = 15;
if (as->usbout.dma.ossmaxfrags < 4)
as->usbout.dma.ossmaxfrags = 4;
}
return 0;
case SNDCTL_DSP_SUBDIVIDE:
if ((file->f_mode & FMODE_READ && as->usbin.dma.subdivision) ||
(file->f_mode & FMODE_WRITE && as->usbout.dma.subdivision))
return -EINVAL;
if (get_user(val, user_arg))
return -EFAULT;
if (val != 1 && val != 2 && val != 4)
return -EINVAL;
if (file->f_mode & FMODE_READ)
as->usbin.dma.subdivision = val;
if (file->f_mode & FMODE_WRITE)
as->usbout.dma.subdivision = val;
return 0;
case SOUND_PCM_READ_RATE:
return put_user((file->f_mode & FMODE_READ) ?
as->usbin.dma.srate : as->usbout.dma.srate,
user_arg);
case SOUND_PCM_READ_CHANNELS:
val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, user_arg);
case SOUND_PCM_READ_BITS:
val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
return put_user(AFMT_IS16BIT(val2) ? 16 : 8, user_arg);
case SOUND_PCM_WRITE_FILTER:
case SNDCTL_DSP_SETSYNCRO:
case SOUND_PCM_READ_FILTER:
return -EINVAL;
}
dprintk((KERN_DEBUG "usbaudio: usb_audio_ioctl - no command found\n"));
return -ENOIOCTLCMD;
}
Generated by GNU enscript 1.6.4.