📄 cmpci.c
字号:
break; case MT_5MUTE: default: rl = 100 - 3 * ((l >> 3) & 31); rr = 100 - 3 * ((r >> 3) & 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_CD] = 1, [SOUND_MIXER_LINE] = 2, [SOUND_MIXER_MIC] = 3, [SOUND_MIXER_SYNTH] = 4, [SOUND_MIXER_VOLUME] = 5, [SOUND_MIXER_PCM] = 6};#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */static unsigned mixer_recmask(struct cm_state *s){ unsigned long flags; int i, j, k; spin_lock_irqsave(&s->lock, flags); j = rdmixer(s, DSP_MIX_ADCMIXIDX_L); spin_unlock_irqrestore(&s->lock, flags); j &= 0x7f; for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++) if (j & mixtable[i].rec) k |= 1 << i; return k;}static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg){ unsigned long flags; int i, val, j; unsigned char l, r, rl, rr; VALIDATE_STATE(s); if (cmd == SOUND_MIXER_INFO) { mixer_info info; strncpy(info.id, "cmpci", sizeof(info.id)); strncpy(info.name, "C-Media PCI", 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, "cmpci", sizeof(info.id)); strncpy(info.name, "C-Media cmpci", 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 (_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_OUTSRC: /* Arg contains a bit for each recording source */ return put_user(mixer_recmask(s), (int *)arg);//need fix 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_OUTMASK: /* Arg contains a bit for each supported recording source */ for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++) if (mixtable[i].play) 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(0, (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); for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) { if (!(val & (1 << i))) continue; if (!mixtable[i].rec) { val &= ~(1 << i); continue; } j |= mixtable[i].rec; } spin_lock_irqsave(&s->lock, flags); wrmixer(s, DSP_MIX_ADCMIXIDX_L, j); wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | (j>>1)); spin_unlock_irqrestore(&s->lock, flags); return 0; case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */ if (get_user(val, (int *)arg)) return -EFAULT; for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) { if (!(val & (1 << i))) continue; if (!mixtable[i].play) { val &= ~(1 << i); continue; } j |= mixtable[i].play; } spin_lock_irqsave(&s->lock, flags); frobindir(s, DSP_MIX_OUTMIXIDX, 0x1f, j); 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 (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: rl = (l < 4 ? 0 : (l - 5) / 3) & 31; rr = (rl >> 2) & 7; wrmixer(s, mixtable[i].left, rl<<3); outb((inb(s->iobase + CODEC_CMI_MIXER2) & ~0x0e) | rr<<1, s->iobase + CODEC_CMI_MIXER2); break; case MT_5MUTEMONO: r = l; rl = l < 4 ? 0 : (l - 5) / 3; rr = rl >> 2; wrmixer(s, mixtable[i].left, rl<<3); outb((inb(s->iobase + CODEC_CMI_MIXER2) & ~0x0e) | rr<<1, s->iobase + CODEC_CMI_MIXER2); break; case MT_5MUTE: rl = l < 4 ? 0 : (l - 5) / 3; rr = r < 4 ? 0 : (r - 5) / 3; wrmixer(s, mixtable[i].left, rl<<3); wrmixer(s, mixtable[i].right, rr<<3); break; case MT_6MUTE: if (l < 6) rl = 0x00; else rl = l * 2 / 3; if (r < 6) rr = 0x00; else rr = r * 2 / 3; wrmixer(s, mixtable[i].left, rl); wrmixer(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 loff_t cm_llseek(struct file *file, loff_t offset, int origin){ return -ESPIPE;}/* --------------------------------------------------------------------- */static int cm_open_mixdev(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); struct cm_state *s = devs; while (s && s->dev_mixer != minor) s = s->next; if (!s) return -ENODEV; VALIDATE_STATE(s); file->private_data = s; return 0;}static int cm_release_mixdev(struct inode *inode, struct file *file){ struct cm_state *s = (struct cm_state *)file->private_data; VALIDATE_STATE(s); return 0;}static int cm_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return mixer_ioctl((struct cm_state *)file->private_data, cmd, arg);}static /*const*/ struct file_operations cm_mixer_fops = { owner: THIS_MODULE, llseek: cm_llseek, ioctl: cm_ioctl_mixdev, open: cm_open_mixdev, release: cm_release_mixdev,};/* --------------------------------------------------------------------- */static int drain_dac(struct cm_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); current->state = TASK_RUNNING; return -EBUSY; } tmo = (count * HZ) / s->ratedac; tmo >>= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK]; if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "cmpci: dma timed out??\n"); } remove_wait_queue(&s->dma_dac.wait, &wait); current->state = TASK_RUNNING; if (signal_pending(current)) return -ERESTARTSYS; return 0;}/* --------------------------------------------------------------------- */static ssize_t cm_read(struct file *file, char *buffer, size_t count, loff_t *ppos){ struct cm_state *s = (struct cm_state *)file->private_data; 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); cm_update_ptr(s); spin_unlock_irqrestore(&s->lock, flags);#endif 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; spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { start_adc(s); if (file->f_flags & O_NONBLOCK) return ret ? ret : -EAGAIN; if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { printk(KERN_DEBUG "cmpci: 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); spin_lock_irqsave(&s->lock, flags); set_dmaadc(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.dmasamples); /* program sample counts */ outw(s->dma_adc.fragsamples-1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2); s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; spin_unlock_irqrestore(&s->lock, flags); } if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; continue; } if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) return ret ? ret : -EFAULT; swptr = (swptr + cnt) % s->dma_adc.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_adc.swptr = swptr; s->dma_adc.count -= cnt; spin_unlock_irqrestore(&s->lock, flags); count -= cnt; buffer += cnt; ret += cnt; start_adc(s); } return ret;}static ssize_t cm_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){ struct cm_state *s = (struct cm_state *)file->private_data; ssize_t ret; unsigned long flags; unsigned swptr; int cnt; VALIDATE_STATE(s); if (ppos != &file->f_pos) return -ESPIPE; if (s->dma_dac.mapped) return -ENXIO; if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; ret = 0;#if 0 spin_lock_irqsave(&s->lock, flags); cm_update_ptr(s); spin_unlock_irqrestore(&s->lock, flags);#endif while (count > 0) { spin_lock_irqsave(&s->lock, flags); if (s->dma_dac.count < 0) { s->dma_dac.count = 0; s->dma_dac.swptr = s->dma_dac.hwptr; } swptr = s->dma_dac.swptr; cnt = s->dma_dac.dmasize-swptr; if (s->dma_dac.count + cnt > s->dma_dac.dmasize) cnt = s->dma_dac.dmasize - s->dma_dac.count; spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { start_dac(s); if (file->f_flags & O_NONBLOCK) return ret ? ret : -EAGAIN; if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, s->dma_dac.hwptr, s->dma_dac.swptr); stop_dac(s); spin_lock_irqsave(&s->lock, flags); set_dmadac(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.dmasamples); /* program sample counts */ outw(s->dma_dac.fragsamples-1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2); s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; spin_unlock_irqrestore(&s->lock, flags); } if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; continue; } if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) return ret ? ret : -EFAULT; swptr = (swptr + cnt) % s->dma_dac.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_dac.swptr = swptr; s->dma_dac.count += cnt; s->dma_dac.endcleared = 0; spin_unlock_irqrestore(&s->lock, flags); count -= cnt; buffer += cnt; ret += cnt; start_dac(s); } return ret;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -