extractedLnx/linux/drivers/sound/ymfpci.c_ymf_ioctl.c
static int ymf_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct ymf_state *state = (struct ymf_state *)file->private_data;
struct ymf_dmabuf *dmabuf;
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
int val;
switch (cmd) {
case OSS_GETVERSION:
return put_user(SOUND_VERSION, (int *)arg);
case SNDCTL_DSP_RESET:
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
dmabuf = &state->wpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf->ready = 0;
dmabuf->swptr = dmabuf->hwptr;
dmabuf->count = dmabuf->total_bytes = 0;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
if (file->f_mode & FMODE_READ) {
ymf_stop_adc(state);
dmabuf = &state->rpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf->ready = 0;
dmabuf->swptr = dmabuf->hwptr;
dmabuf->count = dmabuf->total_bytes = 0;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
return 0;
case SNDCTL_DSP_SYNC:
if (file->f_mode & FMODE_WRITE) {
dmabuf = &state->wpcm.dmabuf;
if (file->f_flags & O_NONBLOCK) {
spin_lock_irqsave(&state->unit->reg_lock, flags);
if (dmabuf->count != 0 && !state->wpcm.running) {
ymf_start_dac(state);
}
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
} else {
ymf_wait_dac(state);
}
}
/* XXX What does this do for reading? dmabuf->count=0; ? */
return 0;
case SNDCTL_DSP_SPEED: /* set smaple rate */
if (get_user(val, (int *)arg))
return -EFAULT;
if (val >= 8000 && val <= 48000) {
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
dmabuf = &state->wpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf->ready = 0;
state->format.rate = val;
ymf_pcm_update_shift(&state->format);
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
if (file->f_mode & FMODE_READ) {
ymf_stop_adc(state);
dmabuf = &state->rpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf->ready = 0;
state->format.rate = val;
ymf_pcm_update_shift(&state->format);
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
}
return put_user(state->format.rate, (int *)arg);
/*
* OSS manual does not mention SNDCTL_DSP_STEREO at all.
* All channels are mono and if you want stereo, you
* play into two channels with SNDCTL_DSP_CHANNELS.
* However, mpg123 calls it. I wonder, why Michael Hipp used it.
*/
case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
if (get_user(val, (int *)arg))
return -EFAULT;
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
dmabuf = &state->wpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf->ready = 0;
state->format.voices = val ? 2 : 1;
ymf_pcm_update_shift(&state->format);
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
if (file->f_mode & FMODE_READ) {
ymf_stop_adc(state);
dmabuf = &state->rpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf->ready = 0;
state->format.voices = val ? 2 : 1;
ymf_pcm_update_shift(&state->format);
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
return 0;
case SNDCTL_DSP_GETBLKSIZE:
if (file->f_mode & FMODE_WRITE) {
if ((val = prog_dmabuf(state, 0)))
return val;
return put_user(state->wpcm.dmabuf.fragsize, (int *)arg);
}
if (file->f_mode & FMODE_READ) {
if ((val = prog_dmabuf(state, 1)))
return val;
return put_user(state->rpcm.dmabuf.fragsize, (int *)arg);
}
return -EINVAL;
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;
if (val == AFMT_S16_LE || val == AFMT_U8) {
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
dmabuf = &state->wpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf->ready = 0;
state->format.format = val;
ymf_pcm_update_shift(&state->format);
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
if (file->f_mode & FMODE_READ) {
ymf_stop_adc(state);
dmabuf = &state->rpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf->ready = 0;
state->format.format = val;
ymf_pcm_update_shift(&state->format);
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
}
return put_user(state->format.format, (int *)arg);
case SNDCTL_DSP_CHANNELS:
if (get_user(val, (int *)arg))
return -EFAULT;
/* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_CHANNELS 0x%x\n", val); */
if (val != 0) {
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
if (val == 1 || val == 2) {
spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf = &state->wpcm.dmabuf;
dmabuf->ready = 0;
state->format.voices = val;
ymf_pcm_update_shift(&state->format);
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
}
if (file->f_mode & FMODE_READ) {
ymf_stop_adc(state);
if (val == 1 || val == 2) {
spin_lock_irqsave(&state->unit->reg_lock, flags);
dmabuf = &state->rpcm.dmabuf;
dmabuf->ready = 0;
state->format.voices = val;
ymf_pcm_update_shift(&state->format);
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
}
}
}
return put_user(state->format.voices, (int *)arg);
case SNDCTL_DSP_POST:
/*
* Quoting OSS PG:
* The ioctl SNDCTL_DSP_POST is a lightweight version of
* SNDCTL_DSP_SYNC. It just tells to the driver that there
* is likely to be a pause in the output. This makes it
* possible for the device to handle the pause more
* intelligently. This ioctl doesn't block the application.
*
* The paragraph above is a clumsy way to say "flush ioctl".
* This ioctl is used by mpg123.
*/
spin_lock_irqsave(&state->unit->reg_lock, flags);
if (state->wpcm.dmabuf.count != 0 && !state->wpcm.running) {
ymf_start_dac(state);
}
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
return 0;
#if 0 /* XXX Was dummy implementation anyways. Make sense of this. */
case SNDCTL_DSP_SUBDIVIDE:
dmabuf = &state->wpcm.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;
#endif
case SNDCTL_DSP_SETFRAGMENT:
if (get_user(val, (int *)arg))
return -EFAULT;
dmabuf = &state->wpcm.dmabuf;
dmabuf->ossfragshift = val & 0xffff;
dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
if (dmabuf->ossfragshift < 4)
dmabuf->ossfragshift = 4;
if (dmabuf->ossfragshift > 15)
dmabuf->ossfragshift = 15;
if (dmabuf->ossmaxfrags < 4)
dmabuf->ossmaxfrags = 4;
return 0;
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
dmabuf = &state->wpcm.dmabuf;
if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
return val;
spin_lock_irqsave(&state->unit->reg_lock, flags);
abinfo.fragsize = dmabuf->fragsize;
abinfo.bytes = dmabuf->dmasize - dmabuf->count;
abinfo.fragstotal = dmabuf->numfrag;
abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
dmabuf = &state->rpcm.dmabuf;
if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
return val;
spin_lock_irqsave(&state->unit->reg_lock, flags);
abinfo.fragsize = dmabuf->fragsize;
abinfo.bytes = dmabuf->count;
abinfo.fragstotal = dmabuf->numfrag;
abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
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); */
return put_user(0, (int *)arg);
#if 0 /* not implememnted, yet? */
case SNDCTL_DSP_GETTRIGGER:
val = 0;
dmabuf = &state->wpcm.dmabuf;
if (file->f_mode & FMODE_READ && dmabuf->enable)
val |= PCM_ENABLE_INPUT;
if (file->f_mode & FMODE_WRITE && dmabuf->enable)
val |= PCM_ENABLE_OUTPUT;
return put_user(val, (int *)arg);
case SNDCTL_DSP_SETTRIGGER:
if (get_user(val, (int *)arg))
return -EFAULT;
if (file->f_mode & FMODE_READ) {
dmabuf = &state->rpcm.dmabuf;
if (val & PCM_ENABLE_INPUT) {
if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
return ret;
start_adc(state);
} else
stop_adc(state);
}
if (file->f_mode & FMODE_WRITE) {
dmabuf = &state->wpcm.dmabuf;
if (val & PCM_ENABLE_OUTPUT) {
if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
return ret;
start_dac(state); // sure?
} else
stop_dac(state);
}
return 0;
#endif
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
dmabuf = &state->rpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
cinfo.bytes = dmabuf->total_bytes;
cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
cinfo.ptr = dmabuf->hwptr;
/* XXX fishy - breaks invariant count=hwptr-swptr */
if (dmabuf->mapped)
dmabuf->count &= dmabuf->fragsize-1;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
dmabuf = &state->wpcm.dmabuf;
spin_lock_irqsave(&state->unit->reg_lock, flags);
cinfo.bytes = dmabuf->total_bytes;
cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
cinfo.ptr = dmabuf->hwptr;
/* XXX fishy - breaks invariant count=swptr-hwptr */
if (dmabuf->mapped)
dmabuf->count &= dmabuf->fragsize-1;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_SETDUPLEX: /* XXX TODO */
return -EINVAL;
#if 0 /* XXX implement when an app found that uses it. */
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
spin_lock_irqsave(&state->unit->reg_lock, flags);
cs_update_ptr(state);
dmabuf = &state->wpcm.dmabuf;
val = dmabuf->count;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
return put_user(val, (int *)arg);
#endif
case SOUND_PCM_READ_RATE:
return put_user(state->format.rate, (int *)arg);
case SOUND_PCM_READ_CHANNELS:
return put_user(state->format.voices, (int *)arg);
case SOUND_PCM_READ_BITS:
return put_user(AFMT_S16_LE, (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 -ENOTTY;
default:
/*
* Some programs mix up audio devices and ioctls
* or perhaps they expect "universal" ioctls,
* for instance we get SNDCTL_TMR_CONTINUE here.
* XXX Is there sound_generic_ioctl() around?
*/
}
return -ENOTTY;
}
Generated by GNU enscript 1.6.4.