swarm_cs4297a.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,962 行 · 第 1/5 页
C
1,962 行
#if CSDEBUG cs_printioctl(cmd);#endif#if CSDEBUG_INTERFACE if ((cmd == SOUND_MIXER_CS_GETDBGMASK) || (cmd == SOUND_MIXER_CS_SETDBGMASK) || (cmd == SOUND_MIXER_CS_GETDBGLEVEL) || (cmd == SOUND_MIXER_CS_SETDBGLEVEL)) { switch (cmd) { case SOUND_MIXER_CS_GETDBGMASK: return put_user(cs_debugmask, (unsigned long *) arg); case SOUND_MIXER_CS_GETDBGLEVEL: return put_user(cs_debuglevel, (unsigned long *) arg); case SOUND_MIXER_CS_SETDBGMASK: if (get_user(val, (unsigned long *) arg)) return -EFAULT; cs_debugmask = val; return 0; case SOUND_MIXER_CS_SETDBGLEVEL: if (get_user(val, (unsigned long *) arg)) return -EFAULT; cs_debuglevel = val; return 0; default: CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO "cs4297a: mixer_ioctl(): ERROR unknown debug cmd\n")); return 0; } }#endif if (cmd == SOUND_MIXER_PRIVATE1) { return -EINVAL; } if (cmd == SOUND_MIXER_PRIVATE2) { // enable/disable/query spatializer if (get_user(val, (int *) arg)) return -EFAULT; if (val != -1) { temp1 = (val & 0x3f) >> 2; cs4297a_write_ac97(s, AC97_3D_CONTROL, temp1); cs4297a_read_ac97(s, AC97_GENERAL_PURPOSE, &temp1); cs4297a_write_ac97(s, AC97_GENERAL_PURPOSE, temp1 | 0x2000); } cs4297a_read_ac97(s, AC97_3D_CONTROL, &temp1); return put_user((temp1 << 2) | 3, (int *) arg); } if (cmd == SOUND_MIXER_INFO) { mixer_info info; memset(&info, 0, sizeof(info)); strlcpy(info.id, "CS4297a", sizeof(info.id)); strlcpy(info.name, "Crystal CS4297a", 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; memset(&info, 0, sizeof(info)); strlcpy(info.id, "CS4297a", sizeof(info.id)); strlcpy(info.name, "Crystal CS4297a", 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 (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) return -EINVAL; // If ioctl has only the SIOC_READ bit(bit 31) // on, process the only-read commands. if (_SIOC_DIR(cmd) == _SIOC_READ) { switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source cs4297a_read_ac97(s, AC97_RECORD_SELECT, &temp1); return put_user(mixer_src[temp1 & 7], (int *) arg); case SOUND_MIXER_DEVMASK: // Arg contains a bit for each supported device return put_user(SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_VOLUME | SOUND_MASK_RECLEV, (int *) arg); case SOUND_MIXER_RECMASK: // Arg contains a bit for each supported recording source return put_user(SOUND_MASK_LINE | SOUND_MASK_VOLUME, (int *) arg); case SOUND_MIXER_STEREODEVS: // Mixer channels supporting stereo return put_user(SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_VOLUME | SOUND_MASK_RECLEV, (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 || !(vidx = mixtable1[i])) return -EINVAL; return put_user(s->mix.vol[vidx - 1], (int *) arg); } } // If ioctl doesn't have both the SIOC_READ and // the SIOC_WRITE bit set, return invalid. if (_SIOC_DIR(cmd) != (_SIOC_READ | _SIOC_WRITE)) return -EINVAL; // Increment the count of volume writes. s->mix.modcnt++; // Isolate the command; it must be a write. 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); // i = # bits on in val. if (i != 1) // One & only 1 bit must be on. return 0; for (i = 0; i < sizeof(mixer_src) / sizeof(int); i++) { if (val == mixer_src[i]) { temp1 = (i << 8) | i; cs4297a_write_ac97(s, AC97_RECORD_SELECT, temp1); return 0; } } return 0; case SOUND_MIXER_VOLUME: if (get_user(val, (int *) arg)) return -EFAULT; l = val & 0xff; if (l > 100) l = 100; // Max soundcard.h vol is 100. if (l < 6) { rl = 63; l = 0; } else rl = attentbl[(10 * l) / 100]; // Convert 0-100 vol to 63-0 atten. r = (val >> 8) & 0xff; if (r > 100) r = 100; // Max right volume is 100, too if (r < 6) { rr = 63; r = 0; } else rr = attentbl[(10 * r) / 100]; // Convert volume to attenuation. if ((rl > 60) && (rr > 60)) // If both l & r are 'low', temp1 = 0x8000; // turn on the mute bit. else temp1 = 0; temp1 |= (rl << 8) | rr; cs4297a_write_ac97(s, AC97_MASTER_VOL_STEREO, temp1); cs4297a_write_ac97(s, AC97_PHONE_VOL, temp1);#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS s->mix.vol[8] = ((unsigned int) r << 8) | l;#else s->mix.vol[8] = val;#endif return put_user(s->mix.vol[8], (int *) arg); case SOUND_MIXER_SPEAKER: if (get_user(val, (int *) arg)) return -EFAULT; l = val & 0xff; if (l > 100) l = 100; if (l < 3) { rl = 0; l = 0; } else { rl = (l * 2 - 5) / 13; // Convert 0-100 range to 0-15. l = (rl * 13 + 5) / 2; } if (rl < 3) { temp1 = 0x8000; rl = 0; } else temp1 = 0; rl = 15 - rl; // Convert volume to attenuation. temp1 |= rl << 1; cs4297a_write_ac97(s, AC97_PCBEEP_VOL, temp1);#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS s->mix.vol[6] = l << 8;#else s->mix.vol[6] = val;#endif return put_user(s->mix.vol[6], (int *) arg); case SOUND_MIXER_RECLEV: if (get_user(val, (int *) arg)) return -EFAULT; l = val & 0xff; if (l > 100) l = 100; r = (val >> 8) & 0xff; if (r > 100) r = 100; rl = (l * 2 - 5) / 13; // Convert 0-100 scale to 0-15. rr = (r * 2 - 5) / 13; if (rl < 3 && rr < 3) temp1 = 0x8000; else temp1 = 0; temp1 = temp1 | (rl << 8) | rr; cs4297a_write_ac97(s, AC97_RECORD_GAIN, temp1);#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS s->mix.vol[7] = ((unsigned int) r << 8) | l;#else s->mix.vol[7] = val;#endif return put_user(s->mix.vol[7], (int *) arg); case SOUND_MIXER_MIC: if (get_user(val, (int *) arg)) return -EFAULT; l = val & 0xff; if (l > 100) l = 100; if (l < 1) { l = 0; rl = 0; } else { rl = ((unsigned) l * 5 - 4) / 16; // Convert 0-100 range to 0-31. l = (rl * 16 + 4) / 5; } cs4297a_read_ac97(s, AC97_MIC_VOL, &temp1); temp1 &= 0x40; // Isolate 20db gain bit. if (rl < 3) { temp1 |= 0x8000; rl = 0; } rl = 31 - rl; // Convert volume to attenuation. temp1 |= rl; cs4297a_write_ac97(s, AC97_MIC_VOL, temp1);#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS s->mix.vol[5] = val << 8;#else s->mix.vol[5] = val;#endif return put_user(s->mix.vol[5], (int *) arg); case SOUND_MIXER_SYNTH: if (get_user(val, (int *) arg)) return -EFAULT; l = val & 0xff; if (l > 100) l = 100; if (get_user(val, (int *) arg)) return -EFAULT; r = (val >> 8) & 0xff; if (r > 100) r = 100; rl = (l * 2 - 11) / 3; // Convert 0-100 range to 0-63. rr = (r * 2 - 11) / 3; if (rl < 3) // If l is low, turn on temp1 = 0x0080; // the mute bit. else temp1 = 0; rl = 63 - rl; // Convert vol to attenuation.// writel(temp1 | rl, s->pBA0 + FMLVC); if (rr < 3) // If rr is low, turn on temp1 = 0x0080; // the mute bit. else temp1 = 0; rr = 63 - rr; // Convert vol to attenuation.// writel(temp1 | rr, s->pBA0 + FMRVC);#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS s->mix.vol[4] = (r << 8) | l;#else s->mix.vol[4] = val;#endif return put_user(s->mix.vol[4], (int *) arg); default: CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO "cs4297a: mixer_ioctl(): default\n")); i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) return -EINVAL; if (get_user(val, (int *) arg)) return -EFAULT; l = val & 0xff; if (l > 100) l = 100; if (l < 1) { l = 0; rl = 31; } else rl = (attentbl[(l * 10) / 100]) >> 1; r = (val >> 8) & 0xff; if (r > 100) r = 100; if (r < 1) { r = 0; rr = 31; } else rr = (attentbl[(r * 10) / 100]) >> 1; if ((rl > 30) && (rr > 30)) temp1 = 0x8000; else temp1 = 0; temp1 = temp1 | (rl << 8) | rr; cs4297a_write_ac97(s, mixreg[vidx - 1], temp1);#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS s->mix.vol[vidx - 1] = ((unsigned int) r << 8) | l;#else s->mix.vol[vidx - 1] = val;#endif return put_user(s->mix.vol[vidx - 1], (int *) arg); }}// --------------------------------------------------------------------- static int cs4297a_open_mixdev(struct inode *inode, struct file *file){ int minor = iminor(inode); struct cs4297a_state *s=NULL; struct list_head *entry; CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n")); list_for_each(entry, &cs4297a_devs) { s = list_entry(entry, struct cs4297a_state, list); if(s->dev_mixer == minor) break; } if (!s) { CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n")); return -ENODEV; } VALIDATE_STATE(s); file->private_data = s; CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n")); return nonseekable_open(inode, file);}static int cs4297a_release_mixdev(struct inode *inode, struct file *file){ struct cs4297a_state *s = (struct cs4297a_state *) file->private_data; VALIDATE_STATE(s); return 0;}static int cs4297a_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?