📄 maestro3.c
字号:
return 0; set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->dma_dac.wait, &wait); for (;;) { 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 = (count * HZ) / s->ratedac; tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]; /* XXX this is just broken. someone is waking us up alot, or schedule_timeout is broken. or something. who cares. - zach */ if (!schedule_timeout(tmo ? tmo : 1) && tmo) DPRINTK(DPCRAP,"dma timed out?? %ld\n",jiffies); } remove_wait_queue(&s->dma_dac.wait, &wait); set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; return 0;}static ssize_t m3_read(struct file *file, char *buffer, size_t count, loff_t *ppos){ struct m3_state *s = (struct m3_state *)file->private_data; 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(s, 1))) return ret; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; ret = 0; spin_lock_irqsave(&s->lock, flags); while (count > 0) { int timed_out; swptr = s->dma_adc.swptr; cnt = s->dma_adc.dmasize-swptr; if (s->dma_adc.count < cnt) cnt = s->dma_adc.count; if (cnt > count) cnt = count; if (cnt <= 0) { start_adc(s); if (file->f_flags & O_NONBLOCK) { ret = ret ? ret : -EAGAIN; goto out; } spin_unlock_irqrestore(&s->lock, flags); timed_out = interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ) == 0; spin_lock_irqsave(&s->lock, flags); if(timed_out) { printk("read: chip lockup? dmasz %u fragsz %u count %u 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); stop_adc(s); set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift); s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; } if (signal_pending(current)) { ret = ret ? ret : -ERESTARTSYS; goto out; } continue; } spin_unlock_irqrestore(&s->lock, flags); if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { ret = ret ? ret : -EFAULT; return ret; } spin_lock_irqsave(&s->lock, flags); swptr = (swptr + cnt) % s->dma_adc.dmasize; s->dma_adc.swptr = swptr; s->dma_adc.count -= cnt; count -= cnt; buffer += cnt; ret += cnt; start_adc(s); }out: spin_unlock_irqrestore(&s->lock, flags); return ret;}static ssize_t m3_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){ struct m3_state *s = (struct m3_state *)file->private_data; 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(s, 0))) return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; ret = 0; spin_lock_irqsave(&s->lock, flags); while (count > 0) { int timed_out; 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 > count) cnt = count; if (cnt <= 0) { start_dac(s); if (file->f_flags & O_NONBLOCK) { if(!ret) ret = -EAGAIN; goto out; } spin_unlock_irqrestore(&s->lock, flags); timed_out = interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ) == 0; spin_lock_irqsave(&s->lock, flags); if(timed_out) { DPRINTK(DPCRAP,"write: chip lockup? dmasz %u fragsz %u count %u 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); stop_dac(s); set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift); s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; goto out; } continue; } spin_unlock_irqrestore(&s->lock, flags); if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { if (!ret) ret = -EFAULT; return ret; } spin_lock_irqsave(&s->lock, flags); DPRINTK(DPSYS,"wrote %6d bytes at sw: %6d cnt: %6d while hw: %6d\n", cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr); swptr = (swptr + cnt) % s->dma_dac.dmasize; s->dma_dac.swptr = swptr; s->dma_dac.count += cnt; s->dma_dac.endcleared = 0; count -= cnt; buffer += cnt; ret += cnt; start_dac(s); }out: spin_unlock_irqrestore(&s->lock, flags); return ret;}static unsigned int m3_poll(struct file *file, struct poll_table_struct *wait){ struct m3_state *s = (struct m3_state *)file->private_data; unsigned long flags; unsigned int mask = 0; VALIDATE_STATE(s); if (file->f_mode & FMODE_WRITE) poll_wait(file, &s->dma_dac.wait, wait); if (file->f_mode & FMODE_READ) poll_wait(file, &s->dma_adc.wait, wait); spin_lock_irqsave(&s->lock, flags); m3_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 m3_mmap(struct file *file, struct vm_area_struct *vma){ struct m3_state *s = (struct m3_state *)file->private_data; unsigned long max_size, size, start, offset; struct dmabuf *db; int ret = -EINVAL; VALIDATE_STATE(s); if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf(s, 0)) != 0) return ret; db = &s->dma_dac; } else if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf(s, 1)) != 0) return ret; db = &s->dma_adc; } else return -EINVAL; max_size = db->dmasize; start = vma->vm_start; offset = (vma->vm_pgoff << PAGE_SHIFT); size = vma->vm_end - vma->vm_start; if(size > max_size) goto out; if(offset > max_size - size) goto out; /* * this will be ->nopage() once I can * ask Jeff what the hell I'm doing wrong. */ 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: return ret;}/* * this function is a disaster.. */#define get_user_ret(x, ptr, ret) ({ if(get_user(x, ptr)) return ret; })static int m3_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct m3_state *s = (struct m3_state *)file->private_data; unsigned long flags; audio_buf_info abinfo; count_info cinfo; int val, mapped, ret; unsigned char fmtm, fmtd; VALIDATE_STATE(s); mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); DPRINTK(DPSYS,"m3_ioctl: cmd %d\n", cmd); 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, file->f_flags & O_NONBLOCK); return 0; case SNDCTL_DSP_SETDUPLEX: /* XXX fix */ 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: spin_lock_irqsave(&s->lock, flags); 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; } spin_unlock_irqrestore(&s->lock, flags); return 0; case SNDCTL_DSP_SPEED: get_user_ret(val, (int *)arg, -EFAULT); spin_lock_irqsave(&s->lock, flags); 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_dac(s); s->dma_dac.ready = 0; set_dac_rate(s, val); } } spin_unlock_irqrestore(&s->lock, flags); return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); case SNDCTL_DSP_STEREO: get_user_ret(val, (int *)arg, -EFAULT); spin_lock_irqsave(&s->lock, flags); fmtd = 0; fmtm = ~0; if (file->f_mode & FMODE_READ) { stop_adc(s); s->dma_adc.ready = 0; if (val) fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT; else fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT); } if (file->f_mode & FMODE_WRITE) { stop_dac(s); s->dma_dac.ready = 0; if (val) fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT; else fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT); } set_fmt(s, fmtm, fmtd); spin_unlock_irqrestore(&s->lock, flags); return 0; case SNDCTL_DSP_CHANNELS: get_user_ret(val, (int *)arg, -EFAULT); spin_lock_irqsave(&s->lock, flags); if (val != 0) { fmtd = 0; fmtm = ~0; if (file->f_mode & FMODE_READ) { stop_adc(s); s->dma_adc.ready = 0; if (val >= 2) fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT; else fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT); } if (file->f_mode & FMODE_WRITE) { stop_dac(s); s->dma_dac.ready = 0; if (val >= 2) fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT; else fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT); } set_fmt(s, fmtm, fmtd); } spin_unlock_irqrestore(&s->lock, flags); return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, (int *)arg); case SNDCTL_DSP_GETFMTS: /* Returns a mask */ return put_user(AFMT_U8|AFMT_S16_LE, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ get_user_ret(val, (int *)arg, -EFAULT); spin_lock_irqsave(&s->lock, flags); if (val != AFMT_QUERY) { fmtd = 0; fmtm = ~0; if (file->f_mode & FMODE_READ) { stop_adc(s); s->dma_adc.ready = 0; if (val == AFMT_S16_LE) fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT; else fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT); } if (file->f_mode & FMODE_WRITE) { stop_dac(s); s->dma_dac.ready = 0; if (val == AFMT_S16_LE) fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT; else fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT); } set_fmt(s, fmtm, fmtd); } spin_unlock_irqrestore(&s->lock, flags); return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT) : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -