📄 vxp_ops.c
字号:
static void vxp_validate_irq(vx_core_t *_chip, int enable){ struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; /* Set the interrupt enable bit to 1 in CDSP register */ if (enable) chip->regCDSP |= VXP_CDSP_VALID_IRQ_MASK; else chip->regCDSP &= ~VXP_CDSP_VALID_IRQ_MASK; vx_outb(chip, CDSP, chip->regCDSP);}/* * vx_setup_pseudo_dma - set up the pseudo dma read/write mode. * @do_write: 0 = read, 1 = set up for DMA write */static void vx_setup_pseudo_dma(vx_core_t *_chip, int do_write){ struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; /* Interrupt mode and HREQ pin enabled for host transmit / receive data transfers */ vx_outb(chip, ICR, do_write ? ICR_TREQ : ICR_RREQ); /* Reset the pseudo-dma register */ vx_inb(chip, ISR); vx_outb(chip, ISR, 0); /* Select DMA in read/write transfer mode and in 16-bit accesses */ chip->regDIALOG |= VXP_DLG_DMA16_SEL_MASK; chip->regDIALOG |= do_write ? VXP_DLG_DMAWRITE_SEL_MASK : VXP_DLG_DMAREAD_SEL_MASK; vx_outb(chip, DIALOG, chip->regDIALOG);}/* * vx_release_pseudo_dma - disable the pseudo-DMA mode */static void vx_release_pseudo_dma(vx_core_t *_chip){ struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; /* Disable DMA and 16-bit accesses */ chip->regDIALOG &= ~(VXP_DLG_DMAWRITE_SEL_MASK| VXP_DLG_DMAREAD_SEL_MASK| VXP_DLG_DMA16_SEL_MASK); vx_outb(chip, DIALOG, chip->regDIALOG); /* HREQ pin disabled. */ vx_outb(chip, ICR, 0);}/* * vx_pseudo_dma_write - write bulk data on pseudo-DMA mode * @count: data length to transfer in bytes * * data size must be aligned to 6 bytes to ensure the 24bit alignment on DSP. * NB: call with a certain lock! */static void vxp_dma_write(vx_core_t *chip, snd_pcm_runtime_t *runtime, vx_pipe_t *pipe, int count){ long port = vxp_reg_addr(chip, VX_DMA); int offset = pipe->hw_ptr; unsigned short *addr = (unsigned short *)(runtime->dma_area + offset); vx_setup_pseudo_dma(chip, 1); if (offset + count > pipe->buffer_bytes) { int length = pipe->buffer_bytes - offset; count -= length; length >>= 1; /* in 16bit words */ /* Transfer using pseudo-dma. */ while (length-- > 0) { outw(cpu_to_le16(*addr), port); addr++; } addr = (unsigned short *)runtime->dma_area; pipe->hw_ptr = 0; } pipe->hw_ptr += count; count >>= 1; /* in 16bit words */ /* Transfer using pseudo-dma. */ while (count-- > 0) { outw(cpu_to_le16(*addr), port); addr++; } vx_release_pseudo_dma(chip);}/* * vx_pseudo_dma_read - read bulk data on pseudo DMA mode * @offset: buffer offset in bytes * @count: data length to transfer in bytes * * the read length must be aligned to 6 bytes, as well as write. * NB: call with a certain lock! */static void vxp_dma_read(vx_core_t *chip, snd_pcm_runtime_t *runtime, vx_pipe_t *pipe, int count){ struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip; long port = vxp_reg_addr(chip, VX_DMA); int offset = pipe->hw_ptr; unsigned short *addr = (unsigned short *)(runtime->dma_area + offset); snd_assert(count % 2 == 0, return); vx_setup_pseudo_dma(chip, 0); if (offset + count > pipe->buffer_bytes) { int length = pipe->buffer_bytes - offset; count -= length; length >>= 1; /* in 16bit words */ /* Transfer using pseudo-dma. */ while (length-- > 0) *addr++ = le16_to_cpu(inw(port)); addr = (unsigned short *)runtime->dma_area; pipe->hw_ptr = 0; } pipe->hw_ptr += count; count >>= 1; /* in 16bit words */ /* Transfer using pseudo-dma. */ while (count-- > 1) *addr++ = le16_to_cpu(inw(port)); /* Disable DMA */ pchip->regDIALOG &= ~VXP_DLG_DMAREAD_SEL_MASK; vx_outb(chip, DIALOG, pchip->regDIALOG); /* Read the last word (16 bits) */ *addr = le16_to_cpu(inw(port)); /* Disable 16-bit accesses */ pchip->regDIALOG &= ~VXP_DLG_DMA16_SEL_MASK; vx_outb(chip, DIALOG, pchip->regDIALOG); /* HREQ pin disabled. */ vx_outb(chip, ICR, 0);}/* * write a codec data (24bit) */static void vxp_write_codec_reg(vx_core_t *chip, int codec, unsigned int data){ int i; /* Activate access to the corresponding codec register */ if (! codec) vx_inb(chip, LOFREQ); else vx_inb(chip, CODEC2); /* We have to send 24 bits (3 x 8 bits). Start with most signif. Bit */ for (i = 0; i < 24; i++, data <<= 1) vx_outb(chip, DATA, ((data & 0x800000) ? VX_DATA_CODEC_MASK : 0)); /* Terminate access to codec registers */ vx_inb(chip, HIFREQ);}/* * vx_set_mic_boost - set mic boost level (on vxp440 only) * @boost: 0 = 20dB, 1 = +38dB */void vx_set_mic_boost(vx_core_t *chip, int boost){ struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip; unsigned long flags; if (chip->chip_status & VX_STAT_IS_STALE) return; spin_lock_irqsave(&chip->lock, flags); if (pchip->regCDSP & P24_CDSP_MICS_SEL_MASK) { if (boost) { /* boost: 38 dB */ pchip->regCDSP &= ~P24_CDSP_MIC20_SEL_MASK; pchip->regCDSP |= P24_CDSP_MIC38_SEL_MASK; } else { /* minimum value: 20 dB */ pchip->regCDSP |= P24_CDSP_MIC20_SEL_MASK; pchip->regCDSP &= ~P24_CDSP_MIC38_SEL_MASK; } vx_outb(chip, CDSP, pchip->regCDSP); } spin_unlock_irqrestore(&chip->lock, flags);}/* * remap the linear value (0-8) to the actual value (0-15) */static int vx_compute_mic_level(int level){ switch (level) { case 5: level = 6 ; break; case 6: level = 8 ; break; case 7: level = 11; break; case 8: level = 15; break; default: break ; } return level;}/* * vx_set_mic_level - set mic level (on vxpocket only) * @level: the mic level = 0 - 8 (max) */void vx_set_mic_level(vx_core_t *chip, int level){ struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip; unsigned long flags; if (chip->chip_status & VX_STAT_IS_STALE) return; spin_lock_irqsave(&chip->lock, flags); if (pchip->regCDSP & VXP_CDSP_MIC_SEL_MASK) { level = vx_compute_mic_level(level); vx_outb(chip, MICRO, level); } spin_unlock_irqrestore(&chip->lock, flags);}/* * change the input audio source */static void vxp_change_audio_source(vx_core_t *_chip, int src){ struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; switch (src) { case VX_AUDIO_SRC_DIGITAL: chip->regCDSP |= VXP_CDSP_DATAIN_SEL_MASK; vx_outb(chip, CDSP, chip->regCDSP); break; case VX_AUDIO_SRC_LINE: chip->regCDSP &= ~VXP_CDSP_DATAIN_SEL_MASK; if (_chip->type == VX_TYPE_VXP440) chip->regCDSP &= ~P24_CDSP_MICS_SEL_MASK; else chip->regCDSP &= ~VXP_CDSP_MIC_SEL_MASK; vx_outb(chip, CDSP, chip->regCDSP); break; case VX_AUDIO_SRC_MIC: chip->regCDSP &= ~VXP_CDSP_DATAIN_SEL_MASK; /* reset mic levels */ if (_chip->type == VX_TYPE_VXP440) { chip->regCDSP &= ~P24_CDSP_MICS_SEL_MASK; if (chip->mic_level) chip->regCDSP |= P24_CDSP_MIC38_SEL_MASK; else chip->regCDSP |= P24_CDSP_MIC20_SEL_MASK; vx_outb(chip, CDSP, chip->regCDSP); } else { chip->regCDSP |= VXP_CDSP_MIC_SEL_MASK; vx_outb(chip, CDSP, chip->regCDSP); vx_outb(chip, MICRO, vx_compute_mic_level(chip->mic_level)); } break; }}/* * change the clock source * source = INTERNAL_QUARTZ or UER_SYNC */static void vxp_set_clock_source(vx_core_t *_chip, int source){ struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; if (source == INTERNAL_QUARTZ) chip->regCDSP &= ~VXP_CDSP_CLOCKIN_SEL_MASK; else chip->regCDSP |= VXP_CDSP_CLOCKIN_SEL_MASK; vx_outb(chip, CDSP, chip->regCDSP);}/* * reset the board */static void vxp_reset_board(vx_core_t *_chip, int cold_reset){ struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; chip->regCDSP = 0; chip->regDIALOG = 0;}/* * callbacks *//* exported */struct snd_vx_ops snd_vxpocket_ops = { .in8 = vxp_inb, .out8 = vxp_outb, .test_and_ack = vxp_test_and_ack, .validate_irq = vxp_validate_irq, .write_codec = vxp_write_codec_reg, .reset_codec = vxp_reset_codec, .change_audio_source = vxp_change_audio_source, .set_clock_source = vxp_set_clock_source, .load_dsp = vxp_load_dsp, .add_controls = vxp_add_mic_controls, .reset_dsp = vxp_reset_dsp, .reset_board = vxp_reset_board, .dma_write = vxp_dma_write, .dma_read = vxp_dma_read,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -