📄 cs4281.c
字号:
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; cs4281_write_ac97(s, BA0_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; cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME, temp1); cs4281_write_ac97(s, BA0_AC97_HEADPHONE_VOLUME, 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; cs4281_write_ac97(s, BA0_AC97_PC_BEEP_VOLUME, 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; cs4281_write_ac97(s, BA0_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; } cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1); temp1 &= 0x40; // Isolate 20db gain bit. if (rl < 3) { temp1 |= 0x8000; rl = 0; } rl = 31 - rl; // Convert volume to attenuation. temp1 |= rl; cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, 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 + BA0_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 + BA0_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 "cs4281: 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; cs4281_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 loff_t cs4281_llseek(struct file *file, loff_t offset, int origin){ return -ESPIPE;}// --------------------------------------------------------------------- static int cs4281_open_mixdev(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); struct cs4281_state *s = devs; while (s && s->dev_mixer != minor) s = s->next; if (!s) return -ENODEV; VALIDATE_STATE(s); file->private_data = s; MOD_INC_USE_COUNT; return 0;}static int cs4281_release_mixdev(struct inode *inode, struct file *file){ struct cs4281_state *s = (struct cs4281_state *) file->private_data; VALIDATE_STATE(s); MOD_DEC_USE_COUNT; return 0;}static int cs4281_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return mixer_ioctl((struct cs4281_state *) file->private_data, cmd, arg);}// ******************************************************************************************// Mixer file operations struct.// ******************************************************************************************static /*const */ struct file_operations cs4281_mixer_fops = { llseek:cs4281_llseek, ioctl:cs4281_ioctl_mixdev, open:cs4281_open_mixdev, release:cs4281_release_mixdev,};// --------------------------------------------------------------------- static int drain_adc(struct cs4281_state *s, int nonblock){ DECLARE_WAITQUEUE(wait, current); unsigned long flags; int count; unsigned tmo; if (s->dma_adc.mapped) return 0; add_wait_queue(&s->dma_adc.wait, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->dma_adc.count; CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: drain_adc() %d\n", count)); spin_unlock_irqrestore(&s->lock, flags); if (count <= 0) { CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: drain_adc() count<0\n")); break; } if (signal_pending(current)) break; if (nonblock) { remove_wait_queue(&s->dma_adc.wait, &wait); current->state = TASK_RUNNING; return -EBUSY; } tmo = 3 * HZ * (count + s->dma_adc.fragsize) / 2 / s->prop_adc.rate; if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE)) tmo >>= 1; if (s->prop_adc.channels > 1) tmo >>= 1; if (!schedule_timeout(tmo + 1)) printk(KERN_DEBUG "cs4281: dma timed out??\n"); } remove_wait_queue(&s->dma_adc.wait, &wait); current->state = TASK_RUNNING; if (signal_pending(current)) return -ERESTARTSYS; return 0;}static int drain_dac(struct cs4281_state *s, int nonblock){ DECLARE_WAITQUEUE(wait, current); unsigned long flags; int count; unsigned tmo; if (s->dma_dac.mapped) 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); current->state = TASK_RUNNING; return -EBUSY; } tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->prop_dac.rate; if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE)) tmo >>= 1; if (s->prop_dac.channels > 1) tmo >>= 1; if (!schedule_timeout(tmo + 1)) printk(KERN_DEBUG "cs4281: dma timed out??\n"); } remove_wait_queue(&s->dma_dac.wait, &wait); current->state = TASK_RUNNING; if (signal_pending(current)) return -ERESTARTSYS; return 0;}//****************************************************************************//// CopySamples copies 16-bit stereo samples from the source to the// destination, possibly converting down to either 8-bit or mono or both.// count specifies the number of output bytes to write.//// Arguments://// dst - Pointer to a destination buffer.// src - Pointer to a source buffer// count - The number of bytes to copy into the destination buffer.// iChannels - Stereo - 2// Mono - 1// fmt - AFMT_xxx (soundcard.h formats)//// NOTES: only call this routine for conversion to 8bit from 16bit////****************************************************************************static void CopySamples(char *dst, char *src, int count, int iChannels, unsigned fmt){ unsigned short *psSrc; long lAudioSample; CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: CopySamples()+ ")); CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO " dst=0x%x src=0x%x count=%d iChannels=%d fmt=0x%x\n", (unsigned) dst, (unsigned) src, (unsigned) count, (unsigned) iChannels, (unsigned) fmt)); // Gershwin does format conversion in hardware so normally // we don't do any host based coversion. The data formatter // truncates 16 bit data to 8 bit and that causes some hiss. // We have already forced the HW to do 16 bit sampling and // 2 channel so that we can use software to round instead // of truncate // // See if the data should be output as 8-bit unsigned stereo. // if ((iChannels == 2) && (fmt & AFMT_U8)) { // // Convert each 16-bit unsigned stereo sample to 8-bit unsigned //
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -