📄 ite8172.c
字号:
static ssize_t it8172_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){ struct it8172_state *s = (struct it8172_state *)file->private_data; struct dmabuf *db = &s->dma_dac; ssize_t ret; unsigned long flags; int cnt, bufcnt, avail; if (ppos != &file->f_pos) return -ESPIPE; if (db->mapped) return -ENXIO; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; ret = 0; while (count > 0) { // wait for space in playback buffer do { spin_lock_irqsave(&s->lock, flags); avail = db->dmasize - db->count; spin_unlock_irqrestore(&s->lock, flags); if (avail <= 0) { if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; return ret; } interruptible_sleep_on(&db->wait); if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; return ret; } } } while (avail <= 0); cnt = count > avail ? avail : count; // copy to nextIn if (copy_from_user(db->nextIn, buffer, cnt)) { if (!ret) ret = -EFAULT; return ret; } bufcnt = cnt; if (cnt % db->fragsize) { // round count up to nearest fragment, and fill remainder of // fragment with silence int newcnt = db->fragsize * ((cnt + db->fragsize) / db->fragsize); memset(db->nextIn + cnt, (s->pcc & CC_DF) ? 0 : 0x80, newcnt - cnt); cnt = newcnt; } spin_lock_irqsave(&s->lock, flags); db->count += cnt; if (db->stopped) start_dac(s); spin_unlock_irqrestore(&s->lock, flags); db->nextIn += cnt; if (db->nextIn >= db->rawbuf + db->dmasize) db->nextIn -= db->dmasize; count -= bufcnt; buffer += bufcnt; ret += bufcnt; } // while (count > 0) return ret;}/* No kernel lock - we have our own spinlock */static unsigned int it8172_poll(struct file *file, struct poll_table_struct *wait){ struct it8172_state *s = (struct it8172_state *)file->private_data; unsigned long flags; unsigned int mask = 0; 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); 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 it8172_mmap(struct file *file, struct vm_area_struct *vma){ struct it8172_state *s = (struct it8172_state *)file->private_data; struct dmabuf *db; unsigned long size; lock_kernel(); if (vma->vm_flags & VM_WRITE) db = &s->dma_dac; else if (vma->vm_flags & VM_READ) db = &s->dma_adc; else { unlock_kernel(); return -EINVAL; } if (vma->vm_pgoff != 0) { unlock_kernel(); return -EINVAL; } size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << db->buforder)) { unlock_kernel(); return -EINVAL; } if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) { unlock_kernel(); return -EAGAIN; } db->mapped = 1; unlock_kernel(); return 0;}#ifdef IT8172_VERBOSE_DEBUGstatic struct ioctl_str_t { unsigned int cmd; const char* str;} ioctl_str[] = { {SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"}, {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"}, {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"}, {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"}, {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"}, {SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"}, {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"}, {SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"}, {SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"}, {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"}, {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"}, {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"}, {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"}, {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"}, {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"}, {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"}, {SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"}, {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"}, {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"}, {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"}, {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"}, {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"}, {SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"}, {SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"}, {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"}, {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"}, {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"}, {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"}, {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"}, {OSS_GETVERSION, "OSS_GETVERSION"}, {SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"}, {SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"}, {SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"}, {SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"}};#endif static int it8172_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct it8172_state *s = (struct it8172_state *)file->private_data; unsigned long flags; audio_buf_info abinfo; count_info cinfo; int count; int val, mapped, ret, diff; mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);#ifdef IT8172_VERBOSE_DEBUG for (count=0; count<sizeof(ioctl_str)/sizeof(ioctl_str[0]); count++) { if (ioctl_str[count].cmd == cmd) break; } if (count < sizeof(ioctl_str)/sizeof(ioctl_str[0])) printk(KERN_INFO PFX "ioctl %s\n", ioctl_str[count].str); else printk(KERN_INFO PFX "ioctl unknown, 0x%x\n", cmd);#endif 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: 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.count = s->dma_dac.total_bytes = 0; s->dma_dac.nextIn = s->dma_dac.nextOut = s->dma_dac.rawbuf; } if (file->f_mode & FMODE_READ) { stop_adc(s); synchronize_irq(); s->dma_adc.count = s->dma_adc.total_bytes = 0; s->dma_adc.nextIn = s->dma_adc.nextOut = s->dma_adc.rawbuf; } 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); set_adc_rate(s, val); if ((ret = prog_dmabuf_adc(s))) return ret; } if (file->f_mode & FMODE_WRITE) { stop_dac(s); set_dac_rate(s, val); if ((ret = prog_dmabuf_dac(s))) return ret; } } return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dacrate, (int *)arg); case SNDCTL_DSP_STEREO: if (get_user(val, (int *)arg)) return -EFAULT; if (file->f_mode & FMODE_READ) { stop_adc(s); if (val) s->capcc |= CC_SM; else s->capcc &= ~CC_SM; outw(s->capcc, s->io+IT_AC_CAPCC); if ((ret = prog_dmabuf_adc(s))) return ret; } if (file->f_mode & FMODE_WRITE) { stop_dac(s); if (val) s->pcc |= CC_SM; else s->pcc &= ~CC_SM; outw(s->pcc, s->io+IT_AC_PCC); if ((ret = prog_dmabuf_dac(s))) return ret; } return 0; case SNDCTL_DSP_CHANNELS: if (get_user(val, (int *)arg)) return -EFAULT; if (val != 0) { if (file->f_mode & FMODE_READ) { stop_adc(s); if (val >= 2) { val = 2; s->capcc |= CC_SM; } else s->capcc &= ~CC_SM; outw(s->capcc, s->io+IT_AC_CAPCC); if ((ret = prog_dmabuf_adc(s))) return ret; } if (file->f_mode & FMODE_WRITE) { stop_dac(s); switch (val) { case 1: s->pcc &= ~CC_SM; break; case 2: s->pcc |= CC_SM; break; default: // FIX! support multichannel??? val = 2; s->pcc |= CC_SM; break; } outw(s->pcc, s->io+IT_AC_PCC); if ((ret = prog_dmabuf_dac(s))) return ret; } } return put_user(val, (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) { if (file->f_mode & FMODE_READ) { stop_adc(s); if (val == AFMT_S16_LE) s->capcc |= CC_DF; else { val = AFMT_U8; s->capcc &= ~CC_DF; } outw(s->capcc, s->io+IT_AC_CAPCC); if ((ret = prog_dmabuf_adc(s))) return ret; } if (file->f_mode & FMODE_WRITE) { stop_dac(s); if (val == AFMT_S16_LE) s->pcc |= CC_DF; else { val = AFMT_U8; s->pcc &= ~CC_DF; } outw(s->pcc, s->io+IT_AC_PCC); if ((ret = prog_dmabuf_dac(s))) return ret; } } else { if (file->f_mode & FMODE_READ) val = (s->capcc & CC_DF) ? AFMT_S16_LE : AFMT_U8; else val = (s->pcc & CC_DF) ? AFMT_S16_LE : AFMT_U8; } return put_user(val, (int *)arg); case SNDCTL_DSP_POST: return 0; case SNDCTL_DSP_GETTRIGGER: val = 0; spin_lock_irqsave(&s->lock, flags); if (file->f_mode & FMODE_READ && !s->dma_adc.stopped) val |= PCM_ENABLE_INPUT; if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped) val |= PCM_ENABLE_OUTPUT; spin_unlock_irqrestore(&s->lock, flags); 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) start_adc(s); else stop_adc(s); } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) start_dac(s); else stop_dac(s); } return 0; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; abinfo.fragsize = s->dma_dac.fragsize; spin_lock_irqsave(&s->lock, flags); count = s->dma_dac.count; if (!s->dma_dac.stopped) count -= (s->dma_dac.fragsize - inw(s->io+IT_AC_PCDL)); spin_unlock_irqrestore(&s->lock, flags); 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; return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; abinfo.fragsize = s->dma_adc.fragsize; spin_lock_irqsave(&s->lock, flags); count = s->dma_adc.count; if (!s->dma_adc.stopped) count += (s->dma_adc.fragsize - inw(s->io+IT_AC_CAPCDL)); spin_unlock_irqrestore(&s->lock, flags); if (count < 0) count = 0; abinfo.bytes = count; abinfo.fragstotal = s->dma_adc.numfrag; abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; 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; spin_lock_irqsave(&s->lock, flags); count = s->dma_dac.count; if (!s->dma_dac.stopped) count -= (s->dma_dac.fragsize - inw(s->io+IT_AC_PCDL)); 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; spin_lock_irqsave(&s->lock, flags); cinfo.bytes = s->dma_adc.total_bytes; count = s->dma_adc.count; if (!s->dma_adc.stopped) { diff = s->dma_adc.fragsize - inw(s->io+IT_AC_CAPCDL); count += diff; cinfo.bytes += diff; cinfo.ptr = inl(s->io+s->dma_adc.curBufPtr) - s->dma_adc.dmaaddr; } else cinfo.ptr = virt_to_bus(s->dma_adc.nextIn) - s->dma_adc.dmaaddr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; spin_unlock_irqrestore(&s->lock, flags); if (count < 0) count = 0; cinfo.blocks = count >> s->dma_adc.fragshift; return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; spin_lock_irqsave(&s->lock, flags); cinfo.bytes = s->dma_dac.total_bytes; count = s->dma_dac.count; if (!s->dma_dac.stopped) { diff = s->dma_dac.fragsize - inw(s->io+IT_AC_CAPCDL); count -= diff; cinfo.bytes += diff; cinfo.ptr = inl(s->io+s->dma_dac.curBufPtr) - s->dma_dac.dmaaddr; } else cinfo.ptr = virt_to_bus(s->dma_dac.nextOut) - s->dma_dac.dmaaddr; if (s->dma_dac.mapped) s->dma_dac.count &= s->dma_dac.fragsize-1; spin_unlock_irqrestore(&s->lock, flags); if (count < 0) count = 0; cinfo.blocks = count >> s->dma_dac.fragshift; return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) return put_user(s->dma_dac.fragsize, (int *)arg); else return put_user(s->dma_adc.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: if (get_user(val, (int *)arg)) return -EFAULT; if (file->f_mode & FMODE_READ) { stop_adc(s); s->dma_adc.ossfragshift = val & 0xffff;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -