📄 esssolo1.c
字号:
else if (l < 5) l = 5; r = (val >> 7) & 0x1fe; if (r > 200) r = 200; else if (r < 5) r = 5; rl = (l - 5) / 13; rr = (r - 5) / 13; r = (rl * 13 + 5) / 2; l = (rr * 13 + 5) / 2; write_mixer(s, mixreg[vidx-1], (rl << 4) | rr);#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS s->mix.vol[vidx-1] = ((unsigned int)r << 8) | l;#else s->mix.vol[vidx-1] = val;#endif return put_user(s->mix.vol[vidx-1], (int *)arg); }}/* --------------------------------------------------------------------- */static int solo1_open_mixdev(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); struct solo1_state *s = NULL; struct pci_dev *pci_dev; pci_for_each_dev(pci_dev) { struct pci_driver *drvr; drvr = pci_dev_driver (pci_dev); if (drvr != &solo1_driver) continue; s = (struct solo1_state*)pci_get_drvdata(pci_dev); if (!s) continue; if (s->dev_mixer == minor) break; } if (!s) return -ENODEV; VALIDATE_STATE(s); file->private_data = s; return 0;}static int solo1_release_mixdev(struct inode *inode, struct file *file){ struct solo1_state *s = (struct solo1_state *)file->private_data; VALIDATE_STATE(s); return 0;}static int solo1_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return mixer_ioctl((struct solo1_state *)file->private_data, cmd, arg);}static /*const*/ struct file_operations solo1_mixer_fops = { owner: THIS_MODULE, llseek: no_llseek, ioctl: solo1_ioctl_mixdev, open: solo1_open_mixdev, release: solo1_release_mixdev,};/* --------------------------------------------------------------------- */static int drain_dac(struct solo1_state *s, int nonblock){ DECLARE_WAITQUEUE(wait, current); unsigned long flags; int count; unsigned tmo; if (s->dma_dac.mapped) 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->rate; if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE)) tmo >>= 1; if (s->channels > 1) tmo >>= 1; if (!schedule_timeout(tmo + 1)) printk(KERN_DEBUG "solo1: 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 solo1_read(struct file *file, char *buffer, size_t count, loff_t *ppos){ struct solo1_state *s = (struct solo1_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_adc.mapped) return -ENXIO; if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) 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;#ifdef DEBUGREC printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x cnt: %u\n", read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc), cnt);#endif if (cnt <= 0) { if (s->dma_adc.enabled) start_adc(s);#ifdef DEBUGREC printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n" KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n" KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n" KERN_DEBUG "solo1_read: SBstat: 0x%02x cnt: %u\n", read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8), read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9), inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);#endif if (inb(s->ddmabase+15) & 1) printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n"); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; break; } schedule();#ifdef DEBUGREC printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n" KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n" KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n" KERN_DEBUG "solo1_read: SBstat: 0x%02x cnt: %u\n", read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8), read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9), inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);#endif if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; break; } continue; } if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { if (!ret) ret = -EFAULT; break; } 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);#ifdef DEBUGREC printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x\n", read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc));#endif } remove_wait_queue(&s->dma_adc.wait, &wait); set_current_state(TASK_RUNNING); return ret;}static ssize_t solo1_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){ struct solo1_state *s = (struct solo1_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_dac.mapped) return -ENXIO; if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT;#if 0 printk(KERN_DEBUG "solo1_write: reg 70: 0x%02x 71: 0x%02x 72: 0x%02x 74: 0x%02x 76: 0x%02x 78: 0x%02x 7A: 0x%02x\n" KERN_DEBUG "solo1_write: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x SBstat: 0x%02x\n", read_mixer(s, 0x70), read_mixer(s, 0x71), read_mixer(s, 0x72), read_mixer(s, 0x74), read_mixer(s, 0x76), read_mixer(s, 0x78), read_mixer(s, 0x7a), inl(s->iobase), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc)); printk(KERN_DEBUG "solo1_write: reg 78: 0x%02x reg 7A: 0x%02x DMAcnt: 0x%04x DMAstat: 0x%02x SBstat: 0x%02x\n", read_mixer(s, 0x78), read_mixer(s, 0x7a), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));#endif 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; } swptr = s->dma_dac.swptr; cnt = s->dma_dac.dmasize-swptr; 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 (cnt <= 0) { if (s->dma_dac.enabled) start_dac(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; break; } schedule(); if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; break; } continue; } if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { if (!ret) ret = -EFAULT; break; } swptr = (swptr + cnt) % s->dma_dac.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_dac.swptr = swptr; s->dma_dac.count += cnt; s->dma_dac.endcleared = 0; spin_unlock_irqrestore(&s->lock, flags); count -= cnt; buffer += cnt; ret += cnt; if (s->dma_dac.enabled) start_dac(s); } remove_wait_queue(&s->dma_dac.wait, &wait); set_current_state(TASK_RUNNING); return ret;}/* No kernel lock - we have our own spinlock */static unsigned int solo1_poll(struct file *file, struct poll_table_struct *wait){ struct solo1_state *s = (struct solo1_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_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); solo1_update_ptr(s); if (file->f_mode & FMODE_READ) { if (s->dma_adc.mapped) { if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) mask |= POLLIN | POLLRDNORM; } else { if (s->dma_adc.count > 0) 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) mask |= POLLOUT | POLLWRNORM; } } spin_unlock_irqrestore(&s->lock, flags); return mask;}static int solo1_mmap(struct file *file, struct vm_area_struct *vma){ struct solo1_state *s = (struct solo1_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_dmabuf_dac(s)) != 0) goto out; db = &s->dma_dac; } else if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf_adc(s)) != 0) goto out; db = &s->dma_adc; } else goto out; ret = -EINVAL; if (vma->vm_pgoff != 0) goto out; size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << db->buforder)) goto out; ret = -EAGAIN; if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) goto out; db->mapped = 1; ret = 0;out: unlock_kernel(); return ret;}static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct solo1_state *s = (struct solo1_state *)file->private_data; unsigned long flags; audio_buf_info abinfo; count_info cinfo; int val, mapped, ret, count; int div1, div2; unsigned rate1, rate2; VALIDATE_STATE(s); mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.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_dac(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_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; } prog_codec(s); return 0; case SNDCTL_DSP_SPEED: if (get_user(val, (int *)arg)) return -EFAULT; if (val >= 0) { stop_adc(s); stop_dac(s); s->dma_adc.ready = s->dma_dac.ready = 0; /* program sampling rates */ if (val > 48000) val = 48000; if (val < 6300) val = 6300; div1 = (768000 + val / 2) / val; rate1 = (768000 + div1 / 2) / div1; div1 = -div1; div2 = (793800 + val / 2) / val; rate2 = (793800 + div2 / 2) / div2; div2 = (-div2) & 0x7f; if (abs(val - rate2) < abs(val - rate1)) { rate1 = rate2; div1 = div2; } s->rate = rate1; s->clkdiv = div1; prog_codec(s); } return put_user(s->rate, (int *)arg); case SNDCTL_DSP_STEREO: if (get_user(val, (int *)arg)) return -EFAULT; stop_adc(s); stop_dac(s); s->dma_adc.ready = s->dma_dac.ready = 0; /* program channels */ s->channels = val ? 2 : 1; prog_codec(s);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -