extractedLnx/linux-2.4.37/drivers/sound/cs46xx.c_cs_ioctl.c
static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct cs_card *card = (struct cs_card *)file->private_data;
struct cs_state *state;
struct dmabuf *dmabuf=0;
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
int val, valsave, mapped, ret;
state = (struct cs_state *)card->states[0];
if(state)
{
dmabuf = &state->dmabuf;
mapped = (file->f_mode & FMODE_READ) && dmabuf->mapped;
}
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
mapped |= (file->f_mode & FMODE_WRITE) && dmabuf->mapped;
}
#if CSDEBUG
printioctl(cmd);
#endif
switch (cmd)
{
case OSS_GETVERSION:
return put_user(SOUND_VERSION, (int *)arg);
case SNDCTL_DSP_RESET:
/* FIXME: spin_lock ? */
if (file->f_mode & FMODE_WRITE) {
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
stop_dac(state);
synchronize_irq();
dmabuf->ready = 0;
resync_dma_ptrs(state);
dmabuf->swptr = dmabuf->hwptr = 0;
dmabuf->count = dmabuf->total_bytes = 0;
dmabuf->blocks = 0;
dmabuf->SGok = 0;
}
}
if (file->f_mode & FMODE_READ) {
state = (struct cs_state *)card->states[0];
if(state)
{
dmabuf = &state->dmabuf;
stop_adc(state);
synchronize_irq();
resync_dma_ptrs(state);
dmabuf->ready = 0;
dmabuf->swptr = dmabuf->hwptr = 0;
dmabuf->count = dmabuf->total_bytes = 0;
dmabuf->blocks = 0;
dmabuf->SGok = 0;
}
}
CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_RESET()-\n") );
return 0;
case SNDCTL_DSP_SYNC:
if (file->f_mode & FMODE_WRITE)
return drain_dac(state, file->f_flags & O_NONBLOCK);
return 0;
case SNDCTL_DSP_SPEED: /* set sample rate */
if (get_user(val, (int *)arg))
return -EFAULT;
if (val >= 0) {
if (file->f_mode & FMODE_READ) {
state = (struct cs_state *)card->states[0];
if(state)
{
dmabuf = &state->dmabuf;
stop_adc(state);
dmabuf->ready = 0;
dmabuf->SGok = 0;
cs_set_adc_rate(state, val);
cs_set_divisor(dmabuf);
}
}
if (file->f_mode & FMODE_WRITE) {
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
stop_dac(state);
dmabuf->ready = 0;
dmabuf->SGok = 0;
cs_set_dac_rate(state, val);
cs_set_divisor(dmabuf);
}
}
CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
"cs46xx: cs_ioctl() DSP_SPEED %s %s %d\n",
file->f_mode & FMODE_WRITE ? "DAC" : "",
file->f_mode & FMODE_READ ? "ADC" : "",
dmabuf->rate ) );
return put_user(dmabuf->rate, (int *)arg);
}
return put_user(0, (int *)arg);
case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
if (get_user(val, (int *)arg))
return -EFAULT;
if (file->f_mode & FMODE_WRITE) {
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
stop_dac(state);
dmabuf->ready = 0;
dmabuf->SGok = 0;
if(val)
dmabuf->fmt |= CS_FMT_STEREO;
else
dmabuf->fmt &= ~CS_FMT_STEREO;
cs_set_divisor(dmabuf);
CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
"cs46xx: DSP_STEREO() DAC %s\n",
(dmabuf->fmt & CS_FMT_STEREO) ?
"STEREO":"MONO") );
}
}
if (file->f_mode & FMODE_READ) {
state = (struct cs_state *)card->states[0];
if(state)
{
dmabuf = &state->dmabuf;
stop_adc(state);
dmabuf->ready = 0;
dmabuf->SGok = 0;
if(val)
dmabuf->fmt |= CS_FMT_STEREO;
else
dmabuf->fmt &= ~CS_FMT_STEREO;
cs_set_divisor(dmabuf);
CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
"cs46xx: DSP_STEREO() ADC %s\n",
(dmabuf->fmt & CS_FMT_STEREO) ?
"STEREO":"MONO") );
}
}
return 0;
case SNDCTL_DSP_GETBLKSIZE:
if (file->f_mode & FMODE_WRITE) {
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
if ((val = prog_dmabuf(state)))
return val;
return put_user(dmabuf->fragsize, (int *)arg);
}
}
if (file->f_mode & FMODE_READ) {
state = (struct cs_state *)card->states[0];
if(state)
{
dmabuf = &state->dmabuf;
if ((val = prog_dmabuf(state)))
return val;
return put_user(dmabuf->fragsize/dmabuf->divisor,
(int *)arg);
}
}
return put_user(0, (int *)arg);
case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
return put_user(AFMT_S16_LE | AFMT_U8, (int *)arg);
case SNDCTL_DSP_SETFMT: /* Select sample format */
if (get_user(val, (int *)arg))
return -EFAULT;
CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
"cs46xx: cs_ioctl() DSP_SETFMT %s %s %s %s\n",
file->f_mode & FMODE_WRITE ? "DAC" : "",
file->f_mode & FMODE_READ ? "ADC" : "",
val == AFMT_S16_LE ? "16Bit Signed" : "",
val == AFMT_U8 ? "8Bit Unsigned" : "") );
valsave = val;
if (val != AFMT_QUERY) {
if(val==AFMT_S16_LE || val==AFMT_U8)
{
if (file->f_mode & FMODE_WRITE) {
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
stop_dac(state);
dmabuf->ready = 0;
dmabuf->SGok = 0;
if(val==AFMT_S16_LE)
dmabuf->fmt |= CS_FMT_16BIT;
else
dmabuf->fmt &= ~CS_FMT_16BIT;
cs_set_divisor(dmabuf);
if((ret = prog_dmabuf(state)))
return ret;
}
}
if (file->f_mode & FMODE_READ) {
val = valsave;
state = (struct cs_state *)card->states[0];
if(state)
{
dmabuf = &state->dmabuf;
stop_adc(state);
dmabuf->ready = 0;
dmabuf->SGok = 0;
if(val==AFMT_S16_LE)
dmabuf->fmt |= CS_FMT_16BIT;
else
dmabuf->fmt &= ~CS_FMT_16BIT;
cs_set_divisor(dmabuf);
if((ret = prog_dmabuf(state)))
return ret;
}
}
}
else
{
CS_DBGOUT(CS_IOCTL | CS_ERROR, 2, printk(
"cs46xx: DSP_SETFMT() Unsupported format (0x%x)\n",
valsave) );
}
}
else
{
if(file->f_mode & FMODE_WRITE)
{
state = (struct cs_state *)card->states[1];
if(state)
dmabuf = &state->dmabuf;
}
else if(file->f_mode & FMODE_READ)
{
state = (struct cs_state *)card->states[0];
if(state)
dmabuf = &state->dmabuf;
}
}
if(dmabuf)
{
if(dmabuf->fmt & CS_FMT_16BIT)
return put_user(AFMT_S16_LE, (int *)arg);
else
return put_user(AFMT_U8, (int *)arg);
}
return put_user(0, (int *)arg);
case SNDCTL_DSP_CHANNELS:
if (get_user(val, (int *)arg))
return -EFAULT;
if (val != 0) {
if (file->f_mode & FMODE_WRITE) {
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
stop_dac(state);
dmabuf->ready = 0;
dmabuf->SGok = 0;
if(val>1)
dmabuf->fmt |= CS_FMT_STEREO;
else
dmabuf->fmt &= ~CS_FMT_STEREO;
cs_set_divisor(dmabuf);
if (prog_dmabuf(state))
return 0;
}
}
if (file->f_mode & FMODE_READ) {
state = (struct cs_state *)card->states[0];
if(state)
{
dmabuf = &state->dmabuf;
stop_adc(state);
dmabuf->ready = 0;
dmabuf->SGok = 0;
if(val>1)
dmabuf->fmt |= CS_FMT_STEREO;
else
dmabuf->fmt &= ~CS_FMT_STEREO;
cs_set_divisor(dmabuf);
if (prog_dmabuf(state))
return 0;
}
}
}
return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1,
(int *)arg);
case SNDCTL_DSP_POST:
/*
* There will be a longer than normal pause in the data.
* so... do nothing, because there is nothing that we can do.
*/
return 0;
case SNDCTL_DSP_SUBDIVIDE:
if (file->f_mode & FMODE_WRITE) {
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
if (dmabuf->subdivision)
return -EINVAL;
if (get_user(val, (int *)arg))
return -EFAULT;
if (val != 1 && val != 2)
return -EINVAL;
dmabuf->subdivision = val;
}
}
if (file->f_mode & FMODE_READ) {
state = (struct cs_state *)card->states[0];
if(state)
{
dmabuf = &state->dmabuf;
if (dmabuf->subdivision)
return -EINVAL;
if (get_user(val, (int *)arg))
return -EFAULT;
if (val != 1 && val != 2)
return -EINVAL;
dmabuf->subdivision = val;
}
}
return 0;
case SNDCTL_DSP_SETFRAGMENT:
if (get_user(val, (int *)arg))
return -EFAULT;
if (file->f_mode & FMODE_WRITE) {
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
dmabuf->ossfragshift = val & 0xffff;
dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
}
}
if (file->f_mode & FMODE_READ) {
state = (struct cs_state *)card->states[0];
if(state)
{
dmabuf = &state->dmabuf;
dmabuf->ossfragshift = val & 0xffff;
dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
}
}
return 0;
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
spin_lock_irqsave(&state->card->lock, flags);
cs_update_ptr(card, CS_TRUE);
abinfo.fragsize = dmabuf->fragsize;
abinfo.fragstotal = dmabuf->numfrag;
/*
* for mmap we always have total space available
*/
if (dmabuf->mapped)
abinfo.bytes = dmabuf->dmasize;
else
abinfo.bytes = dmabuf->dmasize - dmabuf->count;
abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
spin_unlock_irqrestore(&state->card->lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
}
return -ENODEV;
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
state = (struct cs_state *)card->states[0];
if(state)
{
dmabuf = &state->dmabuf;
spin_lock_irqsave(&state->card->lock, flags);
cs_update_ptr(card, CS_TRUE);
abinfo.fragsize = dmabuf->fragsize/dmabuf->divisor;
abinfo.bytes = dmabuf->count/dmabuf->divisor;
abinfo.fragstotal = dmabuf->numfrag;
abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
spin_unlock_irqrestore(&state->card->lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
}
return -ENODEV;
case SNDCTL_DSP_NONBLOCK:
file->f_flags |= O_NONBLOCK;
return 0;
case SNDCTL_DSP_GETCAPS:
return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
(int *)arg);
case SNDCTL_DSP_GETTRIGGER:
val = 0;
CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_GETTRIGGER()+\n") );
if (file->f_mode & FMODE_WRITE)
{
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
if(dmabuf->enable & DAC_RUNNING)
val |= PCM_ENABLE_INPUT;
}
}
if (file->f_mode & FMODE_READ)
{
if(state)
{
state = (struct cs_state *)card->states[0];
dmabuf = &state->dmabuf;
if(dmabuf->enable & ADC_RUNNING)
val |= PCM_ENABLE_OUTPUT;
}
}
CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_GETTRIGGER()- val=0x%x\n",val) );
return put_user(val, (int *)arg);
case SNDCTL_DSP_SETTRIGGER:
if (get_user(val, (int *)arg))
return -EFAULT;
if (file->f_mode & FMODE_READ) {
state = (struct cs_state *)card->states[0];
if(state)
{
dmabuf = &state->dmabuf;
if (val & PCM_ENABLE_INPUT) {
if (!dmabuf->ready && (ret = prog_dmabuf(state)))
return ret;
start_adc(state);
} else
stop_adc(state);
}
}
if (file->f_mode & FMODE_WRITE) {
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
if (val & PCM_ENABLE_OUTPUT) {
if (!dmabuf->ready && (ret = prog_dmabuf(state)))
return ret;
start_dac(state);
} else
stop_dac(state);
}
}
return 0;
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
state = (struct cs_state *)card->states[0];
if(state)
{
dmabuf = &state->dmabuf;
spin_lock_irqsave(&state->card->lock, flags);
cs_update_ptr(card, CS_TRUE);
cinfo.bytes = dmabuf->total_bytes/dmabuf->divisor;
cinfo.blocks = dmabuf->count/dmabuf->divisor >> dmabuf->fragshift;
cinfo.ptr = dmabuf->hwptr/dmabuf->divisor;
spin_unlock_irqrestore(&state->card->lock, flags);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
}
return -ENODEV;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
spin_lock_irqsave(&state->card->lock, flags);
cs_update_ptr(card, CS_TRUE);
cinfo.bytes = dmabuf->total_bytes;
if (dmabuf->mapped)
{
cinfo.blocks = (cinfo.bytes >> dmabuf->fragshift)
- dmabuf->blocks;
CS_DBGOUT(CS_PARMS, 8,
printk("total_bytes=%d blocks=%d dmabuf->blocks=%d\n",
cinfo.bytes,cinfo.blocks,dmabuf->blocks) );
dmabuf->blocks = cinfo.bytes >> dmabuf->fragshift;
}
else
{
cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
}
cinfo.ptr = dmabuf->hwptr;
CS_DBGOUT(CS_PARMS, 4, printk(
"cs46xx: GETOPTR bytes=%d blocks=%d ptr=%d\n",
cinfo.bytes,cinfo.blocks,cinfo.ptr) );
spin_unlock_irqrestore(&state->card->lock, flags);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
}
return -ENODEV;
case SNDCTL_DSP_SETDUPLEX:
return 0;
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
spin_lock_irqsave(&state->card->lock, flags);
cs_update_ptr(card, CS_TRUE);
val = dmabuf->count;
spin_unlock_irqrestore(&state->card->lock, flags);
}
else
val = 0;
return put_user(val, (int *)arg);
case SOUND_PCM_READ_RATE:
if(file->f_mode & FMODE_READ)
state = (struct cs_state *)card->states[0];
else
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
return put_user(dmabuf->rate, (int *)arg);
}
return put_user(0, (int *)arg);
case SOUND_PCM_READ_CHANNELS:
if(file->f_mode & FMODE_READ)
state = (struct cs_state *)card->states[0];
else
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1,
(int *)arg);
}
return put_user(0, (int *)arg);
case SOUND_PCM_READ_BITS:
if(file->f_mode & FMODE_READ)
state = (struct cs_state *)card->states[0];
else
state = (struct cs_state *)card->states[1];
if(state)
{
dmabuf = &state->dmabuf;
return put_user((dmabuf->fmt & CS_FMT_16BIT) ?
AFMT_S16_LE : AFMT_U8, (int *)arg);
}
return put_user(0, (int *)arg);
case SNDCTL_DSP_MAPINBUF:
case SNDCTL_DSP_MAPOUTBUF:
case SNDCTL_DSP_SETSYNCRO:
case SOUND_PCM_WRITE_FILTER:
case SOUND_PCM_READ_FILTER:
return -EINVAL;
}
return -EINVAL;
}
Generated by GNU enscript 1.6.4.