📄 rme96xx.c
字号:
abinfo.fragsize = (s->fragsize*dma->inchannels)>>dma->formatshift; abinfo.bytes = (count*dma->inchannels)>>dma->formatshift;; abinfo.fragstotal = 2; abinfo.fragments = count > s->fragsize; 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: /* What shold this exactly do ? , ATM it is just abinfo.bytes */ if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; val = rme96xx_gethwptr(dma->s,0); count = val - dma->readptr; if (count < 0) count += s->fragsize<<1; return put_user(count, (int *)arg);/* check out how to use mmaped mode (can only be blocked !!!) */ case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; val = rme96xx_gethwptr(dma->s,0); spin_lock_irqsave(&s->lock,flags); cinfo.bytes = s->fragsize<<1;; count = val - dma->readptr; if (count < 0) count += s->fragsize<<1; cinfo.blocks = (count > s->fragsize); cinfo.ptr = val; if (dma->mmapped) dma->readptr &= s->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_READ)) return -EINVAL; val = rme96xx_gethwptr(dma->s,0); spin_lock_irqsave(&s->lock,flags); cinfo.bytes = s->fragsize<<1;; count = val - dma->writeptr; if (count < 0) count += s->fragsize<<1; cinfo.blocks = (count > s->fragsize); cinfo.ptr = val; if (dma->mmapped) dma->writeptr &= s->fragsize<<1; spin_unlock_irqrestore(&s->lock,flags); return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); case SNDCTL_DSP_GETBLKSIZE: return put_user(s->fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: if (get_user(val, (int *)arg)) return -EFAULT; val&=0xffff; val -= 7; if (val < 0) val = 0; if (val > 7) val = 7; rme96xx_setlatency(s,val); return 0; case SNDCTL_DSP_SUBDIVIDE:#if 0 if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision)) return -EINVAL; if (get_user(val, (int *)arg)) return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) s->dma_adc.subdivision = val; if (file->f_mode & FMODE_WRITE) s->dma_dac2.subdivision = val;#endif return 0; case SOUND_PCM_READ_RATE: return put_user(s->rate, (int *)arg); case SOUND_PCM_READ_CHANNELS: return put_user(dma->outchannels, (int *)arg); case SOUND_PCM_READ_BITS: switch (dma->format) { case AFMT_S32_BLOCKED: val = 32; break; case AFMT_S16_LE: val = 16; break; } return put_user(val, (int *)arg); case SOUND_PCM_WRITE_FILTER: case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; } return -ENODEV;}static int rme96xx_open(struct inode *in, struct file *f){ int minor = MINOR(in->i_rdev); struct list_head *list; int devnum = ((minor-3)/16) % devices; /* default = 0 */ rme96xx_info *s; struct dmabuf* dma; DECLARE_WAITQUEUE(wait, current); DBG(printk("device num %d open\n",devnum));/* ??? */ for (list = devs.next; ; list = list->next) { if (list == &devs) return -ENODEV; s = list_entry(list, rme96xx_info, devs); if (!((s->dspnum[devnum] ^ minor) & ~0xf)) break; } VALIDATE_STATE(s);/* ??? */ dma = &s->dma[devnum]; f->private_data = dma; /* wait for device to become free */ down(&s->dma[devnum].open_sem); while (dma->open_mode & f->f_mode) { if (f->f_flags & O_NONBLOCK) { up(&dma->open_sem); return -EBUSY; } add_wait_queue(&dma->open_wait, &wait); __set_current_state(TASK_INTERRUPTIBLE); up(&dma->open_sem); schedule(); remove_wait_queue(&dma->open_wait, &wait); set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&dma->open_sem); } COMM ("hardware open") if (!s->dma[devnum].opened) rme96xx_dmabuf_init(dma->s,dma,dma->inoffset,dma->outoffset); s->dma[devnum].open_mode |= (f->f_mode & (FMODE_READ | FMODE_WRITE)); s->dma[devnum].opened = 1; up(&s->dma[devnum].open_sem); DBG(printk("device num %d open finished\n",devnum)); return 0;}static int rme96xx_release(struct inode *in, struct file *file){ struct dmabuf * dma = (struct dmabuf*) file->private_data; int hwp; DBG(printk(__FUNCTION__"\n")); COMM ("draining") if (dma->open_mode & FMODE_WRITE) {#if 0 /* Why doesn't this work with some cards ?? */ hwp = rme96xx_gethwptr(dma->s,0); while (rme96xx_getospace(dma,hwp)) { interruptible_sleep_on(&(dma->wait)); hwp = rme96xx_gethwptr(dma->s,0); }#endif rme96xx_clearbufs(dma); } dma->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); if (!(dma->open_mode & (FMODE_READ|FMODE_WRITE))) { dma->opened = 0; if (dma->s->started) rme96xx_startcard(dma->s,1); } wake_up(&dma->open_wait); up(&dma->open_sem); return 0;}static ssize_t rme96xx_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){ struct dmabuf *dma = (struct dmabuf *)file->private_data; ssize_t ret = 0; int cnt; /* number of bytes from "buffer" that will/can be used */ int hop = count/dma->outchannels; int hwp; int exact = (file->f_flags & O_NONBLOCK); if(dma == NULL || (dma->s) == NULL) return -ENXIO; if (ppos != &file->f_pos) return -ESPIPE; if (dma->mmapped || !dma->opened) return -ENXIO; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; if (! (dma->open_mode & FMODE_WRITE)) return -ENXIO; if (!dma->s->started) rme96xx_startcard(dma->s,exact); hwp = rme96xx_gethwptr(dma->s,0); if(!(dma->started)){ COMM ("first write") dma->readptr = hwp; dma->writeptr = hwp; dma->started = 1; COMM ("first write done") } while (count > 0) { cnt = rme96xx_getospace(dma,hwp); cnt>>=dma->formatshift; cnt*=dma->outchannels; if (cnt > count) cnt = count; if (cnt != 0) { if (rme96xx_copyfromuser(dma,buffer,cnt,hop)) return ret ? ret : -EFAULT; count -= cnt; buffer += cnt; ret += cnt; if (count == 0) return ret; } if (file->f_flags & O_NONBLOCK) return ret ? ret : -EAGAIN; if ((hwp - dma->writeptr) <= 0) { interruptible_sleep_on(&(dma->wait)); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; } hwp = rme96xx_gethwptr(dma->s,exact); }; /* count > 0 */ return ret;}static ssize_t rme96xx_read(struct file *file, char *buffer,size_t count, loff_t *ppos){ struct dmabuf *dma = (struct dmabuf *)file->private_data; ssize_t ret = 0; int cnt; int hop = count/dma->inchannels; int hwp; int exact = (file->f_flags & O_NONBLOCK); if(dma == NULL || (dma->s) == NULL) return -ENXIO; if (ppos != &file->f_pos) return -ESPIPE; if (dma->mmapped || !dma->opened) return -ENXIO; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; if (! (dma->open_mode & FMODE_READ)) return -ENXIO; if (count > ((dma->s->fragsize*dma->inchannels)>>dma->formatshift)) return -EFAULT; if (!dma->s->started) rme96xx_startcard(dma->s,exact); hwp = rme96xx_gethwptr(dma->s,0); if(!(dma->started)){ COMM ("first read") dma->writeptr = hwp; dma->readptr = hwp; dma->started = 1; } while (count > 0) { cnt = rme96xx_getispace(dma,hwp); cnt>>=dma->formatshift; cnt*=dma->inchannels; if (cnt > count) cnt = count; if (cnt != 0) { if (rme96xx_copytouser(dma,buffer,cnt,hop)) return ret ? ret : -EFAULT; count -= cnt; buffer += cnt; ret += cnt; if (count == 0) return ret; } if (file->f_flags & O_NONBLOCK) return ret ? ret : -EAGAIN; if ((hwp - dma->readptr) <= 0) { interruptible_sleep_on(&(dma->wait)); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; } hwp = rme96xx_gethwptr(dma->s,exact); }; /* count > 0 */ return ret;}static int rm96xx_mmap(struct file *file, struct vm_area_struct *vma) { struct dmabuf *dma = (struct dmabuf *)file->private_data; rme96xx_info* s = dma->s; unsigned long size; VALIDATE_STATE(s); lock_kernel(); if (vma->vm_pgoff != 0) { unlock_kernel(); return -EINVAL; } size = vma->vm_end - vma->vm_start; if (size > RME96xx_DMA_MAX_SIZE) { unlock_kernel(); return -EINVAL; } if (vma->vm_flags & VM_WRITE) { if (!s->started) rme96xx_startcard(s,1); if (remap_page_range(vma->vm_start, virt_to_phys(s->playbuf + dma->outoffset*RME96xx_DMA_MAX_SIZE), size, vma->vm_page_prot)) { unlock_kernel(); return -EAGAIN; } } else if (vma->vm_flags & VM_READ) { if (!s->started) rme96xx_startcard(s,1); if (remap_page_range(vma->vm_start, virt_to_phys(s->playbuf + dma->inoffset*RME96xx_DMA_MAX_SIZE), size, vma->vm_page_prot)) { unlock_kernel(); return -EAGAIN; } } else { unlock_kernel(); return -EINVAL; }/* this is the mapping */ dma->mmapped = 1; unlock_kernel(); return 0;}static unsigned int rme96xx_poll(struct file *file, struct poll_table_struct *wait){ struct dmabuf *dma = (struct dmabuf *)file->private_data; rme96xx_info* s = dma->s; unsigned int mask = 0; unsigned int hwp,cnt; DBG(printk("rme96xx poll_wait ...\n")); VALIDATE_STATE(s); if (!s->started) { mask |= POLLOUT | POLLWRNORM; } poll_wait(file, &dma->wait, wait); hwp = rme96xx_gethwptr(dma->s,0); DBG(printk("rme96xx poll: ..cnt %d > %d\n",cnt,s->fragsize)); cnt = rme96xx_getispace(dma,hwp); if (file->f_mode & FMODE_READ) if (cnt > 0) mask |= POLLIN | POLLRDNORM; cnt = rme96xx_getospace(dma,hwp); if (file->f_mode & FMODE_WRITE) if (cnt > 0) mask |= POLLOUT | POLLWRNORM;// printk("rme96xx poll_wait ...%d > %d\n",rme96xx_getospace(dma,hwp),rme96xx_getispace(dma,hwp)); return mask;}static struct file_operations rme96xx_audio_fops = {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) owner: THIS_MODULE,#endif read: rme96xx_read, write: rme96xx_write, poll: rme96xx_poll, ioctl: rme96xx_ioctl, mmap: rm96xx_mmap, open: rme96xx_open, release: rme96xx_release };static int rme96xx_mixer_open(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); struct list_head *list; rme96xx_info *s; COMM ("mixer open"); for (list = devs.next; ; list = list->next) { if (list == &devs) return -ENODEV; s = list_entry(list, rme96xx_info, devs); if (s->mixer== minor) break; } VALIDATE_STATE(s); file->private_data = s; COMM ("mixer opened") return 0;}static int rme96xx_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ rme96xx_info *s = (rme96xx_info *)file->private_data; u32 status; status = readl(s->iobase + RME96xx_status_register); VALIDATE_STATE(s); if (cmd == SOUND_MIXER_PRIVATE1) { rme_mixer mixer; copy_from_user(&mixer,(void*)arg,sizeof(mixer)); if (file->f_mode & FMODE_WRITE) { s->dma[mixer.devnr].outoffset = mixer.o_offset; s->dma[mixer.devnr].inoffset = mixer.i_offset; } mixer.o_offset = s->dma[mixer.devnr].outoffset; mixer.i_offset = s->dma[mixer.devnr].inoffset; return copy_to_user((void *)arg, &mixer, sizeof(mixer)) ? -EFAULT : 0; } if (cmd == SOUND_MIXER_PRIVATE2) { return put_user(status, (int *)arg); } if (cmd == SOUND_MIXER_PRIVATE3) { u32 control; copy_from_user(&control,(void*)arg,sizeof(control)); if (file->f_mode & FMODE_WRITE) { s->control_register = control; writel(control,s->iobase + RME96xx_control_register); } return put_user(s->control_register, (int *)arg); } return -1;}static int rme96xx_mixer_release(struct inode *inode, struct file *file){ return 0;}static /*const*/ struct file_operations rme96xx_mixer_fops = {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) owner: THIS_MODULE,#endif ioctl: rme96xx_mixer_ioctl, open: rme96xx_mixer_open, release: rme96xx_mixer_release,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -