📄 trident.c
字号:
if (state->fmt_flag) { \ spin_unlock_irqrestore(&state->card->lock, flags); \ return -EFAULT; \ } \ state->fmt_flag = 1; \ spin_unlock_irqrestore(&state->card->lock, flags);} #define unlock_set_fmt(state) {spin_lock_irqsave(&state->card->lock, flags); \ state->fmt_flag = 0; \ spin_unlock_irqrestore(&state->card->lock, flags);}static int trident_enable_loop_interrupts(struct trident_card * card){ u32 global_control; global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR)); switch (card->pci_id) { case PCI_DEVICE_ID_SI_7018: global_control |= (ENDLP_IE | MIDLP_IE| BANK_B_EN); break; case PCI_DEVICE_ID_ALI_5451: case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: case PCI_DEVICE_ID_INTERG_5050: global_control |= (ENDLP_IE | MIDLP_IE); break; default: return FALSE; } outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));#ifdef DEBUG printk("trident: Enable Loop Interrupts, globctl = 0x%08X\n", inl(TRID_REG(card, T4D_LFO_GC_CIR)));#endif return (TRUE);}static int trident_disable_loop_interrupts(struct trident_card * card){ u32 global_control; global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR)); global_control &= ~(ENDLP_IE | MIDLP_IE); outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));#ifdef DEBUG printk("trident: Disabled Loop Interrupts, globctl = 0x%08X\n", global_control);#endif return (TRUE);}static void trident_enable_voice_irq(struct trident_card * card, unsigned int channel){ unsigned int mask = 1 << (channel & 0x1f); struct trident_pcm_bank *bank = &card->banks[channel >> 5]; u32 reg, addr = bank->addresses->aint_en; reg = inl(TRID_REG(card, addr)); reg |= mask; outl(reg, TRID_REG(card, addr));#ifdef DEBUG reg = inl(TRID_REG(card, addr)); printk("trident: enabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n", channel, addr==T4D_AINTEN_B? "AINTEN_B":"AINTEN_A",reg,addr);#endif}static void trident_disable_voice_irq(struct trident_card * card, unsigned int channel){ unsigned int mask = 1 << (channel & 0x1f); struct trident_pcm_bank *bank = &card->banks[channel >> 5]; u32 reg, addr = bank->addresses->aint_en; reg = inl(TRID_REG(card, addr)); reg &= ~mask; outl(reg, TRID_REG(card, addr)); /* Ack the channel in case the interrupt was set before we disable it. */ outl(mask, TRID_REG(card, bank->addresses->aint));#ifdef DEBUG reg = inl(TRID_REG(card, addr)); printk("trident: disabled IRQ on channel %d, %s = 0x%08x(addr:%X)\n", channel, addr==T4D_AINTEN_B? "AINTEN_B":"AINTEN_A",reg,addr);#endif}static void trident_start_voice(struct trident_card * card, unsigned int channel){ unsigned int mask = 1 << (channel & 0x1f); struct trident_pcm_bank *bank = &card->banks[channel >> 5]; u32 addr = bank->addresses->start;#ifdef DEBUG u32 reg;#endif outl(mask, TRID_REG(card, addr));#ifdef DEBUG reg = inl(TRID_REG(card, addr)); printk("trident: start voice on channel %d, %s = 0x%08x(addr:%X)\n", channel, addr==T4D_START_B? "START_B":"START_A",reg,addr);#endif}static void trident_stop_voice(struct trident_card * card, unsigned int channel){ unsigned int mask = 1 << (channel & 0x1f); struct trident_pcm_bank *bank = &card->banks[channel >> 5]; u32 addr = bank->addresses->stop;#ifdef DEBUG u32 reg;#endif outl(mask, TRID_REG(card, addr));#ifdef DEBUG reg = inl(TRID_REG(card, addr)); printk("trident: stop voice on channel %d, %s = 0x%08x(addr:%X)\n", channel, addr==T4D_STOP_B? "STOP_B":"STOP_A",reg,addr);#endif}static u32 trident_get_interrupt_mask (struct trident_card * card, unsigned int channel){ struct trident_pcm_bank *bank = &card->banks[channel]; u32 addr = bank->addresses->aint; return inl(TRID_REG(card, addr));}static int trident_check_channel_interrupt(struct trident_card * card, unsigned int channel){ unsigned int mask = 1 << (channel & 0x1f); u32 reg = trident_get_interrupt_mask (card, channel >> 5);#ifdef DEBUG if (reg & mask) printk("trident: channel %d has interrupt, %s = 0x%08x\n", channel,reg==T4D_AINT_B? "AINT_B":"AINT_A", reg);#endif return (reg & mask) ? TRUE : FALSE;}static void trident_ack_channel_interrupt(struct trident_card * card, unsigned int channel){ unsigned int mask = 1 << (channel & 0x1f); struct trident_pcm_bank *bank = &card->banks[channel >> 5]; u32 reg, addr = bank->addresses->aint; reg = inl(TRID_REG(card, addr)); reg &= mask; outl(reg, TRID_REG(card, addr));#ifdef DEBUG reg = inl(TRID_REG(card, T4D_AINT_B)); printk("trident: Ack channel %d interrupt, AINT_B = 0x%08x\n", channel, reg);#endif}static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *card){ struct trident_pcm_bank *bank; int idx; bank = &card->banks[BANK_B]; for (idx = 31; idx >= 0; idx--) { if (!(bank->bitmap & (1 << idx))) { struct trident_channel *channel = &bank->channels[idx]; bank->bitmap |= 1 << idx; channel->num = idx + 32; return channel; } } /* no more free channels available */ printk(KERN_ERR "trident: no more channels available on Bank B.\n"); return NULL;}static void trident_free_pcm_channel(struct trident_card *card, unsigned int channel){ int bank; unsigned char b; if (channel < 31 || channel > 63) return; if (card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_DX || card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_NX) { b = inb (TRID_REG(card, T4D_REC_CH)); if ((b & ~0x80) == channel) outb(0x0, TRID_REG(card, T4D_REC_CH)); } bank = channel >> 5; channel = channel & 0x1f; card->banks[bank].bitmap &= ~(1 << (channel));}static struct trident_channel * cyber_alloc_pcm_channel(struct trident_card *card){ struct trident_pcm_bank *bank; int idx; /* The cyberpro 5050 has only 32 voices and one bank */ /* .. at least they are not documented (if you want to call that * crap documentation), perhaps broken ? */ bank = &card->banks[BANK_A]; for (idx = 31; idx >= 0; idx--) { if (!(bank->bitmap & (1 << idx))) { struct trident_channel *channel = &bank->channels[idx]; bank->bitmap |= 1 << idx; channel->num = idx; return channel; } } /* no more free channels available */ printk(KERN_ERR "cyberpro5050: no more channels available on Bank A.\n"); return NULL;}static void cyber_free_pcm_channel(struct trident_card *card, unsigned int channel){ if (channel > 31) return; card->banks[BANK_A].bitmap &= ~(1 << (channel));}static inline void cyber_outidx(int port,int idx,int data){ outb(idx,port); outb(data,port+1);}static inline int cyber_inidx(int port,int idx){ outb(idx,port); return inb(port+1);}static int cyber_init_ritual(struct trident_card *card){ /* some black magic, taken from SDK samples */ /* remove this and nothing will work */ int portDat; int ret = 0; unsigned long flags; /* * Keep interrupts off for the configure - we don't want to * clash with another cyberpro config event */ save_flags(flags); cli(); portDat = cyber_inidx(CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE); /* enable, if it was disabled */ if( (portDat & CYBER_BMSK_AUENZ) != CYBER_BMSK_AUENZ_ENABLE ) { printk(KERN_INFO "cyberpro5050: enabling audio controller\n" ); cyber_outidx( CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE, portDat | CYBER_BMSK_AUENZ_ENABLE ); /* check again if hardware is enabled now */ portDat = cyber_inidx(CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE); } if( (portDat & CYBER_BMSK_AUENZ) != CYBER_BMSK_AUENZ_ENABLE ) { printk(KERN_ERR "cyberpro5050: initAudioAccess: no success\n" ); ret = -1; } else { cyber_outidx( CYBER_PORT_AUDIO, CYBER_IDX_IRQ_ENABLE, CYBER_BMSK_AUDIO_INT_ENABLE ); cyber_outidx( CYBER_PORT_AUDIO, 0xbf, 0x01 ); cyber_outidx( CYBER_PORT_AUDIO, 0xba, 0x20 ); cyber_outidx( CYBER_PORT_AUDIO, 0xbb, 0x08 ); cyber_outidx( CYBER_PORT_AUDIO, 0xbf, 0x02 ); cyber_outidx( CYBER_PORT_AUDIO, 0xb3, 0x06 ); cyber_outidx( CYBER_PORT_AUDIO, 0xbf, 0x00 ); } restore_flags(flags); return ret;}/* called with spin lock held */static int trident_load_channel_registers(struct trident_card *card, u32 *data, unsigned int channel){ int i; if (channel > 63) return FALSE; /* select hardware channel to write */ outb(channel, TRID_REG(card, T4D_LFO_GC_CIR)); /* Output the channel registers, but don't write register three to an ALI chip. */ for (i = 0; i < CHANNEL_REGS; i++) { if (i == 3 && card->pci_id == PCI_DEVICE_ID_ALI_5451) continue; outl(data[i], TRID_REG(card, CHANNEL_START + 4*i)); } if (card->pci_id == PCI_DEVICE_ID_ALI_5451 || card->pci_id == PCI_DEVICE_ID_INTERG_5050) { outl(ALI_EMOD_Still, TRID_REG(card, ALI_EBUF1)); outl(ALI_EMOD_Still, TRID_REG(card, ALI_EBUF2)); } return TRUE;}/* called with spin lock held */static int trident_write_voice_regs(struct trident_state *state){ unsigned int data[CHANNEL_REGS + 1]; struct trident_channel *channel; channel = state->dmabuf.channel; data[1] = channel->lba; data[4] = channel->control; switch (state->card->pci_id) { case PCI_DEVICE_ID_ALI_5451: data[0] = 0; /* Current Sample Offset */ data[2] = (channel->eso << 16) | (channel->delta & 0xffff); data[3] = 0; break; case PCI_DEVICE_ID_SI_7018: case PCI_DEVICE_ID_INTERG_5050: data[0] = 0; /* Current Sample Offset */ data[2] = (channel->eso << 16) | (channel->delta & 0xffff); data[3] = (channel->attribute << 16) | (channel->fm_vol & 0xffff); break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: data[0] = 0; /* Current Sample Offset */ data[2] = (channel->eso << 16) | (channel->delta & 0xffff); data[3] = channel->fm_vol & 0xffff; break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: data[0] = (channel->delta << 24); data[2] = ((channel->delta << 16) & 0xff000000) | (channel->eso & 0x00ffffff); data[3] = channel->fm_vol & 0xffff; break; default: return FALSE; } return trident_load_channel_registers(state->card, data, channel->num);}static int compute_rate_play(u32 rate){ int delta; /* We special case 44100 and 8000 since rounding with the equation does not give us an accurate enough value. For 11025 and 22050 the equation gives us the best answer. All other frequencies will also use the equation. JDW */ if (rate == 44100) delta = 0xeb3; else if (rate == 8000) delta = 0x2ab; else if (rate == 48000) delta = 0x1000; else delta = (((rate << 12) + rate) / 48000) & 0x0000ffff; return delta;}static int compute_rate_rec(u32 rate){ int delta; if (rate == 44100) delta = 0x116a; else if (rate == 8000) delta = 0x6000; else if (rate == 48000) delta = 0x1000; else delta = ((48000 << 12) / rate) & 0x0000ffff; return delta;}/* set playback sample rate */static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned int rate){ struct dmabuf *dmabuf = &state->dmabuf; if (rate > 48000) rate = 48000; if (rate < 4000) rate = 4000; dmabuf->rate = rate; dmabuf->channel->delta = compute_rate_play(rate); trident_write_voice_regs(state);#ifdef DEBUG printk("trident: called trident_set_dac_rate : rate = %d\n", rate);#endif return rate;}/* set recording sample rate */static unsigned int trident_set_adc_rate(struct trident_state * state, unsigned int rate){ struct dmabuf *dmabuf = &state->dmabuf; if (rate > 48000) rate = 48000; if (rate < 4000) rate = 4000; dmabuf->rate = rate; dmabuf->channel->delta = compute_rate_rec(rate); trident_write_voice_regs(state);#ifdef DEBUG printk("trident: called trident_set_adc_rate : rate = %d\n", rate);#endif return rate;}/* prepare channel attributes for playback */ static void trident_play_setup(struct trident_state *state){ struct dmabuf *dmabuf = &state->dmabuf; struct trident_channel *channel = dmabuf->channel; channel->lba = dmabuf->dma_handle; channel->delta = compute_rate_play(dmabuf->rate); channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -