📄 waveartist.c
字号:
{ unsigned long flags; wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; unsigned int speed, bits; /* * program the speed, channels, bits */ speed = waveartist_get_speed(portc); bits = waveartist_get_bits(portc); spin_lock_irqsave(&waveartist_lock, flags); if (waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed) && waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed)) printk(KERN_WARNING "waveartist: error setting the playback " "speed to %dHz.\n", portc->speed); if (waveartist_cmd2(devc, WACMD_OUTPUTCHANNELS, portc->channels)) printk(KERN_WARNING "waveartist: error setting the playback " "to %d channels\n", portc->channels); if (waveartist_cmd2(devc, WACMD_OUTPUTDMA, 0)) printk(KERN_WARNING "waveartist: error setting the playback " "data path to 0x%X\n", 0); if (waveartist_cmd2(devc, WACMD_OUTPUTFORMAT, bits)) printk(KERN_WARNING "waveartist: error setting the playback " "format to %d\n", portc->audio_format); devc->xfer_count = 0; spin_unlock_irqrestore(&waveartist_lock, flags); waveartist_halt_output(dev); if (debug_flg & DEBUG_INTR) { printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR)); printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR)); printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT)); } return 0;}static voidwaveartist_halt(int dev){ wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; wavnc_info *devc; if (portc->open_mode & OPEN_WRITE) waveartist_halt_output(dev); if (portc->open_mode & OPEN_READ) waveartist_halt_input(dev); devc = (wavnc_info *) audio_devs[dev]->devc; devc->audio_mode = 0;}static voidwaveartist_halt_input(int dev){ wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; unsigned long flags; spin_lock_irqsave(&waveartist_lock, flags); /* * Stop capture */ waveartist_cmd1(devc, WACMD_INPUTSTOP); devc->audio_mode &= ~PCM_ENABLE_INPUT; /* * Clear interrupt by toggling * the IRQ_ACK bit in CTRL */ if (inb(devc->hw.io_base + STATR) & IRQ_REQ) waveartist_iack(devc);// devc->audio_mode &= ~PCM_ENABLE_INPUT; spin_unlock_irqrestore(&waveartist_lock, flags);}static voidwaveartist_halt_output(int dev){ wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; unsigned long flags; spin_lock_irqsave(&waveartist_lock, flags); waveartist_cmd1(devc, WACMD_OUTPUTSTOP); devc->audio_mode &= ~PCM_ENABLE_OUTPUT; /* * Clear interrupt by toggling * the IRQ_ACK bit in CTRL */ if (inb(devc->hw.io_base + STATR) & IRQ_REQ) waveartist_iack(devc);// devc->audio_mode &= ~PCM_ENABLE_OUTPUT; spin_unlock_irqrestore(&waveartist_lock, flags);}static voidwaveartist_trigger(int dev, int state){ wavnc_info *devc = (wavnc_info *) audio_devs[dev]->devc; wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; unsigned long flags; if (debug_flg & DEBUG_TRIGGER) { printk("wavnc: audio trigger "); if (state & PCM_ENABLE_INPUT) printk("in "); if (state & PCM_ENABLE_OUTPUT) printk("out"); printk("\n"); } spin_lock_irqsave(&waveartist_lock, flags); state &= devc->audio_mode; if (portc->open_mode & OPEN_READ && state & PCM_ENABLE_INPUT) /* * enable ADC Data Transfer to PC */ waveartist_cmd1(devc, WACMD_INPUTSTART); if (portc->open_mode & OPEN_WRITE && state & PCM_ENABLE_OUTPUT) /* * enable DAC data transfer from PC */ waveartist_cmd1(devc, WACMD_OUTPUTSTART); spin_unlock_irqrestore(&waveartist_lock, flags);}static intwaveartist_set_speed(int dev, int arg){ wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; if (arg <= 0) return portc->speed; if (arg < 5000) arg = 5000; if (arg > 44100) arg = 44100; portc->speed = arg; return portc->speed;}static shortwaveartist_set_channels(int dev, short arg){ wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; if (arg != 1 && arg != 2) return portc->channels; portc->channels = arg; return arg;}static unsigned intwaveartist_set_bits(int dev, unsigned int arg){ wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; if (arg == 0) return portc->audio_format; if ((arg != AFMT_U8) && (arg != AFMT_S16_LE) && (arg != AFMT_S8)) arg = AFMT_U8; portc->audio_format = arg; return arg;}static struct audio_driver waveartist_audio_driver = { owner: THIS_MODULE, open: waveartist_open, close: waveartist_close, output_block: waveartist_output_block, start_input: waveartist_start_input, ioctl: waveartist_ioctl, prepare_for_input: waveartist_prepare_for_input, prepare_for_output: waveartist_prepare_for_output, halt_io: waveartist_halt, halt_input: waveartist_halt_input, halt_output: waveartist_halt_output, trigger: waveartist_trigger, set_speed: waveartist_set_speed, set_bits: waveartist_set_bits, set_channels: waveartist_set_channels};static voidwaveartist_intr(int irq, void *dev_id, struct pt_regs *regs){ wavnc_info *devc = (wavnc_info *)dev_id; int irqstatus, status; irqstatus = inb(devc->hw.io_base + IRQSTAT); status = inb(devc->hw.io_base + STATR); if (debug_flg & DEBUG_INTR) printk("waveartist_intr: stat=%02x, irqstat=%02x\n", status, irqstatus); if (status & IRQ_REQ) /* Clear interrupt */ waveartist_iack(devc); else printk(KERN_WARNING "waveartist: unexpected interrupt\n"); if (irqstatus & 0x01) { int temp = 1; /* PCM buffer done */ if ((status & DMA0) && (devc->audio_mode & PCM_ENABLE_OUTPUT)) { DMAbuf_outputintr(devc->playback_dev, 1); temp = 0; } if ((status & DMA1) && (devc->audio_mode & PCM_ENABLE_INPUT)) { DMAbuf_inputintr(devc->record_dev); temp = 0; } if (temp) //default: printk(KERN_WARNING "waveartist: Unknown interrupt\n"); } if (irqstatus & 0x2) // We do not use SB mode natively... printk(KERN_WARNING "waveartist: Unexpected SB interrupt...\n");}/* ------------------------------------------------------------------------- * Mixer stuff */static voidwaveartist_mixer_update(wavnc_info *devc, int whichDev){ unsigned int mask, reg_l, reg_r; unsigned int lev_left, lev_right; unsigned int vals[3]; lev_left = devc->levels[whichDev] & 0xff; lev_right = devc->levels[whichDev] >> 8;#define SCALE(lev,max) ((lev) * (max) / 100) if (machine_is_netwinder() && whichDev == SOUND_MIXER_PHONEOUT) whichDev = SOUND_MIXER_VOLUME; switch(whichDev) { case SOUND_MIXER_VOLUME: mask = 0x000e; reg_l = 0x200; reg_r = 0x600; lev_left = SCALE(lev_left, 7) << 1; lev_right = SCALE(lev_right, 7) << 1; break; case SOUND_MIXER_LINE: if ((devc->recmask & SOUND_MASK_LINE) == 0) return; mask = 0x07c0; reg_l = 0x000; reg_r = 0x400; lev_left = SCALE(lev_left, 31) << 6; lev_right = SCALE(lev_right, 31) << 6; break; case SOUND_MIXER_MIC: if ((devc->recmask & SOUND_MASK_MIC) == 0) return; mask = 0x0030; reg_l = 0x200; reg_r = 0x600; lev_left = SCALE(lev_left, 3) << 4; lev_right = SCALE(lev_right, 3) << 4; break; case SOUND_MIXER_RECLEV: mask = 0x000f; reg_l = 0x300; reg_r = 0x700; lev_left = SCALE(lev_left, 10); lev_right = SCALE(lev_right, 10); break; case SOUND_MIXER_LINE1: if ((devc->recmask & SOUND_MASK_LINE1) == 0) return; mask = 0x003e; reg_l = 0x000; reg_r = 0x400; lev_left = SCALE(lev_left, 31) << 1; lev_right = SCALE(lev_right, 31) << 1; break; case SOUND_MIXER_PCM: waveartist_cmd3(devc, WACMD_SET_LEVEL, SCALE(lev_left, 32767), SCALE(lev_right, 32767)); return; case SOUND_MIXER_SYNTH: waveartist_cmd3(devc, 0x0100 | WACMD_SET_LEVEL, SCALE(lev_left, 32767), SCALE(lev_right, 32767)); return; default: return; } /* read left setting */ vals[0] = reg_l + WACMD_GET_LEVEL; waveartist_cmd(devc, 1, vals, 1, vals + 1); /* read right setting */ vals[0] = reg_r + 0x30; waveartist_cmd(devc, 1, vals, 1, vals + 2); vals[1] = (vals[1] & ~mask) | (lev_left & mask); vals[2] = (vals[2] & ~mask) | (lev_right & mask); /* write left,right back */ vals[0] = WACMD_SET_MIXER; waveartist_cmd(devc, 3, vals, 0, NULL);}static voidwaveartist_select_input(wavnc_info *devc, unsigned int input){ unsigned int vals[3]; /* * Get reg 9 */ vals[0] = 0x0830; waveartist_cmd(devc, 1, vals, 1, vals + 1); /* * Get reg 10, only so that we can write it back. */ vals[0] = 0x0930; waveartist_cmd(devc, 1, vals, 1, vals + 2); if (debug_flg & DEBUG_MIXER) printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n", vals[1] & 0x07, (vals[1] >> 3) & 0x07); /* * kill current left/right mux input select */ vals[1] &= ~0x03F; switch (input) { case SOUND_MASK_MIC: /* * right=mic, left=mic */ vals[1] |= 0x002D; break; case SOUND_MASK_LINE1: /* * right=none, left=Aux1; */ vals[1] |= 0x0004; break; case SOUND_MASK_LINE: /* * right=Line, left=Line; */ vals[1] |= 0x0012; break; } if (debug_flg & DEBUG_MIXER) printk("RECSRC %d: left=0x%04X, right=0x%04X.\n", input, vals[1] & 0x07, (vals[1] >> 3) & 0x07); /* * and finally - write the reg pair back.... */ vals[0] = WACMD_SET_MIXER; waveartist_cmd(devc, 3, vals, 0, NULL);}static intwaveartist_mixer_set(wavnc_info *devc, int whichDev, unsigned int level){ unsigned int lev_left = level & 0x007f; unsigned int lev_right = (level & 0x7f00) >> 8; int left, right, devmask; left = level & 0x7f; right = (level & 0x7f00) >> 8; if (debug_flg & DEBUG_MIXER) printk("wa_mixer_set(dev=%d, level=%X)\n", whichDev, level); switch (whichDev) { case SOUND_MIXER_VOLUME: /* master volume (0-7) */ case SOUND_MIXER_LINE: /* external line (0-31) */ case SOUND_MIXER_MIC: /* mono mic (0-3) */ case SOUND_MIXER_RECLEV: /* recording level (0-7) */ case SOUND_MIXER_LINE1: /* mono external aux1 (0-31) */ case SOUND_MIXER_PCM: /* Waveartist PCM (0-32767) */ case SOUND_MIXER_SYNTH: /* internal synth (0-31) */ case SOUND_MIXER_IMIX: /* recording feedback */ devc->levels[whichDev] = lev_left | lev_right << 8; waveartist_mixer_update(devc, whichDev); break; /* Select recording input source */ case SOUND_MIXER_RECSRC: devmask = level & devc->rec_devices;#ifdef CONFIG_ARCH_NETWINDER if (machine_is_netwinder()) vnc_configure_mixer(devc); else#endif { waveartist_select_input(devc, level); /* * if record monitoring is on, make sure the bit is set */ if (devc->levels[SOUND_MIXER_IMIX]) waveartist_mixer_update(devc, SOUND_MIXER_IMIX); } /* * do not save in "levels", return current setting */ return devc->recmask; default: return -EINVAL; } return devc->levels[whichDev];}static voidwaveartist_mixer_reset(wavnc_info *devc){ int i; if (debug_flg & DEBUG_MIXER) printk("%s: mixer_reset\n", devc->hw.name); /* * reset mixer cmd */ waveartist_cmd1(devc, WACMD_RST_MIXER); /* * set input for ADC to come from 'quiet' * turn on default modes */ waveartist_cmd3(devc, WACMD_SET_MIXER, 0x9800, 0xa836); /* * set mixer input select to none, RX filter gains 0 db */ waveartist_cmd3(devc, WACMD_SET_MIXER, 0x4c00, 0x8c00); /* * set bit 0 reg 2 to 1 - unmute MonoOut */ waveartist_cmd3(devc, WACMD_SET_MIXER, 0x2801, 0x6800); /* set default input device = internal mic * current recording device = none */ devc->recmask = 0; for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) waveartist_mixer_update(devc, i); devc->supported_devices = SUPPORTED_MIXER_DEVICES; devc->rec_devices = POSSIBLE_RECORDING_DEVICES; if (machine_is_netwinder()) { devc->supported_devices |= SOUND_MASK_PHONEIN | SOUND_MASK_PHONEOUT; devc->rec_devices |= SOUND_MASK_PHONEIN; }}static intwaveartist_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg){ wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc; int ret;#ifdef CONFIG_ARCH_NETWINDER if (machine_is_netwinder()) { ret = vnc_private_ioctl(dev, cmd, arg); if (ret != -ENOIOCTLCMD) return ret; }#endif if (((cmd >> 8) & 0xff) == 'M') { if (_SIOC_DIR(cmd) & _SIOC_WRITE) { int val; if (get_user(val, (int *)arg)) return -EFAULT; return waveartist_mixer_set(devc, cmd & 0xff, val); } else { /* * Return parameters */ switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: ret = devc->recmask; break; case SOUND_MIXER_DEVMASK: ret = devc->supported_devices; break; case SOUND_MIXER_STEREODEVS: ret = devc->supported_devices & ~(SOUND_MASK_SPEAKER|SOUND_MASK_IMIX); break; case SOUND_MIXER_RECMASK: ret = devc->rec_devices; break; case SOUND_MIXER_CAPS: ret = SOUND_CAP_EXCL_INPUT; break; default: if ((cmd & 0xff) < SOUND_MIXER_NRDEVICES) ret = devc->levels[cmd & 0xff]; else return -EINVAL; } return put_user(ret, (int *)arg) ? -EFAULT : 0; } } return -ENOIOCTLCMD;}static struct mixer_operations waveartist_mixer_operations ={ owner: THIS_MODULE, id: "WaveArtist", name: "WaveArtist NetWinder", ioctl: waveartist_mixer_ioctl};static int __init waveartist_init(wavnc_info *devc){ wavnc_port_info *portc; char rev[3], dev_name[64]; int my_dev; if (waveartist_reset(devc)) return -ENODEV; sprintf(dev_name, "%s (%s", devc->hw.name, devc->chip_name); if (waveartist_getrev(devc, rev)) { strcat(dev_name, " rev. "); strcat(dev_name, rev); } strcat(dev_name, ")"); conf_printf2(dev_name, devc->hw.io_base, devc->hw.irq, devc->hw.dma, devc->hw.dma2); portc = (wavnc_port_info *)kmalloc(sizeof(wavnc_port_info), GFP_KERNEL); if (portc == NULL) goto nomem; memset(portc, 0, sizeof(wavnc_port_info));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -