📄 es1371.c
字号:
static int es1371_release_mixdev(struct inode *inode, struct file *file){ struct es1371_state *s = (struct es1371_state *)file->private_data; VALIDATE_STATE(s); return 0;}static int es1371_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct es1371_state *s = (struct es1371_state *)file->private_data; struct ac97_codec *codec = &s->codec; return mixdev_ioctl(codec, cmd, arg);}static /*const*/ struct file_operations es1371_mixer_fops = { owner: THIS_MODULE, llseek: no_llseek, ioctl: es1371_ioctl_mixdev, open: es1371_open_mixdev, release: es1371_release_mixdev,};/* --------------------------------------------------------------------- */static int drain_dac1(struct es1371_state *s, int nonblock){ DECLARE_WAITQUEUE(wait, current); unsigned long flags; int count, tmo; if (s->dma_dac1.mapped || !s->dma_dac1.ready) return 0; add_wait_queue(&s->dma_dac1.wait, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->dma_dac1.count; spin_unlock_irqrestore(&s->lock, flags); if (count <= 0) break; if (signal_pending(current)) break; if (nonblock) { remove_wait_queue(&s->dma_dac1.wait, &wait); set_current_state(TASK_RUNNING); return -EBUSY; } tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate; tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; if (!schedule_timeout(tmo + 1)) DBG(printk(KERN_DEBUG PFX "dac1 dma timed out??\n");) } remove_wait_queue(&s->dma_dac1.wait, &wait); set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; return 0;}static int drain_dac2(struct es1371_state *s, int nonblock){ DECLARE_WAITQUEUE(wait, current); unsigned long flags; int count, tmo; if (s->dma_dac2.mapped || !s->dma_dac2.ready) return 0; add_wait_queue(&s->dma_dac2.wait, &wait); for (;;) { __set_current_state(TASK_UNINTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->dma_dac2.count; spin_unlock_irqrestore(&s->lock, flags); if (count <= 0) break; if (signal_pending(current)) break; if (nonblock) { remove_wait_queue(&s->dma_dac2.wait, &wait); set_current_state(TASK_RUNNING); return -EBUSY; } tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate; tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; if (!schedule_timeout(tmo + 1)) DBG(printk(KERN_DEBUG PFX "dac2 dma timed out??\n");) } remove_wait_queue(&s->dma_dac2.wait, &wait); set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; return 0;}/* --------------------------------------------------------------------- */static ssize_t es1371_read(struct file *file, char *buffer, size_t count, loff_t *ppos){ struct es1371_state *s = (struct es1371_state *)file->private_data; DECLARE_WAITQUEUE(wait, current); ssize_t ret = 0; unsigned long flags; unsigned swptr; int cnt; VALIDATE_STATE(s); if (ppos != &file->f_pos) return -ESPIPE; if (s->dma_adc.mapped) return -ENXIO; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; down(&s->sem); if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) goto out2; 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; } up(&s->sem); schedule(); if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; goto out2; } down(&s->sem); if (s->dma_adc.mapped) { ret = -ENXIO; goto out; } continue; } 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; spin_unlock_irqrestore(&s->lock, flags); count -= cnt; buffer += cnt; ret += cnt; if (s->dma_adc.enabled) start_adc(s); }out: up(&s->sem);out2: remove_wait_queue(&s->dma_adc.wait, &wait); set_current_state(TASK_RUNNING); return ret;}static ssize_t es1371_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){ struct es1371_state *s = (struct es1371_state *)file->private_data; DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned swptr; int cnt; VALIDATE_STATE(s); if (ppos != &file->f_pos) return -ESPIPE; if (s->dma_dac2.mapped) return -ENXIO; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; down(&s->sem); if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) goto out3; ret = 0; add_wait_queue(&s->dma_dac2.wait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); if (s->dma_dac2.count < 0) { s->dma_dac2.count = 0; s->dma_dac2.swptr = s->dma_dac2.hwptr; } swptr = s->dma_dac2.swptr; cnt = s->dma_dac2.dmasize-swptr; if (s->dma_dac2.count + cnt > s->dma_dac2.dmasize) cnt = s->dma_dac2.dmasize - s->dma_dac2.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_dac2.enabled) start_dac2(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; goto out; } up(&s->sem); schedule(); if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; goto out2; } down(&s->sem); if (s->dma_dac2.mapped) { ret = -ENXIO; goto out; } continue; } if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt)) { if (!ret) ret = -EFAULT; goto out; } swptr = (swptr + cnt) % s->dma_dac2.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_dac2.swptr = swptr; s->dma_dac2.count += cnt; s->dma_dac2.endcleared = 0; spin_unlock_irqrestore(&s->lock, flags); count -= cnt; buffer += cnt; ret += cnt; if (s->dma_dac2.enabled) start_dac2(s); }out: up(&s->sem);out2: remove_wait_queue(&s->dma_dac2.wait, &wait);out3: set_current_state(TASK_RUNNING); return ret;}/* No kernel lock - we have our own spinlock */static unsigned int es1371_poll(struct file *file, struct poll_table_struct *wait){ struct es1371_state *s = (struct es1371_state *)file->private_data; unsigned long flags; unsigned int mask = 0; VALIDATE_STATE(s); if (file->f_mode & FMODE_WRITE) { if (!s->dma_dac2.ready && prog_dmabuf_dac2(s)) return 0; poll_wait(file, &s->dma_dac2.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); es1371_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_dac2.mapped) { if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize) mask |= POLLOUT | POLLWRNORM; } else { if ((signed)s->dma_dac2.dmasize >= s->dma_dac2.count + (signed)s->dma_dac2.fragsize) mask |= POLLOUT | POLLWRNORM; } } spin_unlock_irqrestore(&s->lock, flags); return mask;}static int es1371_mmap(struct file *file, struct vm_area_struct *vma){ struct es1371_state *s = (struct es1371_state *)file->private_data; struct dmabuf *db; int ret = 0; unsigned long size; VALIDATE_STATE(s); lock_kernel(); down(&s->sem); if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf_dac2(s)) != 0) { goto out; } db = &s->dma_dac2; } else if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf_adc(s)) != 0) { goto out; } db = &s->dma_adc; } else { ret = -EINVAL; goto out; } if (vma->vm_pgoff != 0) { ret = -EINVAL; goto out; } size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << db->buforder)) { ret = -EINVAL; goto out; } if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) { ret = -EAGAIN; goto out; } db->mapped = 1;out: up(&s->sem); unlock_kernel(); return ret;}static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct es1371_state *s = (struct es1371_state *)file->private_data; unsigned long flags; audio_buf_info abinfo; count_info cinfo; int count; int val, mapped, ret; VALIDATE_STATE(s); mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac2.mapped) || ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); switch (cmd) { case OSS_GETVERSION: return put_user(SOUND_VERSION, (int *)arg); case SNDCTL_DSP_SYNC: if (file->f_mode & FMODE_WRITE) return drain_dac2(s, 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, (int *)arg); case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_WRITE) { stop_dac2(s); synchronize_irq(); s->dma_dac2.swptr = s->dma_dac2.hwptr = s->dma_dac2.count = s->dma_dac2.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; if (val >= 0) { if (file->f_mode & FMODE_READ) { stop_adc(s); s->dma_adc.ready = 0; set_adc_rate(s, val); } if (file->f_mode & FMODE_WRITE) { stop_dac2(s); s->dma_dac2.ready = 0; set_dac2_rate(s, val); } } return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dac2rate, (int *)arg); case SNDCTL_DSP_STEREO: if (get_user(val, (int *)arg)) return -EFAULT; if (file->f_mode & FMODE_READ) { stop_adc(s); s->dma_adc.ready = 0; spin_lock_irqsave(&s->lock, flags); if (val)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -