📄 nec_vrc5477.c
字号:
if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; return ret; } } } while (avail <= 0); MIPS_ASSERT( (avail % db->fragSize) == 0); copyCount = copy_adc_to_user(s, buffer, count, avail); if (copyCount <=0 ) { if (!ret) ret = -EFAULT; return ret; } count -= copyCount; buffer += copyCount; ret += copyCount; } // while (count > 0) return ret;}static int inline copy_two_channel_dac_from_user(struct vrc5477_ac97_state *s, const char *buffer, int copyCount){ struct dmabuf *db = &s->dma_dac; int bufStart = db->nextIn; MIPS_ASSERT(db->ready); for (; copyCount > 0; ) { int i; int count = copyCount; if (count > WORK_BUF_SIZE/2) count = WORK_BUF_SIZE/2; if (copy_from_user(s->workBuf, buffer, count*2)) { return -1; } for (i=0; i< count/2; i++) { *(u16*)(db->lbuf + bufStart + i*2) = s->workBuf[i].lchannel; *(u16*)(db->rbuf + bufStart + i*2) = s->workBuf[i].rchannel; } copyCount -= count; bufStart += count; MIPS_ASSERT(bufStart <= db->fragTotalSize); buffer += count *2; } return 0;}/* return the total bytes that is copied */static int inline copy_dac_from_user(struct vrc5477_ac97_state *s, const char *buffer, size_t count, int avail){ struct dmabuf *db = &s->dma_dac; int copyCount=0; int copyFragCount=0; int totalCopyCount = 0; int totalCopyFragCount = 0; unsigned long flags;#if defined(VRC5477_AC97_VERBOSE_DEBUG) int i;#endif /* adjust count to signel channel byte count */ count >>= s->dacChannels - 1; /* we may have to "copy" twice as ring buffer wraps around */ for (; (avail > 0) && (count > 0); ) { /* determine max possible copy count for single channel */ copyCount = count; if (copyCount > avail) { copyCount = avail; } if (copyCount + db->nextIn > db->fragTotalSize) { copyCount = db->fragTotalSize - db->nextIn; MIPS_ASSERT((copyCount % db->fragSize) == 0); MIPS_ASSERT(copyCount > 0); } copyFragCount = (copyCount-1) >> db->fragShift; copyFragCount = (copyFragCount+1) << db->fragShift; MIPS_ASSERT(copyFragCount >= copyCount); /* we copy differently based on the number channels */ if (s->dacChannels == 1) { if (copy_from_user(db->lbuf + db->nextIn, buffer, copyCount)) return -1; /* fill gaps with 0 */ memset(db->lbuf + db->nextIn + copyCount, 0, copyFragCount - copyCount); } else { /* we have demux the stream into two separate ones */ if (copy_two_channel_dac_from_user(s, buffer, copyCount)) return -1; /* fill gaps with 0 */ memset(db->lbuf + db->nextIn + copyCount, 0, copyFragCount - copyCount); memset(db->rbuf + db->nextIn + copyCount, 0, copyFragCount - copyCount); }#if defined(VRC5477_AC97_VERBOSE_DEBUG) for (i=0; i< copyFragCount; i+= db->fragSize) { *(u16*)(db->lbuf + db->nextIn + i) = inTicket ++; }#endif count -= copyCount; totalCopyCount =+ copyCount; avail -= copyFragCount; totalCopyFragCount += copyFragCount; buffer += copyCount << (s->dacChannels - 1); db->nextIn += copyFragCount; if (db->nextIn >= db->fragTotalSize) { MIPS_ASSERT(db->nextIn == db->fragTotalSize); db->nextIn = 0; } MIPS_ASSERT((copyFragCount % db->fragSize) == 0); MIPS_ASSERT( (count == 0) || (copyCount == copyFragCount)); } spin_lock_irqsave(&s->lock, flags); db->count += totalCopyFragCount; if (db->stopped) { start_dac(s); } /* nextIn should not be equal to nextOut unless we are full */ MIPS_ASSERT( ( (db->count == db->fragTotalSize) && (db->nextIn == db->nextOut) ) || ( (db->count < db->fragTotalSize) && (db->nextIn != db->nextOut) ) ); spin_unlock_irqrestore(&s->lock, flags); return totalCopyCount << (s->dacChannels-1);}static ssize_t vrc5477_ac97_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){ struct vrc5477_ac97_state *s = (struct vrc5477_ac97_state *)file->private_data; struct dmabuf *db = &s->dma_dac; ssize_t ret; unsigned long flags; int copyCount, avail; if (ppos != &file->f_pos) return -ESPIPE; 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->fragTotalSize - 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); MIPS_ASSERT( (avail % db->fragSize) == 0); copyCount = copy_dac_from_user(s, buffer, count, avail); if (copyCount < 0) { if (!ret) ret = -EFAULT; return ret; } count -= copyCount; buffer += copyCount; ret += copyCount; } // while (count > 0) return ret;}/* No kernel lock - we have our own spinlock */static unsigned int vrc5477_ac97_poll(struct file *file, struct poll_table_struct *wait){ struct vrc5477_ac97_state *s = (struct vrc5477_ac97_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 ((signed)s->dma_dac.fragTotalSize >= s->dma_dac.count + (signed)s->dma_dac.fragSize) mask |= POLLOUT | POLLWRNORM; } spin_unlock_irqrestore(&s->lock, flags); return mask;}#ifdef CONFIG_LL_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_SETFMT, "SNDCTL_DSP_SETFMT"}, {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_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 vrc5477_ac97_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct vrc5477_ac97_state *s = (struct vrc5477_ac97_state *)file->private_data; unsigned long flags; audio_buf_info abinfo; int count; int val, ret;#ifdef CONFIG_LL_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, (int *)arg); case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_WRITE) { stop_dac(s); synchronize_irq(); s->dma_dac.count = 0; s->dma_dac.nextIn = s->dma_dac.nextOut = 0; } if (file->f_mode & FMODE_READ) { stop_adc(s); synchronize_irq(); s->dma_adc.count = 0; s->dma_adc.nextIn = s->dma_adc.nextOut = 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); 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->adcChannels = 2; else s->adcChannels = 1; if ((ret = prog_dmabuf_adc(s))) return ret; } if (file->f_mode & FMODE_WRITE) { stop_dac(s); if (val) s->dacChannels = 2; else s->dacChannels = 1; 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 ( (val != 1) && (val != 2)) val = 2; if (file->f_mode & FMODE_READ) { stop_adc(s); s->dacChannels = val; if ((ret = prog_dmabuf_adc(s))) return ret; } if (file->f_mode & FMODE_WRITE) { stop_dac(s); s->dacChannels = val; 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, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ if (get_user(val, (int *)arg)) return -EFAULT; if (val != AFMT_QUERY) { if (val != AFMT_S16_LE) return -EINVAL; if (file->f_mode & FMODE_READ) { stop_adc(s); if ((ret = prog_dmabuf_adc(s))) return ret; } if (file->f_mode & FMODE_WRITE) { stop_dac(s); if ((ret = prog_dmabuf_dac(s))) return ret; } } else { val = AFMT_S16_LE; } return put_user(val, (int *)arg); case SNDCTL_DSP_POST: return 0; case SNDCTL_DSP_GETTRIGGER: case SNDCTL_DSP_SETTRIGGER: /* NO trigger */ return -EINVAL; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; abinfo.fragsize = s->dma_dac.fragSize << (s->dacChannels-1); spin_lock_irqsave(&s->lock, flags); count = s->dma_dac.count; spin_unlock_irqrestore(&s->lock, flags); abinfo.bytes = (s->dma_dac.fragTotalSize - count) << (s->dacChannels-1); abinfo.fragstotal = s->dma_dac.numFrag; abinfo.fragments = abinfo.bytes >> s->dma_dac.fragShift >> (s->dacChannels-1); 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 << (s->adcChannels-1); spin_lock_irqsave(&s->lock, flags); count = s->dma_adc.count; spin_unlock_irqrestore(&s->lock, flags); if (count < 0) count = 0; abinfo.bytes = count << (s->adcChannels-1); abinfo.fragstotal = s->dma_adc.numFrag; abinfo.fragments = (abinfo.bytes >> s->dma_adc.fragShift) >> (s->adcChannels-1); 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; spin_unlock_irqrestore(&s->lock, flags); return put_user(count, (int *)arg); case SNDCTL_DSP_GETIPTR: case SNDCTL_DSP_GETOPTR: /* we cannot get DMA ptr */ return -EINVAL; case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) return put_user(s->dma_dac.fragSize << (s->dacChannels-1), (int *)arg); else return put_user(s->dma_adc.fragSize << (s->adcChannels-1), (int *)arg); case SNDCTL_DSP_SETFRAGMENT: /* we ignore fragment size request */ return 0; case SNDCTL_DSP_SUBDIVIDE: /* what is this for? [jsun] */ return 0; case SOUND_PCM_READ_RATE: return put_user((file->f_mode & FMODE_READ) ? s->adcRate : s->dacRate, (int *)arg); case SOUND_PCM_READ_CHANNELS: if (file->f_mode & FMODE_READ) return put_user(s->adcChannels, (int *)arg); else return put_user(s->dacChannels ? 2 : 1, (int *)arg); case SOUND_PCM_READ_BITS: return put_user(16, (int *)arg); case SOUND_PCM_WRITE_FILTER: case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; } return mixdev_ioctl(&s->codec, cmd, arg);}static int vrc5477_ac97_open(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); unsigned long flags; struct list_head *list; struct vrc5477_ac97_state *s;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -