📄 msnd_pinnacle.c
字号:
/* digital controls */ case SOUND_MIXER_SYNTH: /* synth vol (dsp mix) */ case SOUND_MIXER_PCM: /* pcm vol (dsp mix) */ case SOUND_MIXER_IMIX: /* input monitor (dsp mix) */ /* scaled by master volume */ updatemaster = 1; break; default: return 0; } if (updatemaster) { /* update master volume scaled controls */ update_volm(SOUND_MIXER_PCM, wCurrPlayVol); update_volm(SOUND_MIXER_IMIX, wCurrInVol);#ifndef MSND_CLASSIC update_volm(SOUND_MIXER_SYNTH, wCurrMHdrVol);#endif update_potm(SOUND_MIXER_LINE1, bAuxPotPos, HDEXAR_AUX_SET_POTS); } return mixer_get(d);}static void mixer_setup(void){ update_pot(SOUND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS); update_potm(SOUND_MIXER_LINE1, bAuxPotPos, HDEXAR_AUX_SET_POTS); update_volm(SOUND_MIXER_PCM, wCurrPlayVol); update_volm(SOUND_MIXER_IMIX, wCurrInVol);#ifndef MSND_CLASSIC update_pot(SOUND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS); update_volm(SOUND_MIXER_SYNTH, wCurrMHdrVol);#endif}static unsigned long set_recsrc(unsigned long recsrc){ if (dev.recsrc == recsrc) return dev.recsrc;#ifdef HAVE_NORECSRC else if (recsrc == 0) dev.recsrc = 0;#endif else dev.recsrc ^= recsrc;#ifndef MSND_CLASSIC if (dev.recsrc & SOUND_MASK_IMIX) { if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0) chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); } else if (dev.recsrc & SOUND_MASK_SYNTH) { if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_SYNTH_IN) == 0) chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); } else if ((dev.recsrc & SOUND_MASK_DIGITAL1) && test_bit(F_HAVEDIGITAL, &dev.flags)) { if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_DAT_IN) == 0) chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); } else {#ifdef HAVE_NORECSRC /* Select no input (?) */ dev.recsrc = 0;#else dev.recsrc = SOUND_MASK_IMIX; if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0) chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);#endif }#endif /* MSND_CLASSIC */ return dev.recsrc;}static unsigned long force_recsrc(unsigned long recsrc){ dev.recsrc = 0; return set_recsrc(recsrc);}#define set_mixer_info() \ strncpy(info.id, "MSNDMIXER", sizeof(info.id)); \ strncpy(info.name, "MultiSound Mixer", sizeof(info.name));static int mixer_ioctl(unsigned int cmd, unsigned long arg){ if (cmd == SOUND_MIXER_INFO) { mixer_info info; set_mixer_info(); info.modify_counter = dev.mixer_mod_count; return copy_to_user((void *)arg, &info, sizeof(info)); } else if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; set_mixer_info(); return copy_to_user((void *)arg, &info, sizeof(info)); } else if (cmd == SOUND_MIXER_PRIVATE1) { dev.nresets = 0; dsp_full_reset(); return 0; } else if (((cmd >> 8) & 0xff) == 'M') { int val = 0; if (_SIOC_DIR(cmd) & _SIOC_WRITE) { switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: if (get_user(val, (int *)arg)) return -EFAULT; val = set_recsrc(val); break; default: if (get_user(val, (int *)arg)) return -EFAULT; val = mixer_set(cmd & 0xff, val); break; } ++dev.mixer_mod_count; return put_user(val, (int *)arg); } else { switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: val = dev.recsrc; break; case SOUND_MIXER_DEVMASK: case SOUND_MIXER_STEREODEVS: val = SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_IMIX | SOUND_MASK_LINE1 |#ifndef MSND_CLASSIC SOUND_MASK_MIC | SOUND_MASK_SYNTH |#endif SOUND_MASK_VOLUME; break; case SOUND_MIXER_RECMASK:#ifdef MSND_CLASSIC val = 0;#else val = SOUND_MASK_IMIX | SOUND_MASK_SYNTH; if (test_bit(F_HAVEDIGITAL, &dev.flags)) val |= SOUND_MASK_DIGITAL1;#endif break; case SOUND_MIXER_CAPS: val = SOUND_CAP_EXCL_INPUT; break; default: if ((val = mixer_get(cmd & 0xff)) < 0) return -EINVAL; break; } } return put_user(val, (int *)arg); } return -EINVAL;}static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int minor = MINOR(inode->i_rdev); if (cmd == OSS_GETVERSION) { int sound_version = SOUND_VERSION; return put_user(sound_version, (int *)arg); } if (minor == dev.dsp_minor) return dsp_ioctl(file, cmd, arg); else if (minor == dev.mixer_minor) return mixer_ioctl(cmd, arg); return -EINVAL;}static void dsp_write_flush(void){ if (!(dev.mode & FMODE_WRITE) || !test_bit(F_WRITING, &dev.flags)) return; set_bit(F_WRITEFLUSH, &dev.flags); interruptible_sleep_on_timeout( &dev.writeflush, get_play_delay_jiffies(dev.DAPF.len)); clear_bit(F_WRITEFLUSH, &dev.flags); if (!signal_pending(current)) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(get_play_delay_jiffies(DAP_BUFF_SIZE)); } clear_bit(F_WRITING, &dev.flags);}static void dsp_halt(struct file *file){ if ((file ? file->f_mode : dev.mode) & FMODE_READ) { clear_bit(F_READING, &dev.flags); chk_send_dsp_cmd(&dev, HDEX_RECORD_STOP); msnd_disable_irq(&dev); if (file) { printk(KERN_DEBUG LOGNAME ": Stopping read for %p\n", file); dev.mode &= ~FMODE_READ; } clear_bit(F_AUDIO_READ_INUSE, &dev.flags); } if ((file ? file->f_mode : dev.mode) & FMODE_WRITE) { if (test_bit(F_WRITING, &dev.flags)) { dsp_write_flush(); chk_send_dsp_cmd(&dev, HDEX_PLAY_STOP); } msnd_disable_irq(&dev); if (file) { printk(KERN_DEBUG LOGNAME ": Stopping write for %p\n", file); dev.mode &= ~FMODE_WRITE; } clear_bit(F_AUDIO_WRITE_INUSE, &dev.flags); }}static int dsp_release(struct file *file){ dsp_halt(file); return 0;}static int dsp_open(struct file *file){ if ((file ? file->f_mode : dev.mode) & FMODE_WRITE) { set_bit(F_AUDIO_WRITE_INUSE, &dev.flags); clear_bit(F_WRITING, &dev.flags); msnd_fifo_make_empty(&dev.DAPF); reset_play_queue(); if (file) { printk(KERN_DEBUG LOGNAME ": Starting write for %p\n", file); dev.mode |= FMODE_WRITE; } msnd_enable_irq(&dev); } if ((file ? file->f_mode : dev.mode) & FMODE_READ) { set_bit(F_AUDIO_READ_INUSE, &dev.flags); clear_bit(F_READING, &dev.flags); msnd_fifo_make_empty(&dev.DARF); reset_record_queue(); if (file) { printk(KERN_DEBUG LOGNAME ": Starting read for %p\n", file); dev.mode |= FMODE_READ; } msnd_enable_irq(&dev); } return 0;}static void set_default_play_audio_parameters(void){ dev.play_sample_size = DEFSAMPLESIZE; dev.play_sample_rate = DEFSAMPLERATE; dev.play_channels = DEFCHANNELS;}static void set_default_rec_audio_parameters(void){ dev.rec_sample_size = DEFSAMPLESIZE; dev.rec_sample_rate = DEFSAMPLERATE; dev.rec_channels = DEFCHANNELS;}static void set_default_audio_parameters(void){ set_default_play_audio_parameters(); set_default_rec_audio_parameters();}static int dev_open(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); int err = 0; if (minor == dev.dsp_minor) { if ((file->f_mode & FMODE_WRITE && test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) || (file->f_mode & FMODE_READ && test_bit(F_AUDIO_READ_INUSE, &dev.flags))) return -EBUSY; if ((err = dsp_open(file)) >= 0) { dev.nresets = 0; if (file->f_mode & FMODE_WRITE) { set_default_play_audio_parameters(); if (!test_bit(F_DISABLE_WRITE_NDELAY, &dev.flags)) dev.play_ndelay = (file->f_flags & O_NDELAY) ? 1 : 0; else dev.play_ndelay = 0; } if (file->f_mode & FMODE_READ) { set_default_rec_audio_parameters(); dev.rec_ndelay = (file->f_flags & O_NDELAY) ? 1 : 0; } } } else if (minor == dev.mixer_minor) { /* nothing */ } else err = -EINVAL; return err;}static int dev_release(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); int err = 0; lock_kernel(); if (minor == dev.dsp_minor) err = dsp_release(file); else if (minor == dev.mixer_minor) { /* nothing */ } else err = -EINVAL; unlock_kernel(); return err;}static __inline__ int pack_DARQ_to_DARF(register int bank){ register int size, n, timeout = 3; register WORD wTmp; LPDAQD DAQD; /* Increment the tail and check for queue wrap */ wTmp = isa_readw(dev.DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size); if (wTmp > isa_readw(dev.DARQ + JQS_wSize)) wTmp = 0; while (wTmp == isa_readw(dev.DARQ + JQS_wHead) && timeout--) udelay(1); isa_writew(wTmp, dev.DARQ + JQS_wTail); /* Get our digital audio queue struct */ DAQD = bank * DAQDS__size + dev.base + DARQ_DATA_BUFF; /* Get length of data */ size = isa_readw(DAQD + DAQDS_wSize); /* Read data from the head (unprotected bank 1 access okay since this is only called inside an interrupt) */ outb(HPBLKSEL_1, dev.io + HP_BLKS); if ((n = msnd_fifo_write( &dev.DARF, (char *)(dev.base + bank * DAR_BUFF_SIZE), size, 0)) <= 0) { outb(HPBLKSEL_0, dev.io + HP_BLKS); return n; } outb(HPBLKSEL_0, dev.io + HP_BLKS); return 1;}static __inline__ int pack_DAPF_to_DAPQ(register int start){ register WORD DAPQ_tail; register int protect = start, nbanks = 0; LPDAQD DAQD; DAPQ_tail = isa_readw(dev.DAPQ + JQS_wTail); while (DAPQ_tail != isa_readw(dev.DAPQ + JQS_wHead) || start) { register int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size); register int n; unsigned long flags; /* Write the data to the new tail */ if (protect) { /* Critical section: protect fifo in non-interrupt */ spin_lock_irqsave(&dev.lock, flags); if ((n = msnd_fifo_read( &dev.DAPF, (char *)(dev.base + bank_num * DAP_BUFF_SIZE), DAP_BUFF_SIZE, 0)) < 0) { spin_unlock_irqrestore(&dev.lock, flags); return n; } spin_unlock_irqrestore(&dev.lock, flags); } else { if ((n = msnd_fifo_read( &dev.DAPF, (char *)(dev.base + bank_num * DAP_BUFF_SIZE), DAP_BUFF_SIZE, 0)) < 0) { return n; } } if (!n) break; if (start) start = 0; /* Get our digital audio queue struct */ DAQD = bank_num * DAQDS__size + dev.base + DAPQ_DATA_BUFF; /* Write size of this bank */ isa_writew(n, DAQD + DAQDS_wSize); ++nbanks; /* Then advance the tail */ DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size); isa_writew(DAPQ_tail, dev.DAPQ + JQS_wTail); /* Tell the DSP to play the bank */ msnd_send_dsp_cmd(&dev, HDEX_PLAY_START); } return nbanks;}static int dsp_read(char *buf, size_t len){ int count = len; while (count > 0) { int n; unsigned long flags; /* Critical section: protect fifo in non-interrupt */ spin_lock_irqsave(&dev.lock, flags); if ((n = msnd_fifo_read(&dev.DARF, buf, count, 1)) < 0) { printk(KERN_WARNING LOGNAME ": FIFO read error\n"); spin_unlock_irqrestore(&dev.lock, flags); return n; } spin_unlock_irqrestore(&dev.lock, flags); buf += n; count -= n; if (!test_bit(F_READING, &dev.flags) && dev.mode & FMODE_READ) { dev.last_recbank = -1; if (chk_send_dsp_cmd(&dev, HDEX_RECORD_START) == 0) set_bit(F_READING, &dev.flags); } if (dev.rec_ndelay) return count == len ? -EAGAIN : len - count; if (count > 0) { set_bit(F_READBLOCK, &dev.flags); if (!interruptible_sleep_on_timeout( &dev.readblock, get_rec_delay_jiffies(DAR_BUFF_SIZE))) clear_bit(F_READING, &dev.flags); clear_bit(F_READBLOCK, &dev.flags); if (signal_pending(current)) return -EINTR; } } return len - count;}static int dsp_write(const char *buf, size_t len){ int count = len; while (count > 0) { int n; unsigned long flags; /* Critical section: protect fifo in non-interrupt */ spin_lock_irqsave(&dev.lock, flags); if ((n = msnd_fifo_write(&dev.DAPF, buf, count, 1)) < 0) { printk(KERN_WARNING LOGNAME ": FIFO write error\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -