📄 trident_main.c
字号:
return; channel &= 0x1f; if (trident->ChanMap[T4D_BANK_A] & (1 << channel)) { trident->ChanMap[T4D_BANK_A] &= ~(1 << channel); trident->synth.ChanSynthCount--; }}/*--------------------------------------------------------------------------- snd_trident_write_voice_regs Description: This routine will complete and write the 5 hardware channel registers to hardware. Paramters: trident - pointer to target device class for 4DWave. voice - synthesizer voice structure Each register field. ---------------------------------------------------------------------------*/void snd_trident_write_voice_regs(trident_t * trident, snd_trident_voice_t * voice){ unsigned int FmcRvolCvol; unsigned int regs[5]; regs[1] = voice->LBA; regs[4] = (voice->GVSel << 31) | ((voice->Pan & 0x0000007f) << 24) | ((voice->CTRL & 0x0000000f) << 12); FmcRvolCvol = ((voice->FMC & 3) << 14) | ((voice->RVol & 0x7f) << 7) | (voice->CVol & 0x7f); switch (trident->device) { case TRIDENT_DEVICE_ID_SI7018: regs[4] |= voice->number > 31 ? (voice->Vol & 0x000003ff) : ((voice->Vol & 0x00003fc) << (16-2)) | (voice->EC & 0x00000fff); regs[0] = (voice->CSO << 16) | ((voice->Alpha & 0x00000fff) << 4) | (voice->FMS & 0x0000000f); regs[2] = (voice->ESO << 16) | (voice->Delta & 0x0ffff); regs[3] = (voice->Attribute << 16) | FmcRvolCvol; break; case TRIDENT_DEVICE_ID_DX: regs[4] |= ((voice->Vol & 0x000003fc) << (16-2)) | (voice->EC & 0x00000fff); regs[0] = (voice->CSO << 16) | ((voice->Alpha & 0x00000fff) << 4) | (voice->FMS & 0x0000000f); regs[2] = (voice->ESO << 16) | (voice->Delta & 0x0ffff); regs[3] = FmcRvolCvol; break; case TRIDENT_DEVICE_ID_NX: regs[4] |= ((voice->Vol & 0x000003fc) << (16-2)) | (voice->EC & 0x00000fff); regs[0] = (voice->Delta << 24) | (voice->CSO & 0x00ffffff); regs[2] = ((voice->Delta << 16) & 0xff000000) | (voice->ESO & 0x00ffffff); regs[3] = (voice->Alpha << 20) | ((voice->FMS & 0x0000000f) << 16) | FmcRvolCvol; break; default: snd_BUG(); return; } outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); outl(regs[0], TRID_REG(trident, CH_START + 0)); outl(regs[1], TRID_REG(trident, CH_START + 4)); outl(regs[2], TRID_REG(trident, CH_START + 8)); outl(regs[3], TRID_REG(trident, CH_START + 12)); outl(regs[4], TRID_REG(trident, CH_START + 16));#if 0 printk("written %i channel:\n", voice->number); printk(" regs[0] = 0x%x/0x%x\n", regs[0], inl(TRID_REG(trident, CH_START + 0))); printk(" regs[1] = 0x%x/0x%x\n", regs[1], inl(TRID_REG(trident, CH_START + 4))); printk(" regs[2] = 0x%x/0x%x\n", regs[2], inl(TRID_REG(trident, CH_START + 8))); printk(" regs[3] = 0x%x/0x%x\n", regs[3], inl(TRID_REG(trident, CH_START + 12))); printk(" regs[4] = 0x%x/0x%x\n", regs[4], inl(TRID_REG(trident, CH_START + 16)));#endif}/*--------------------------------------------------------------------------- snd_trident_write_cso_reg Description: This routine will write the new CSO offset register to hardware. Paramters: trident - pointer to target device class for 4DWave. voice - synthesizer voice structure CSO - new CSO value ---------------------------------------------------------------------------*/static void snd_trident_write_cso_reg(trident_t * trident, snd_trident_voice_t * voice, unsigned int CSO){ voice->CSO = CSO; outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); if (trident->device != TRIDENT_DEVICE_ID_NX) { outw(voice->CSO, TRID_REG(trident, CH_DX_CSO_ALPHA_FMS) + 2); } else { outl((voice->Delta << 24) | (voice->CSO & 0x00ffffff), TRID_REG(trident, CH_NX_DELTA_CSO)); }}/*--------------------------------------------------------------------------- snd_trident_write_eso_reg Description: This routine will write the new ESO offset register to hardware. Paramters: trident - pointer to target device class for 4DWave. voice - synthesizer voice structure ESO - new ESO value ---------------------------------------------------------------------------*/static void snd_trident_write_eso_reg(trident_t * trident, snd_trident_voice_t * voice, unsigned int ESO){ voice->ESO = ESO; outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); if (trident->device != TRIDENT_DEVICE_ID_NX) { outw(voice->ESO, TRID_REG(trident, CH_DX_ESO_DELTA) + 2); } else { outl(((voice->Delta << 16) & 0xff000000) | (voice->ESO & 0x00ffffff), TRID_REG(trident, CH_NX_DELTA_ESO)); }}/*--------------------------------------------------------------------------- snd_trident_write_vol_reg Description: This routine will write the new voice volume register to hardware. Paramters: trident - pointer to target device class for 4DWave. voice - synthesizer voice structure Vol - new voice volume ---------------------------------------------------------------------------*/static void snd_trident_write_vol_reg(trident_t * trident, snd_trident_voice_t * voice, unsigned int Vol){ voice->Vol = Vol; outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); switch (trident->device) { case TRIDENT_DEVICE_ID_DX: case TRIDENT_DEVICE_ID_NX: outb(voice->Vol >> 2, TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC + 2)); break; case TRIDENT_DEVICE_ID_SI7018: // printk("voice->Vol = 0x%x\n", voice->Vol); outw((voice->CTRL << 12) | voice->Vol, TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC)); break; }}/*--------------------------------------------------------------------------- snd_trident_write_pan_reg Description: This routine will write the new voice pan register to hardware. Paramters: trident - pointer to target device class for 4DWave. voice - synthesizer voice structure Pan - new pan value ---------------------------------------------------------------------------*/static void snd_trident_write_pan_reg(trident_t * trident, snd_trident_voice_t * voice, unsigned int Pan){ voice->Pan = Pan; outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); outb(((voice->GVSel & 0x01) << 7) | (voice->Pan & 0x7f), TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC + 3));}/*--------------------------------------------------------------------------- snd_trident_write_rvol_reg Description: This routine will write the new reverb volume register to hardware. Paramters: trident - pointer to target device class for 4DWave. voice - synthesizer voice structure RVol - new reverb volume ---------------------------------------------------------------------------*/static void snd_trident_write_rvol_reg(trident_t * trident, snd_trident_voice_t * voice, unsigned int RVol){ voice->RVol = RVol; outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); outw(((voice->FMC & 0x0003) << 14) | ((voice->RVol & 0x007f) << 7) | (voice->CVol & 0x007f), TRID_REG(trident, trident->device == TRIDENT_DEVICE_ID_NX ? CH_NX_ALPHA_FMS_FMC_RVOL_CVOL : CH_DX_FMC_RVOL_CVOL));}/*--------------------------------------------------------------------------- snd_trident_write_cvol_reg Description: This routine will write the new chorus volume register to hardware. Paramters: trident - pointer to target device class for 4DWave. voice - synthesizer voice structure CVol - new chorus volume ---------------------------------------------------------------------------*/static void snd_trident_write_cvol_reg(trident_t * trident, snd_trident_voice_t * voice, unsigned int CVol){ voice->CVol = CVol; outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); outw(((voice->FMC & 0x0003) << 14) | ((voice->RVol & 0x007f) << 7) | (voice->CVol & 0x007f), TRID_REG(trident, trident->device == TRIDENT_DEVICE_ID_NX ? CH_NX_ALPHA_FMS_FMC_RVOL_CVOL : CH_DX_FMC_RVOL_CVOL));}/*--------------------------------------------------------------------------- snd_trident_convert_rate Description: This routine converts rate in HZ to hardware delta value. Paramters: trident - pointer to target device class for 4DWave. rate - Real or Virtual channel number. Returns: Delta value. ---------------------------------------------------------------------------*/static unsigned int snd_trident_convert_rate(unsigned int rate){ unsigned 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) + 24000) / 48000) & 0x0000ffff; return delta;}/*--------------------------------------------------------------------------- snd_trident_convert_adc_rate Description: This routine converts rate in HZ to hardware delta value. Paramters: trident - pointer to target device class for 4DWave. rate - Real or Virtual channel number. Returns: Delta value. ---------------------------------------------------------------------------*/static unsigned int snd_trident_convert_adc_rate(unsigned int rate){ unsigned 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 = 0x116a; else if (rate == 8000) delta = 0x6000; else if (rate == 48000) delta = 0x1000; else delta = ((48000 << 12) / rate) & 0x0000ffff; return delta;}/*--------------------------------------------------------------------------- snd_trident_spurious_threshold Description: This routine converts rate in HZ to spurious threshold. Paramters: trident - pointer to target device class for 4DWave. rate - Real or Virtual channel number. Returns: Delta value. ---------------------------------------------------------------------------*/static unsigned int snd_trident_spurious_threshold(unsigned int rate, unsigned int period_size){ unsigned int res = (rate * period_size) / 48000; if (res < 64) res = res / 2; else res -= 32; return res;}/*--------------------------------------------------------------------------- snd_trident_control_mode Description: This routine returns a control mode for a PCM channel. Paramters: trident - pointer to target device class for 4DWave. substream - PCM substream Returns: Control value. ---------------------------------------------------------------------------*/static unsigned int snd_trident_control_mode(snd_pcm_substream_t *substream){ unsigned int CTRL; snd_pcm_runtime_t *runtime = substream->runtime; /* set ctrl mode CTRL default: 8-bit (unsigned) mono, loop mode enabled */ CTRL = 0x00000001; if (snd_pcm_format_width(runtime->format) == 16) CTRL |= 0x00000008; // 16-bit data if (snd_pcm_format_signed(runtime->format)) CTRL |= 0x00000002; // signed data if (runtime->channels > 1) CTRL |= 0x00000004; // stereo data return CTRL;}/* * PCM part *//*--------------------------------------------------------------------------- snd_trident_ioctl Description: Device I/O control handler for playback/capture parameters. Paramters: substream - PCM substream class cmd - what ioctl message to process arg - additional message infoarg Returns: Error status ---------------------------------------------------------------------------*/static int snd_trident_ioctl(snd_pcm_substream_t * substream, unsigned int cmd, void *arg){ /* FIXME: it seems that with small periods the behaviour of trident hardware is unpredictable and interrupt generator is broken */ return snd_pcm_lib_ioctl(substream, cmd, arg);}/*--------------------------------------------------------------------------- snd_trident_allocate_pcm_mem Description: Allocate PCM ring buffer for given substream Parameters: substream - PCM substream class hw_params - hardware parameters Returns: Error status ---------------------------------------------------------------------------*/static int snd_trident_allocate_pcm_mem(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ trident_t *trident = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data; int err; if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) return err; if (trident->tlb.entries) { if (err > 0) { /* change */ if (voice->memblk) snd_trident_free_pages(trident, voice->memblk); voice->memblk = snd_trident_alloc_pages(trident, substream); if (voice->memblk == NULL) return -ENOMEM; } } return 0;}/*--------------------------------------------------------------------------- snd_trident_allocate_evoice Description: Allocate extra voice as interrupt generator Parameters: substream - PCM substream class hw_params - hardware parameters Returns: Error status ---------------------------------------------------------------------------*/static int snd_trident_allocate_evoice(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ trident_t *trident = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data; snd_trident_voice_t *evoice = voice->extra; /* voice management */ if (params_buffer_size(hw_params) / 2 != params_period_size(hw_params)) { if (evoice == NULL) { evoice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0); if (evoice == NULL) return -ENOMEM; voice->extra = evoice; evoice->substream = substream; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -