📄 waveartist.c
字号:
waveartist_cmd2(devc, WACMD_INPUTSIZE, count); devc->xfer_count = count; devc->audio_mode |= PCM_ENABLE_INPUT; spin_unlock_irqrestore(&waveartist_lock, flags);}static intwaveartist_ioctl(int dev, unsigned int cmd, caddr_t arg){ return -EINVAL;}static unsigned intwaveartist_get_speed(wavnc_port_info *portc){ unsigned int speed; /* * program the speed, channels, bits */ if (portc->speed == 8000) speed = 0x2E71; else if (portc->speed == 11025) speed = 0x4000; else if (portc->speed == 22050) speed = 0x8000; else if (portc->speed == 44100) speed = 0x0; else { /* * non-standard - just calculate */ speed = portc->speed << 16; speed = (speed / 44100) & 65535; } return speed;}static unsigned intwaveartist_get_bits(wavnc_port_info *portc){ unsigned int bits; if (portc->audio_format == AFMT_S16_LE) bits = 1; else if (portc->audio_format == AFMT_S8) bits = 0; else bits = 2; //default AFMT_U8 return bits;}static intwaveartist_prepare_for_input(int dev, int bsize, int bcount){ 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; speed = waveartist_get_speed(portc); bits = waveartist_get_bits(portc); spin_lock_irqsave(&waveartist_lock, flags); if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) printk(KERN_WARNING "waveartist: error setting the " "record format to %d\n", portc->audio_format); if (waveartist_cmd2(devc, WACMD_INPUTCHANNELS, portc->channels)) printk(KERN_WARNING "waveartist: error setting record " "to %d channels\n", portc->channels); /* * write cmd SetSampleSpeedTimeConstant */ if (waveartist_cmd2(devc, WACMD_INPUTSPEED, speed)) printk(KERN_WARNING "waveartist: error setting the record " "speed to %dHz.\n", portc->speed); if (waveartist_cmd2(devc, WACMD_INPUTDMA, 1)) printk(KERN_WARNING "waveartist: error setting the record " "data path to 0x%X\n", 1); if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits)) printk(KERN_WARNING "waveartist: error setting the record " "format to %d\n", portc->audio_format); devc->xfer_count = 0; spin_unlock_irqrestore(&waveartist_lock, flags); waveartist_halt_input(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 intwaveartist_prepare_for_output(int dev, int bsize, int bcount){ 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 */struct mix_ent { unsigned char reg_l; unsigned char reg_r; unsigned char shift; unsigned char max;};static const struct mix_ent mix_devs[SOUND_MIXER_NRDEVICES] = { { 2, 6, 1, 7 }, /* SOUND_MIXER_VOLUME */ { 0, 0, 0, 0 }, /* SOUND_MIXER_BASS */ { 0, 0, 0, 0 }, /* SOUND_MIXER_TREBLE */ { 0, 0, 0, 0 }, /* SOUND_MIXER_SYNTH */ { 0, 0, 0, 0 }, /* SOUND_MIXER_PCM */ { 0, 0, 0, 0 }, /* SOUND_MIXER_SPEAKER */ { 0, 4, 6, 31 }, /* SOUND_MIXER_LINE */ { 2, 6, 4, 3 }, /* SOUND_MIXER_MIC */ { 0, 0, 0, 0 }, /* SOUND_MIXER_CD */ { 0, 0, 0, 0 }, /* SOUND_MIXER_IMIX */ { 0, 0, 0, 0 }, /* SOUND_MIXER_ALTPCM */#if 0 { 3, 7, 0, 10 }, /* SOUND_MIXER_RECLEV */ { 0, 0, 0, 0 }, /* SOUND_MIXER_IGAIN */#else { 0, 0, 0, 0 }, /* SOUND_MIXER_RECLEV */ { 3, 7, 0, 7 }, /* SOUND_MIXER_IGAIN */#endif { 0, 0, 0, 0 }, /* SOUND_MIXER_OGAIN */ { 0, 4, 1, 31 }, /* SOUND_MIXER_LINE1 */ { 1, 5, 6, 31 }, /* SOUND_MIXER_LINE2 */ { 0, 0, 0, 0 }, /* SOUND_MIXER_LINE3 */ { 0, 0, 0, 0 }, /* SOUND_MIXER_DIGITAL1 */ { 0, 0, 0, 0 }, /* SOUND_MIXER_DIGITAL2 */ { 0, 0, 0, 0 }, /* SOUND_MIXER_DIGITAL3 */ { 0, 0, 0, 0 }, /* SOUND_MIXER_PHONEIN */ { 0, 0, 0, 0 }, /* SOUND_MIXER_PHONEOUT */ { 0, 0, 0, 0 }, /* SOUND_MIXER_VIDEO */ { 0, 0, 0, 0 }, /* SOUND_MIXER_RADIO */ { 0, 0, 0, 0 } /* SOUND_MIXER_MONITOR */};static voidwaveartist_mixer_update(wavnc_info *devc, int whichDev){ unsigned int lev_left, lev_right; lev_left = devc->levels[whichDev] & 0xff; lev_right = devc->levels[whichDev] >> 8; if (lev_left > 100) lev_left = 100; if (lev_right > 100) lev_right = 100;#define SCALE(lev,max) ((lev) * (max) / 100) if (machine_is_netwinder() && whichDev == SOUND_MIXER_PHONEOUT) whichDev = SOUND_MIXER_VOLUME; if (mix_devs[whichDev].reg_l || mix_devs[whichDev].reg_r) { const struct mix_ent *mix = mix_devs + whichDev; unsigned int mask, left, right; mask = mix->max << mix->shift; lev_left = SCALE(lev_left, mix->max) << mix->shift; lev_right = SCALE(lev_right, mix->max) << mix->shift; /* read left setting */ left = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | mix->reg_l << 8); /* read right setting */ right = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | mix->reg_r << 8); left = (left & ~mask) | (lev_left & mask); right = (right & ~mask) | (lev_right & mask); /* write left,right back */ waveartist_cmd3(devc, WACMD_SET_MIXER, left, right); } else { switch(whichDev) { case SOUND_MIXER_PCM: waveartist_cmd3(devc, WACMD_SET_LEVEL, SCALE(lev_left, 32767), SCALE(lev_right, 32767)); break; case SOUND_MIXER_SYNTH: waveartist_cmd3(devc, 0x0100 | WACMD_SET_LEVEL, SCALE(lev_left, 32767), SCALE(lev_right, 32767)); break; } }}/* * Set the ADC MUX to the specified values. We do NOT do any * checking of the values passed, since we assume that the * relevant *_select_input function has done that for us. */static voidwaveartist_set_adc_mux(wavnc_info *devc, char left_dev, char right_dev){ unsigned int reg_08, reg_09; reg_08 = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x0800); reg_09 = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x0900); reg_08 = (reg_08 & ~0x3f) | right_dev << 3 | left_dev; waveartist_cmd3(devc, WACMD_SET_MIXER, reg_08, reg_09);}/* * Decode a recording mask into a mixer selection as follows: * * OSS Source WA Source Actual source * SOUND_MASK_IMIX Mixer Mixer output (same as AD1848) * SOUND_MASK_LINE Line Line in * SOUND_MASK_LINE1 Aux 1 Aux 1 in * SOUND_MASK_LINE2 Aux 2 Aux 2 in * SOUND_MASK_MIC Mic Microphone */static unsigned intwaveartist_select_input(wavnc_info *devc, unsigned int recmask, unsigned char *dev_l, unsigned char *dev_r){ unsigned int recdev = ADC_MUX_NONE; if (recmask & SOUND_MASK_IMIX) { recmask = SOUND_MASK_IMIX; recdev = ADC_MUX_MIXER; } else if (recmask & SOUND_MASK_LINE2) { recmask = SOUND_MASK_LINE2; recdev = ADC_MUX_AUX2; } else if (recmask & SOUND_MASK_LINE1) { recmask = SOUND_MASK_LINE1; recdev = ADC_MUX_AUX1; } else if (recmask & SOUND_MASK_LINE) { recmask = SOUND_MASK_LINE; recdev = ADC_MUX_LINE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -