📄 ibmcsiti.c
字号:
if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) {
printk("DEBUG: ibmcsiti_dsp_write dac ready %d prog_dmabuf retcode %d \n", s->dma_dac.ready, ret);
goto out;
}
ret = 0;
add_wait_queue(&s->dma_dac.wait, &wait);
while (insamples > 0) {
spin_lock_irqsave(&s->lock, flags);
if (s->dma_dac.count < 0) {
s->dma_dac.count = 0;
s->dma_dac.swptr = s->dma_dac.hwptr;
}
swptr = s->dma_dac.swptr;
bufspace = s->dma_dac.dmasize-swptr;
/* Truncate to fit in dma buffer */
if (s->dma_dac.count + bufspace > s->dma_dac.dmasize)
bufspace = s->dma_dac.dmasize - s->dma_dac.count;
if ((bufspace <= 0) || (s->dac_free_sgdt_q == NULL))
set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&s->lock, flags);
if ((bufspace <= 0) || (s->dac_free_sgdt_q == NULL)) {
/* No room... */
if (file->f_flags & O_NONBLOCK) {
if (!ret)
ret = -EAGAIN;
goto out;
}
up(&s->dsp_sem);
schedule();
if (signal_pending(current)) {
if (!ret)
ret = -ERESTARTSYS;
goto out;
}
down(&s->dsp_sem);
if (s->dma_dac.mapped) {
ret = -ENXIO;
goto out;
}
continue;
}
/* Always 4 bytes/sample (stereo) in the DMA buffer */
outsamples = min_t(size_t, insamples, bufspace/4);
if (copy_samples_from_user(s->dma_dac.rawbuf + swptr, buffer,
outsamples, s->outstereo)) {
ret = -EFAULT;
goto out;
}
/* FIXME: replace with consistent_sync()? */
dma_cache_wback_inv((unsigned long)(s->dma_dac.rawbuf + swptr),
outsamples*4);
swptr = (swptr + outsamples*4) % s->dma_dac.dmasize; /* Wrap */
spin_lock_irqsave(&s->lock, flags);
s->dma_dac.swptr = swptr;
s->dma_dac.count += outsamples * 4;
s->dma_dac.endcleared = 0; /* Remember to zero clear
* one fragment at the
* end */
s->dma_dac.sg_count += outsamples*4;
spin_unlock_irqrestore(&s->lock, flags);
/* FIXME: broken if odd byte written. Also, format is
* assumed 16 bit */
insamples -= outsamples;
buffer += outsamples * bytespersample;
ret += outsamples * bytespersample;
if (s->dma_dac.enabled) {
DBG(printk("bottom start_dac\n"));
DBG(printk("dma_dac.count %d, dma_dac.sg_count %d\n",
s->dma_dac.count, s->dma_dac.sg_count));
start_dac(s);
DBG(printk("dma_dac.count %d, dma_dac.sg_count %d\n",
s->dma_dac.count, s->dma_dac.sg_count));
}
}
out:
up(&s->dsp_sem);
remove_wait_queue(&s->dma_dac.wait, &wait);
set_current_state(TASK_RUNNING);
DBG(printk("swptr %8.8x hwptr %8.8x sg_count %d\n", s->dma_dac.swptr,
s->dma_dac.hwptr, s->dma_dac.sg_count);)
return ret;
}
static unsigned int ibmcsiti_dsp_poll(struct file *file,
struct poll_table_struct *wait)
{
struct ibmcsiti_state *s = file->private_data;
unsigned long flags;
unsigned int mask = 0;
VALIDATE_STATE(s);
if (file->f_mode & FMODE_WRITE) {
if (!s->dma_dac.ready && prog_dmabuf_dac(s))
return 0;
poll_wait(file, &s->dma_dac.wait, wait);
}
if (file->f_mode & FMODE_READ) {
if (!s->dma_adc.ready && prog_dmabuf_adc(s))
return 0;
poll_wait(file, &s->dma_adc.wait, wait);
}
spin_lock_irqsave(&s->lock, flags);
ibmcsiti_update_ptr(s);
if (file->f_mode & FMODE_READ) {
if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
mask |= POLLIN | POLLRDNORM;
}
if (file->f_mode & FMODE_WRITE) {
if (s->dma_dac.mapped) {
if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
mask |= POLLOUT | POLLWRNORM;
} else {
if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
mask |= POLLOUT | POLLWRNORM;
}
}
spin_unlock_irqrestore(&s->lock, flags);
return mask;
}
static int ibmcsiti_dsp_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct ibmcsiti_state *s = (struct ibmcsiti_state *)file->private_data;
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
int count;
int val, ret;
VALIDATE_STATE(s);
switch (cmd) {
case OSS_GETVERSION:
return put_user(SOUND_VERSION, (int *)arg);
case SNDCTL_DSP_SYNC:
printk(KERN_DEBUG "SNDCTL_DSP_SYNC\n");
if (file->f_mode & FMODE_WRITE)
return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
return 0;
case SNDCTL_DSP_SETDUPLEX:
printk(KERN_DEBUG "SNDCTL_DSP_SETDUPLEX\n");
return 0;
case SNDCTL_DSP_GETCAPS:
printk(KERN_DEBUG "SNDCTL_DSP_GETCAPS\n");
return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
case SNDCTL_DSP_RESET:
printk(KERN_DEBUG "SNDCTL_DSP_RESET\n");
if (file->f_mode & FMODE_WRITE) {
stop_dac(s);
synchronize_irq();
s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count
= s->dma_dac.total_bytes = 0;
}
if (file->f_mode & FMODE_READ) {
stop_adc(s);
synchronize_irq();
s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count
= s->dma_adc.total_bytes = 0;
}
return 0;
case SNDCTL_DSP_SPEED:
if (get_user(val, (int *)arg))
return -EFAULT;
printk(KERN_DEBUG "SNDCTL_DSP_SPEED arg=%d\n", val);
/* FIXME: Hardcoded for now */
return put_user(IBMCSI_DEFAULT_SAMPLING_RATE, (int *)arg);
case SNDCTL_DSP_STEREO:
if (get_user(val, (int *)arg))
return -EFAULT;
printk(KERN_DEBUG "SNDCTL_DSP_STEREO arg=%d\n", val);
if (file->f_mode & FMODE_WRITE) {
down(&s->dsp_sem);
if (val)
s->outstereo = 1;
else
s->outstereo = 0;
if (put_user(s->outstereo, (int *)arg) != 0)
ret = -EFAULT;
up(&s->dsp_sem);
} else {
if (put_user(0, (int *)arg) != 0)
ret = -EFAULT;
}
return ret;
case SNDCTL_DSP_CHANNELS:
if (get_user(val, (int *)arg))
return -EFAULT;
printk(KERN_DEBUG "SNDCTL_DSP_CHANNELS arg=%d\n", val);
if (file->f_mode & FMODE_WRITE) {
if (val >= 2) {
s->outstereo = 1;
ret = put_user(2, (int *)arg);
} else {
s->outstereo = 0;
ret = put_user(1, (int *)arg);
}
} else {
ret = put_user(1, (int *)arg);
}
if (ret)
return -EFAULT;
return 0;
case SNDCTL_DSP_GETFMTS: /* Returns a mask */
printk(KERN_DEBUG "SNDCTL_DSP_GETFMTS\n");
return put_user(AFMT_S16_BE, (int *)arg);
case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
if (get_user(val, (int *)arg))
return -EFAULT;
printk(KERN_DEBUG "SNDCTL_DSP_SETFMT arg=%d\n", val);
return put_user(AFMT_S16_BE, (int *)arg);
case SNDCTL_DSP_POST:
return 0;
case SNDCTL_DSP_GETTRIGGER:
printk(KERN_DEBUG "SNDCTL_DSP_GETTRIGGER\n");
val = 0;
if ((file->f_mode) & FMODE_READ && (s->state & IBMCSI_ADC_RUNNING))
val |= PCM_ENABLE_INPUT;
if ((file->f_mode & FMODE_WRITE) && (s->state & IBMCSI_DAC_RUNNING))
val |= PCM_ENABLE_OUTPUT;
return put_user(val, (int *)arg);
case SNDCTL_DSP_SETTRIGGER:
if (get_user(val, (int *)arg))
return -EFAULT;
printk(KERN_DEBUG "SNDCTL_DSP_SETTRIGGER arg=%d\n", val);
if (file->f_mode & FMODE_READ) {
if (val & PCM_ENABLE_INPUT) {
if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
return ret;
s->dma_adc.enabled = 1;
start_adc(s);
} else {
s->dma_adc.enabled = 0;
stop_adc(s);
}
}
if (file->f_mode & FMODE_WRITE) {
if (val & PCM_ENABLE_OUTPUT) {
if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
return ret;
s->dma_dac.enabled = 1;
start_dac(s);
} else {
s->dma_dac.enabled = 0;
stop_dac(s);
}
}
return 0;
case SNDCTL_DSP_GETOSPACE:
printk(KERN_DEBUG "SNDCTL_DSP_GETOSPACE\n");
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
ibmcsiti_update_ptr(s);
abinfo.fragsize = s->dma_dac.fragsize;
count = s->dma_dac.count;
if (count < 0)
count = 0;
abinfo.bytes = s->dma_dac.dmasize - count;
abinfo.fragstotal = s->dma_dac.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo))
? -EFAULT : 0;
case SNDCTL_DSP_GETISPACE:
printk(KERN_DEBUG "SNDCTL_DSP_GETISPACE\n");
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
ibmcsiti_update_ptr(s);
abinfo.fragsize = s->dma_adc.fragsize;
count = s->dma_adc.count;
if (count < 0)
count = 0;
abinfo.bytes = count;
abinfo.fragstotal = s->dma_adc.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo))
? -EFAULT : 0;
case SNDCTL_DSP_NONBLOCK:
printk(KERN_DEBUG "SNDCTL_DSP_NONBLOCK\n");
file->f_flags |= O_NONBLOCK;
return 0;
case SNDCTL_DSP_GETODELAY:
printk(KERN_DEBUG "SNDCTL_DSP_GETODELAY\n");
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
ibmcsiti_update_ptr(s);
count = s->dma_dac.count;
spin_unlock_irqrestore(&s->lock, flags);
if (count < 0)
count = 0;
return put_user(count, (int *)arg);
case SNDCTL_DSP_GETIPTR:
printk(KERN_DEBUG "SNDCTL_DSP_GETIPTR\n");
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
ibmcsiti_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
count = s->dma_adc.count;
if (count < 0)
count = 0;
cinfo.blocks = count >> s->dma_adc.fragshift;
cinfo.ptr = s->dma_adc.hwptr;
if (s->dma_adc.mapped)
s->dma_adc.count &= s->dma_adc.fragsize-1;
spin_unlock_irqrestore(&s->lock, flags);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo))
? -EFAULT : 0;
case SNDCTL_DSP_GETOPTR:
printk(KERN_DEBUG "SNDCTL_DSP_GETOPTR\n");
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
ibmcsiti_update_ptr(s);
cinfo.bytes = s->dma_dac.total_bytes;
count = s->dma_dac.count;
if (count < 0)
count = 0;
cinfo.blocks = count >> s->dma_dac.fragshift;
cinfo.ptr = s->dma_dac.hwptr;
if (s->dma_dac.mapped)
s->dma_dac.count &= s->dma_dac.fragsize-1;
spin_unlock_irqrestore(&s->lock, flags);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo))
? -EFAULT : 0;
case SNDCTL_DSP_GETBLKSIZE:
printk(KERN_DEBUG "SNDCTL_DSP_GETBLKSIZE\n");
if (file->f_mode & FMODE_WRITE) {
if ((val = prog_dmabuf_dac(s)))
return val;
return put_user(s->dma_dac.fragsize, (int *)arg);
}
if ((val = prog_dmabuf_adc(s)))
return val;
return put_user(s->dma_adc.fragsize, (int *)arg);
case SNDCTL_DSP_SETFRAGMENT:
if (get_user(val, (int *)arg))
return -EFAULT;
printk(KERN_DEBUG "SNDCTL_DSP_SETFRAGMENT arg=%d\n", val);
if (file->f_mode & FMODE_READ) {
s->dma_adc.ossfragshift = val & 0xffff;
s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
if (s->dma_adc.ossfragshift < 4)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -