📄 cmpci.c
字号:
s->mix.vol[volidx[i]-1] = val; return put_user(s->mix.vol[volidx[i]-1], p); }}/* --------------------------------------------------------------------- */static int cm_open_mixdev(struct inode *inode, struct file *file){ int minor = iminor(inode); struct list_head *list; struct cm_state *s; for (list = devs.next; ; list = list->next) { if (list == &devs) return -ENODEV; s = list_entry(list, struct cm_state, devs); if (s->dev_mixer == minor) break; } VALIDATE_STATE(s); file->private_data = s; return nonseekable_open(inode, file);}static int cm_release_mixdev(struct inode *inode, struct file *file){ struct cm_state *s = (struct cm_state *)file->private_data; VALIDATE_STATE(s); return 0;}static int cm_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return mixer_ioctl((struct cm_state *)file->private_data, cmd, arg);}static /*const*/ struct file_operations cm_mixer_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .ioctl = cm_ioctl_mixdev, .open = cm_open_mixdev, .release = cm_release_mixdev,};/* --------------------------------------------------------------------- */static int drain_dac(struct cm_state *s, int nonblock){ DECLARE_WAITQUEUE(wait, current); unsigned long flags; int count, tmo; if (s->dma_dac.mapped || !s->dma_dac.ready) return 0; add_wait_queue(&s->dma_dac.wait, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->dma_dac.count; spin_unlock_irqrestore(&s->lock, flags); if (count <= 0) break; if (signal_pending(current)) break; if (nonblock) { remove_wait_queue(&s->dma_dac.wait, &wait); set_current_state(TASK_RUNNING); return -EBUSY; } tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac; tmo >>= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK]; if (!schedule_timeout(tmo + 1)) DBG(printk(KERN_DEBUG "cmpci: dma timed out??\n");) } remove_wait_queue(&s->dma_dac.wait, &wait); set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; return 0;}/* --------------------------------------------------------------------- */static ssize_t cm_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos){ struct cm_state *s = (struct cm_state *)file->private_data; DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned swptr; int cnt; VALIDATE_STATE(s); if (s->dma_adc.mapped) return -ENXIO; if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) return ret; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; ret = 0; add_wait_queue(&s->dma_adc.wait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); swptr = s->dma_adc.swptr; cnt = s->dma_adc.dmasize-swptr; if (s->dma_adc.count < cnt) cnt = s->dma_adc.count; if (cnt <= 0) __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { if (s->dma_adc.enabled) start_adc(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; goto out; } if (!schedule_timeout(HZ)) { printk(KERN_DEBUG "cmpci: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, s->dma_adc.hwptr, s->dma_adc.swptr); spin_lock_irqsave(&s->lock, flags); stop_adc_unlocked(s); set_dmaadc(s, s->dma_adc.dmaaddr, s->dma_adc.dmasamples); /* program sample counts */ set_countadc(s, s->dma_adc.fragsamples); s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; spin_unlock_irqrestore(&s->lock, flags); } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; goto out; } continue; } if (s->status & DO_BIGENDIAN_R) { int i, err; unsigned char *src; char __user *dst = buffer; unsigned char data[2]; src = (unsigned char *) (s->dma_adc.rawbuf + swptr); // copy left/right sample at one time for (i = 0; i < cnt / 2; i++) { data[0] = src[1]; data[1] = src[0]; if ((err = __put_user(data[0], dst++))) { ret = err; goto out; } if ((err = __put_user(data[1], dst++))) { ret = err; goto out; } src += 2; } } else if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { if (!ret) ret = -EFAULT; goto out; } swptr = (swptr + cnt) % s->dma_adc.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_adc.swptr = swptr; s->dma_adc.count -= cnt; count -= cnt; buffer += cnt; ret += cnt; if (s->dma_adc.enabled) start_adc_unlocked(s); spin_unlock_irqrestore(&s->lock, flags); }out: remove_wait_queue(&s->dma_adc.wait, &wait); set_current_state(TASK_RUNNING); return ret;}static ssize_t cm_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos){ struct cm_state *s = (struct cm_state *)file->private_data; DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned swptr; int cnt; VALIDATE_STATE(s); if (s->dma_dac.mapped) return -ENXIO; if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; if (s->status & DO_DUAL_DAC) { if (s->dma_adc.mapped) return -ENXIO; if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) return ret; } if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; ret = 0; add_wait_queue(&s->dma_dac.wait, &wait); while (count > 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; } if (s->status & DO_DUAL_DAC) { s->dma_adc.swptr = s->dma_dac.swptr; s->dma_adc.count = s->dma_dac.count; s->dma_adc.endcleared = s->dma_dac.endcleared; } swptr = s->dma_dac.swptr; cnt = s->dma_dac.dmasize-swptr; if (s->status & DO_AC3_SW) { if (s->dma_dac.count + 2 * cnt > s->dma_dac.dmasize) cnt = (s->dma_dac.dmasize - s->dma_dac.count) / 2; } else { if (s->dma_dac.count + cnt > s->dma_dac.dmasize) cnt = s->dma_dac.dmasize - s->dma_dac.count; } if (cnt <= 0) __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if ((s->status & DO_DUAL_DAC) && (cnt > count / 2)) cnt = count / 2; if (cnt <= 0) { if (s->dma_dac.enabled) start_dac(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; goto out; } if (!schedule_timeout(HZ)) { printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, s->dma_dac.hwptr, s->dma_dac.swptr); spin_lock_irqsave(&s->lock, flags); stop_dac_unlocked(s); set_dmadac(s, s->dma_dac.dmaaddr, s->dma_dac.dmasamples); /* program sample counts */ set_countdac(s, s->dma_dac.fragsamples); s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; if (s->status & DO_DUAL_DAC) { set_dmadac1(s, s->dma_adc.dmaaddr, s->dma_adc.dmasamples); s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; } spin_unlock_irqrestore(&s->lock, flags); } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; goto out; } continue; } if (s->status & DO_AC3_SW) { int err; // clip exceeded data, caught by 033 and 037 if (swptr + 2 * cnt > s->dma_dac.dmasize) cnt = (s->dma_dac.dmasize - swptr) / 2; if ((err = trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt))) { ret = err; goto out; } swptr = (swptr + 2 * cnt) % s->dma_dac.dmasize; } else if ((s->status & DO_DUAL_DAC) && (s->status & DO_BIGENDIAN_W)) { int i, err; const char __user *src = buffer; unsigned char *dst0, *dst1; unsigned char data[8]; dst0 = (unsigned char *) (s->dma_dac.rawbuf + swptr); dst1 = (unsigned char *) (s->dma_adc.rawbuf + swptr); // copy left/right sample at one time for (i = 0; i < cnt / 4; i++) { if ((err = __get_user(data[0], src++))) { ret = err; goto out; } if ((err = __get_user(data[1], src++))) { ret = err; goto out; } if ((err = __get_user(data[2], src++))) { ret = err; goto out; } if ((err = __get_user(data[3], src++))) { ret = err; goto out; } if ((err = __get_user(data[4], src++))) { ret = err; goto out; } if ((err = __get_user(data[5], src++))) { ret = err; goto out; } if ((err = __get_user(data[6], src++))) { ret = err; goto out; } if ((err = __get_user(data[7], src++))) { ret = err; goto out; } dst0[0] = data[1]; dst0[1] = data[0]; dst0[2] = data[3]; dst0[3] = data[2]; dst1[0] = data[5]; dst1[1] = data[4]; dst1[2] = data[7]; dst1[3] = data[6]; dst0 += 4; dst1 += 4; } swptr = (swptr + cnt) % s->dma_dac.dmasize; } else if (s->status & DO_DUAL_DAC) { int i, err; unsigned long __user *src = (unsigned long __user *) buffer; unsigned long *dst0, *dst1; dst0 = (unsigned long *) (s->dma_dac.rawbuf + swptr); dst1 = (unsigned long *) (s->dma_adc.rawbuf + swptr); // copy left/right sample at one time for (i = 0; i < cnt / 4; i++) { if ((err = __get_user(*dst0++, src++))) { ret = err; goto out; } if ((err = __get_user(*dst1++, src++))) { ret = err; goto out; } } swptr = (swptr + cnt) % s->dma_dac.dmasize; } else if (s->status & DO_BIGENDIAN_W) { int i, err; const char __user *src = buffer; unsigned char *dst; unsigned char data[2]; dst = (unsigned char *) (s->dma_dac.rawbuf + swptr); // swap hi/lo bytes for each sample for (i = 0; i < cnt / 2; i++) { if ((err = __get_user(data[0], src++))) { ret = err; goto out; } if ((err = __get_user(data[1], src++))) { ret = err; goto out; } dst[0] = data[1]; dst[1] = data[0]; dst += 2; } swptr = (swptr + cnt) % s->dma_dac.dmasize; } else { if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { if (!ret) ret = -EFAULT; goto out; } swptr = (swptr + cnt) % s->dma_dac.dmasize; } spin_lock_irqsave(&s->lock, flags); s->dma_dac.swptr = swptr; s->dma_dac.count += cnt; if (s->status & DO_AC3_SW) s->dma_dac.count += cnt; s->dma_dac.endcleared = 0; spin_unlock_irqrestore(&s->lock, flags); count -= cnt; buffer += cnt; ret += cnt; if (s->status & DO_DUAL_DAC) { count -= cnt; buffer += cnt; ret += cnt; } if (s->dma_dac.enabled) start_dac(s); }out: remove_wait_queue(&s->dma_dac.wait, &wait); set_current_state(TASK_RUNNING); return ret;}static unsigned int cm_poll(struct file *file, struct poll_table_struct *wait){ struct cm_state *s = (struct cm_state *)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(s, 0)) return 0; poll_wait(file, &s->dma_dac.wait, wait); } if (file->f_mode & FMODE_READ) { if (!s->dma_adc.ready && prog_dmabuf(s, 1)) return 0; poll_wait(file, &s->dma_adc.wait, wait); } spin_lock_irqsave(&s->lock, flags); cm_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 cm_mmap(struct file *file, struct vm_area_struct *vma){ struct cm_state *s = (struct cm_state *)file->private_data; struct dmabuf *db; int ret = -EINVAL; unsigned long size; VALIDATE_STATE(s); lock_kernel(); if (vma->vm_flags & VM_WRITE) { if ((ret = prog_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -