📄 ali5455.c
字号:
static void ali_set_spdif_output(struct ali_state *state, int slots, int rate){ int vol; int aud_reg; struct ac97_codec *codec = state->card->ac97_codec[0]; if (!(state->card->ac97_features & 4)) { state->card->ac97_status &= ~SPDIF_ON; } else { if (slots == -1) { /* Turn off S/PDIF */ aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF)); /* If the volume wasn't muted before we turned on S/PDIF, unmute it */ if (!(state->card->ac97_status & VOL_MUTED)) { aud_reg = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO); ali_ac97_set(codec, AC97_MASTER_VOL_STEREO, (aud_reg & ~VOL_MUTED)); } state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON); return; } vol = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO); state->card->ac97_status = vol & VOL_MUTED; /* Set S/PDIF transmitter sample rate */ aud_reg = ali_ac97_get(codec, AC97_SPDIF_CONTROL); switch (rate) { case 32000: aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K; break; case 44100: aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K; break; case 48000: aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K; break; default: /* turn off S/PDIF */ aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF)); state->card->ac97_status &= ~SPDIF_ON; return; } ali_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg); aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_SPDIF; ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg); aud_reg = ali_ac97_get(codec, AC97_POWER_CONTROL); aud_reg |= 0x0002; ali_ac97_set(codec, AC97_POWER_CONTROL, aud_reg); udelay(1); state->card->ac97_status |= SPDIF_ON; /* Check to make sure the configuration is valid */ aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); if (!(aud_reg & 0x0400)) { /* turn off S/PDIF */ ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF)); state->card->ac97_status &= ~SPDIF_ON; return; } if (codec_independent_spdif_locked > 0) { aud_reg = ali_ac97_get(codec, 0x6a); ali_ac97_set(codec, 0x6a, (aud_reg & 0xefff)); } /* Mute the analog output */ /* Should this only mute the PCM volume??? */ }}/* ali_set_dac_channels * * Configure the codec's multi-channel DACs * * The logic is backwards. Setting the bit to 1 turns off the DAC. * * What about the ICH? We currently configure it using the * SNDCTL_DSP_CHANNELS ioctl. If we're turnning on the DAC, * does that imply that we want the ICH set to support * these channels? * * TODO: * vailidate that the codec really supports these DACs * before turning them on. */static void ali_set_dac_channels(struct ali_state *state, int channel){ int aud_reg; struct ac97_codec *codec = state->card->ac97_codec[0]; aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS); aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK; state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON); switch (channel) { case 2: /* always enabled */ break; case 4: aud_reg &= ~AC97_EA_PRJ; state->card->ac97_status |= SURR_ON; break; case 6: aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK); state->card->ac97_status |= SURR_ON | CENTER_LFE_ON; break; default: break; } ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);}/* set playback sample rate */static unsigned int ali_set_dac_rate(struct ali_state *state, unsigned int rate){ struct dmabuf *dmabuf = &state->dmabuf; u32 new_rate; struct ac97_codec *codec = state->card->ac97_codec[0]; if (!(state->card->ac97_features & 0x0001)) { dmabuf->rate = clocking; return clocking; } if (rate > 48000) rate = 48000; if (rate < 8000) rate = 8000; dmabuf->rate = rate; /* * Adjust for misclocked crap */ rate = (rate * clocking) / 48000; if (strict_clocking && rate < 8000) { rate = 8000; dmabuf->rate = (rate * 48000) / clocking; } new_rate = ac97_set_dac_rate(codec, rate); if (new_rate != rate) { dmabuf->rate = (new_rate * 48000) / clocking; } rate = new_rate; return dmabuf->rate;}/* set recording sample rate */static unsigned int ali_set_adc_rate(struct ali_state *state, unsigned int rate){ struct dmabuf *dmabuf = &state->dmabuf; u32 new_rate; struct ac97_codec *codec = state->card->ac97_codec[0]; if (!(state->card->ac97_features & 0x0001)) { dmabuf->rate = clocking; return clocking; } if (rate > 48000) rate = 48000; if (rate < 8000) rate = 8000; dmabuf->rate = rate; /* * Adjust for misclocked crap */ rate = (rate * clocking) / 48000; if (strict_clocking && rate < 8000) { rate = 8000; dmabuf->rate = (rate * 48000) / clocking; } new_rate = ac97_set_adc_rate(codec, rate); if (new_rate != rate) { dmabuf->rate = (new_rate * 48000) / clocking; rate = new_rate; } return dmabuf->rate;}/* set codec independent spdifout sample rate */static unsigned int ali_set_codecspdifout_rate(struct ali_state *state, unsigned int rate){ struct dmabuf *dmabuf = &state->dmabuf; if (!(state->card->ac97_features & 0x0001)) { dmabuf->rate = clocking; return clocking; } if (rate > 48000) rate = 48000; if (rate < 8000) rate = 8000; dmabuf->rate = rate; return dmabuf->rate;}/* set controller independent spdif out function sample rate */static void ali_set_spdifout_rate(struct ali_state *state, unsigned int rate){ unsigned char ch_st_sel; unsigned short status_rate; switch (rate) { case 44100: status_rate = 0; break; case 32000: status_rate = 0x300; break; case 48000: default: status_rate = 0x200; break; } ch_st_sel = inb(state->card->iobase + ALI_SPDIFICS) & ALI_SPDIF_OUT_CH_STATUS; //select spdif_out ch_st_sel |= 0x80; //select right outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS)); outb(status_rate | 0x20, (state->card->iobase + ALI_SPDIFCSR + 2)); ch_st_sel &= (~0x80); //select left outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS)); outw(status_rate | 0x10, (state->card->iobase + ALI_SPDIFCSR + 2));}/* get current playback/recording dma buffer pointer (byte offset from LBA), called with spinlock held! */static inline unsigned ali_get_dma_addr(struct ali_state *state, int rec){ struct dmabuf *dmabuf = &state->dmabuf; unsigned int civ, offset, port, port_picb; unsigned int data; if (!dmabuf->enable) return 0; if (rec == 1) port = state->card->iobase + dmabuf->read_channel->port; else if (rec == 2) port = state->card->iobase + dmabuf->codec_spdifout_channel->port; else if (rec == 3) port = state->card->iobase + dmabuf->controller_spdifout_channel->port; else port = state->card->iobase + dmabuf->write_channel->port; port_picb = port + OFF_PICB; do { civ = inb(port + OFF_CIV) & 31; offset = inw(port_picb); /* Must have a delay here! */ if (offset == 0) udelay(1); /* Reread both registers and make sure that that total * offset from the first reading to the second is 0. * There is an issue with SiS hardware where it will count * picb down to 0, then update civ to the next value, * then set the new picb to fragsize bytes. We can catch * it between the civ update and the picb update, making * it look as though we are 1 fragsize ahead of where we * are. The next to we get the address though, it will * be back in thdelay is more than long enough * that we won't have to worry about the chip still being * out of sync with reality ;-) */ } while (civ != (inb(port + OFF_CIV) & 31) || offset != inw(port_picb)); data = ((civ + 1) * dmabuf->fragsize - (2 * offset)) % dmabuf->dmasize; if (inw(port_picb) == 0) data -= 2048; return data;}/* Stop recording (lock held) */static inline void __stop_adc(struct ali_state *state){ struct dmabuf *dmabuf = &state->dmabuf; struct ali_card *card = state->card; dmabuf->enable &= ~ADC_RUNNING; outl((1 << 18) | (1 << 16), card->iobase + ALI_DMACR); udelay(1); outb(0, card->iobase + PI_CR); while (inb(card->iobase + PI_CR) != 0); // now clear any latent interrupt bits (like the halt bit) outb(inb(card->iobase + PI_SR) | 0x001e, card->iobase + PI_SR); outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMIN, card->iobase + ALI_INTERRUPTSR);}static void stop_adc(struct ali_state *state){ struct ali_card *card = state->card; unsigned long flags; spin_lock_irqsave(&card->lock, flags); __stop_adc(state); spin_unlock_irqrestore(&card->lock, flags);}static inline void __start_adc(struct ali_state *state){ struct dmabuf *dmabuf = &state->dmabuf; if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable && (dmabuf->trigger & PCM_ENABLE_INPUT)) { dmabuf->enable |= ADC_RUNNING; outb((1 << 4) | (1 << 2), state->card->iobase + PI_CR); if (state->card->channel[0].used == 1) outl(1, state->card->iobase + ALI_DMACR); // DMA CONTROL REGISTRER udelay(100); if (state->card->channel[2].used == 1) outl((1 << 2), state->card->iobase + ALI_DMACR); //DMA CONTROL REGISTER udelay(100); }}static void start_adc(struct ali_state *state){ struct ali_card *card = state->card; unsigned long flags; spin_lock_irqsave(&card->lock, flags); __start_adc(state); spin_unlock_irqrestore(&card->lock, flags);}/* stop playback (lock held) */static inline void __stop_dac(struct ali_state *state){ struct dmabuf *dmabuf = &state->dmabuf; struct ali_card *card = state->card; dmabuf->enable &= ~DAC_RUNNING; outl(0x00020000, card->iobase + 0x08); outb(0, card->iobase + PO_CR); while (inb(card->iobase + PO_CR) != 0) cpu_relax(); outb(inb(card->iobase + PO_SR) | 0x001e, card->iobase + PO_SR); outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMOUT, card->iobase + ALI_INTERRUPTSR);}static void stop_dac(struct ali_state *state){ struct ali_card *card = state->card; unsigned long flags; spin_lock_irqsave(&card->lock, flags); __stop_dac(state); spin_unlock_irqrestore(&card->lock, flags);}static inline void __start_dac(struct ali_state *state){ struct dmabuf *dmabuf = &state->dmabuf; if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) { dmabuf->enable |= DAC_RUNNING; outb((1 << 4) | (1 << 2), state->card->iobase + PO_CR); outl((1 << 1), state->card->iobase + 0x08); //dma control register }}static void start_dac(struct ali_state *state){ struct ali_card *card = state->card; unsigned long flags; spin_lock_irqsave(&card->lock, flags); __start_dac(state); spin_unlock_irqrestore(&card->lock, flags);}/* stop codec and controller spdif out (lock held) */static inline void __stop_spdifout(struct ali_state *state){ struct dmabuf *dmabuf = &state->dmabuf; struct ali_card *card = state->card; if (codec_independent_spdif_locked > 0) { dmabuf->enable &= ~CODEC_SPDIFOUT_RUNNING; outl((1 << 19), card->iobase + 0x08); outb(0, card->iobase + CODECSPDIFOUT_CR); while (inb(card->iobase + CODECSPDIFOUT_CR) != 0) cpu_relax(); outb(inb(card->iobase + CODECSPDIFOUT_SR) | 0x001e, card->iobase + CODECSPDIFOUT_SR); outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_CODECSPDIFOUT, card->iobase + ALI_INTERRUPTSR); } else { if (controller_independent_spdif_locked > 0) { dmabuf->enable &= ~CONTROLLER_SPDIFOUT_RUNNING; outl((1 << 23), card->iobase + 0x08); outb(0, card->iobase + CONTROLLERSPDIFOUT_CR); while (inb(card->iobase + CONTROLLERSPDIFOUT_CR) != 0) cpu_relax(); outb(inb(card->iobase + CONTROLLERSPDIFOUT_SR) | 0x001e, card->iobase + CONTROLLERSPDIFOUT_SR); outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_SPDIFOUT, card->iobase + ALI_INTERRUPTSR); } }}static void stop_spdifout(struct ali_state *state){ struct ali_card *card = state->card; unsigned long flags; spin_lock_irqsave(&card->lock, flags); __stop_spdifout(state); spin_unlock_irqrestore(&card->lock, flags);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -