📄 sonicvibes.c
字号:
return; spin_lock(&s->lock); sv_update_ptr(s); sv_handle_midi(s); spin_unlock(&s->lock);}static void sv_midi_timer(unsigned long data){ struct sv_state *s = (struct sv_state *)data; unsigned long flags; spin_lock_irqsave(&s->lock, flags); sv_handle_midi(s); spin_unlock_irqrestore(&s->lock, flags); s->midi.timer.expires = jiffies+1; add_timer(&s->midi.timer);}/* --------------------------------------------------------------------- */static const char invalid_magic[] = KERN_CRIT "sv: invalid magic value\n";#define VALIDATE_STATE(s) \({ \ if (!(s) || (s)->magic != SV_MAGIC) { \ printk(invalid_magic); \ return -ENXIO; \ } \})/* --------------------------------------------------------------------- */#define MT_4 1#define MT_5MUTE 2#define MT_4MUTEMONO 3#define MT_6MUTE 4static const struct { unsigned left:5; unsigned right:5; unsigned type:3; unsigned rec:3;} mixtable[SOUND_MIXER_NRDEVICES] = { [SOUND_MIXER_RECLEV] = { SV_CIMIX_ADCINL, SV_CIMIX_ADCINR, MT_4, 0 }, [SOUND_MIXER_LINE1] = { SV_CIMIX_AUX1INL, SV_CIMIX_AUX1INR, MT_5MUTE, 5 }, [SOUND_MIXER_CD] = { SV_CIMIX_CDINL, SV_CIMIX_CDINR, MT_5MUTE, 1 }, [SOUND_MIXER_LINE] = { SV_CIMIX_LINEINL, SV_CIMIX_LINEINR, MT_5MUTE, 4 }, [SOUND_MIXER_MIC] = { SV_CIMIX_MICIN, SV_CIMIX_ADCINL, MT_4MUTEMONO, 6 }, [SOUND_MIXER_SYNTH] = { SV_CIMIX_SYNTHINL, SV_CIMIX_SYNTHINR, MT_5MUTE, 2 }, [SOUND_MIXER_LINE2] = { SV_CIMIX_AUX2INL, SV_CIMIX_AUX2INR, MT_5MUTE, 3 }, [SOUND_MIXER_VOLUME] = { SV_CIMIX_ANALOGINL, SV_CIMIX_ANALOGINR, MT_5MUTE, 7 }, [SOUND_MIXER_PCM] = { SV_CIMIX_PCMINL, SV_CIMIX_PCMINR, MT_6MUTE, 0 }};#ifdef OSS_DOCUMENTED_MIXER_SEMANTICSstatic int return_mixval(struct sv_state *s, unsigned i, int *arg){ unsigned long flags; unsigned char l, r, rl, rr; spin_lock_irqsave(&s->lock, flags); l = rdindir(s, mixtable[i].left); r = rdindir(s, mixtable[i].right); spin_unlock_irqrestore(&s->lock, flags); switch (mixtable[i].type) { case MT_4: r &= 0xf; l &= 0xf; rl = 10 + 6 * (l & 15); rr = 10 + 6 * (r & 15); break; case MT_4MUTEMONO: rl = 55 - 3 * (l & 15); if (r & 0x10) rl += 45; rr = rl; r = l; break; case MT_5MUTE: default: rl = 100 - 3 * (l & 31); rr = 100 - 3 * (r & 31); break; case MT_6MUTE: rl = 100 - 3 * (l & 63) / 2; rr = 100 - 3 * (r & 63) / 2; break; } if (l & 0x80) rl = 0; if (r & 0x80) rr = 0; return put_user((rr << 8) | rl, arg);}#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = { [SOUND_MIXER_RECLEV] = 1, [SOUND_MIXER_LINE1] = 2, [SOUND_MIXER_CD] = 3, [SOUND_MIXER_LINE] = 4, [SOUND_MIXER_MIC] = 5, [SOUND_MIXER_SYNTH] = 6, [SOUND_MIXER_LINE2] = 7, [SOUND_MIXER_VOLUME] = 8, [SOUND_MIXER_PCM] = 9};#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */static unsigned mixer_recmask(struct sv_state *s){ unsigned long flags; int i, j; spin_lock_irqsave(&s->lock, flags); j = rdindir(s, SV_CIMIX_ADCINL) >> 5; spin_unlock_irqrestore(&s->lock, flags); j &= 7; for (i = 0; i < SOUND_MIXER_NRDEVICES && mixtable[i].rec != j; i++); return 1 << i;}static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg){ unsigned long flags; int i, val; unsigned char l, r, rl, rr; VALIDATE_STATE(s); if (cmd == SOUND_MIXER_INFO) { mixer_info info; strncpy(info.id, "SonicVibes", sizeof(info.id)); strncpy(info.name, "S3 SonicVibes", sizeof(info.name)); info.modify_counter = s->mix.modcnt; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; } if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; strncpy(info.id, "SonicVibes", sizeof(info.id)); strncpy(info.name, "S3 SonicVibes", sizeof(info.name)); if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; } if (cmd == OSS_GETVERSION) return put_user(SOUND_VERSION, (int *)arg); if (cmd == SOUND_MIXER_PRIVATE1) { /* SRS settings */ if (get_user(val, (int *)arg)) return -EFAULT; spin_lock_irqsave(&s->lock, flags); if (val & 1) { if (val & 2) { l = 4 - ((val >> 2) & 7); if (l & ~3) l = 4; r = 4 - ((val >> 5) & 7); if (r & ~3) r = 4; wrindir(s, SV_CISRSSPACE, l); wrindir(s, SV_CISRSCENTER, r); } else wrindir(s, SV_CISRSSPACE, 0x80); } l = rdindir(s, SV_CISRSSPACE); r = rdindir(s, SV_CISRSCENTER); spin_unlock_irqrestore(&s->lock, flags); if (l & 0x80) return put_user(0, (int *)arg); return put_user(((4 - (l & 7)) << 2) | ((4 - (r & 7)) << 5) | 2, (int *)arg); } if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) return -EINVAL; if (_SIOC_DIR(cmd) == _SIOC_READ) { switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ return put_user(mixer_recmask(s), (int *)arg); case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) if (mixtable[i].type) val |= 1 << i; return put_user(val, (int *)arg); case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) if (mixtable[i].rec) val |= 1 << i; return put_user(val, (int *)arg); case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO) val |= 1 << i; return put_user(val, (int *)arg); case SOUND_MIXER_CAPS: return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg); default: i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) return -EINVAL;#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS return return_mixval(s, i, (int *)arg);#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ if (!volidx[i]) return -EINVAL; return put_user(s->mix.vol[volidx[i]-1], (int *)arg);#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } } if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE)) return -EINVAL; s->mix.modcnt++; switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ if (get_user(val, (int *)arg)) return -EFAULT; i = hweight32(val); if (i == 0) return 0; /*val = mixer_recmask(s);*/ else if (i > 1) val &= ~mixer_recmask(s); for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { if (!(val & (1 << i))) continue; if (mixtable[i].rec) break; } if (!mixtable[i].rec) return 0; spin_lock_irqsave(&s->lock, flags); frobindir(s, SV_CIMIX_ADCINL, 0x1f, mixtable[i].rec << 5); frobindir(s, SV_CIMIX_ADCINR, 0x1f, mixtable[i].rec << 5); spin_unlock_irqrestore(&s->lock, flags); return 0; default: i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) return -EINVAL; if (get_user(val, (int *)arg)) return -EFAULT; l = val & 0xff; r = (val >> 8) & 0xff; if (mixtable[i].type == MT_4MUTEMONO) l = (r + l) / 2; if (l > 100) l = 100; if (r > 100) r = 100; spin_lock_irqsave(&s->lock, flags); switch (mixtable[i].type) { case MT_4: if (l >= 10) l -= 10; if (r >= 10) r -= 10; frobindir(s, mixtable[i].left, 0xf0, l / 6); frobindir(s, mixtable[i].right, 0xf0, l / 6); break; case MT_4MUTEMONO: rr = 0; if (l < 10) rl = 0x80; else { if (l >= 55) { rr = 0x10; l -= 45; } rl = (55 - l) / 3; } wrindir(s, mixtable[i].left, rl); frobindir(s, mixtable[i].right, ~0x10, rr); break; case MT_5MUTE: if (l < 7) rl = 0x80; else rl = (100 - l) / 3; if (r < 7) rr = 0x80; else rr = (100 - r) / 3; wrindir(s, mixtable[i].left, rl); wrindir(s, mixtable[i].right, rr); break; case MT_6MUTE: if (l < 6) rl = 0x80; else rl = (100 - l) * 2 / 3; if (r < 6) rr = 0x80; else rr = (100 - r) * 2 / 3; wrindir(s, mixtable[i].left, rl); wrindir(s, mixtable[i].right, rr); break; } spin_unlock_irqrestore(&s->lock, flags);#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS return return_mixval(s, i, (int *)arg);#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ if (!volidx[i]) return -EINVAL; s->mix.vol[volidx[i]-1] = val; return put_user(s->mix.vol[volidx[i]-1], (int *)arg);#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ }}/* --------------------------------------------------------------------- */static int sv_open_mixdev(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); struct list_head *list; struct sv_state *s; for (list = devs.next; ; list = list->next) { if (list == &devs) return -ENODEV; s = list_entry(list, struct sv_state, devs); if (s->dev_mixer == minor) break; } VALIDATE_STATE(s); file->private_data = s; return 0;}static int sv_release_mixdev(struct inode *inode, struct file *file){ struct sv_state *s = (struct sv_state *)file->private_data; VALIDATE_STATE(s); return 0;}static int sv_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return mixer_ioctl((struct sv_state *)file->private_data, cmd, arg);}static /*const*/ struct file_operations sv_mixer_fops = { owner: THIS_MODULE, llseek: no_llseek, ioctl: sv_ioctl_mixdev, open: sv_open_mixdev, release: sv_release_mixdev,};/* --------------------------------------------------------------------- */static int drain_dac(struct sv_state *s, int nonblock){ DECLARE_WAITQUEUE(wait, current); unsigned long flags; int count, tmo; if (s->dma_dac.mapped || !s->dma_dac.ready) return 0; add_wait_queue(&s->dma_dac.wait, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); 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 = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac; tmo >>= sample_shift[(s->fmt >> SV_CFMT_ASHIFT) & SV_CFMT_MASK]; if (!schedule_timeout(tmo + 1)) printk(KERN_DEBUG "sv: dma timed out??\n"); } remove_wait_queue(&s->dma_dac.wait, &wait); set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; return 0;}/* --------------------------------------------------------------------- */static ssize_t sv_read(struct file *file, 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_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;#if 0 spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); spin_unlock_irqrestore(&s->lock, flags);#endif add_wait_queue(&s->dma_adc.wait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); swptr = s->dma_adc.swptr; cnt = s->dma_adc.dmasize-swptr; if (s->dma_adc.count < cnt) cnt = s->dma_adc.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_adc.enabled) start_adc(s); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; break; } if (!schedule_timeout(HZ)) { printk(KERN_DEBUG "sv: read: chip lockup? dmasz %u fragsz %u count %i 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -