📄 sonicvibes.c
字号:
spin_lock_irqsave(&s->lock, flags); set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift); /* program enhanced mode registers */ wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8); wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); 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; 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); } remove_wait_queue(&s->dma_adc.wait, &wait); set_current_state(TASK_RUNNING); return ret;}static ssize_t sv_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){ struct sv_state *s = (struct sv_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(s, 0))) return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; ret = 0;#if 0 spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); spin_unlock_irqrestore(&s->lock, flags);#endif 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; } if (!schedule_timeout(HZ)) { printk(KERN_DEBUG "sv: 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); stop_dac(s); spin_lock_irqsave(&s->lock, flags); set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift); /* program enhanced mode registers */ wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8); wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; spin_unlock_irqrestore(&s->lock, flags); } 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 sv_poll(struct file *file, struct poll_table_struct *wait){ struct sv_state *s = (struct sv_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, 1)) return 0; poll_wait(file, &s->dma_dac.wait, wait); } if (file->f_mode & FMODE_READ) { if (!s->dma_adc.ready && prog_dmabuf(s, 0)) return 0; poll_wait(file, &s->dma_adc.wait, wait); } spin_lock_irqsave(&s->lock, flags); sv_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 sv_mmap(struct file *file, struct vm_area_struct *vma){ struct sv_state *s = (struct sv_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(s, 1)) != 0) goto out; db = &s->dma_dac; } else if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf(s, 0)) != 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 sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct sv_state *s = (struct sv_state *)file->private_data; unsigned long flags; audio_buf_info abinfo; count_info cinfo; int count; 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); 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; } 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_dac(s); s->dma_dac.ready = 0; set_dac_rate(s, val); } } return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); case SNDCTL_DSP_STEREO: if (get_user(val, (int *)arg)) return -EFAULT; fmtd = 0; fmtm = ~0; if (file->f_mode & FMODE_READ) { stop_adc(s); s->dma_adc.ready = 0; if (val) fmtd |= SV_CFMT_STEREO << SV_CFMT_CSHIFT; else fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_CSHIFT); } if (file->f_mode & FMODE_WRITE) { stop_dac(s); s->dma_dac.ready = 0; if (val) fmtd |= SV_CFMT_STEREO << SV_CFMT_ASHIFT; else fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_ASHIFT); } set_fmt(s, fmtm, fmtd); return 0; case SNDCTL_DSP_CHANNELS: if (get_user(val, (int *)arg)) return -EFAULT; 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 |= SV_CFMT_STEREO << SV_CFMT_CSHIFT; else fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_CSHIFT); } if (file->f_mode & FMODE_WRITE) { stop_dac(s); s->dma_dac.ready = 0; if (val >= 2) fmtd |= SV_CFMT_STEREO << SV_CFMT_ASHIFT; else fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_ASHIFT); } set_fmt(s, fmtm, fmtd); } return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_STEREO << SV_CFMT_CSHIFT) : (SV_CFMT_STEREO << SV_CFMT_ASHIFT))) ? 2 : 1, (int *)arg); case SNDCTL_DSP_GETFMTS: /* Returns a mask */ return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ if (get_user(val, (int *)arg)) return -EFAULT; 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 |= SV_CFMT_16BIT << SV_CFMT_CSHIFT; else fmtm &= ~(SV_CFMT_16BIT << SV_CFMT_CSHIFT); } if (file->f_mode & FMODE_WRITE) { stop_dac(s); s->dma_dac.ready = 0; if (val == AFMT_S16_LE) fmtd |= SV_CFMT_16BIT << SV_CFMT_ASHIFT; else fmtm &= ~(SV_CFMT_16BIT << SV_CFMT_ASHIFT); } set_fmt(s, fmtm, fmtd); } return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_16BIT << SV_CFMT_CSHIFT) : (SV_CFMT_16BIT << SV_CFMT_ASHIFT))) ? AFMT_S16_LE : AFMT_U8, (int *)arg); case SNDCTL_DSP_POST: return 0; case SNDCTL_DSP_GETTRIGGER: val = 0; if (file->f_mode & FMODE_READ && s->enable & SV_CENABLE_RE) val |= PCM_ENABLE_INPUT; if (file->f_mode & FMODE_WRITE && s->enable & SV_CENABLE_PE) val |= PCM_ENABLE_OUTPUT; return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: if (get_user(val, (int *)arg)) return -EFAULT; if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) 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(s, 0))) 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: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) return val; spin_lock_irqsave(&s->lock, flags); sv_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: if (!(file->f_mode & FMODE_READ)) return -EINVAL; if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0) return val; spin_lock_irqsave(&s->lock, flags); sv_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: file->f_flags |= O_NONBLOCK; return 0; case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) return val; spin_lock_irqsave(&s->lock, flags); sv_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: if (!(file->f_mode & FMODE_READ)) return -EINVAL; if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0) return val; spin_lock_irqsave(&s->lock, flags); sv_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)); case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0) return val; spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; count = s->dma_dac.count; if (count < 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -