📄 trident_main.c
字号:
voice->FMC = 3; voice->RVol = 0x7f; voice->CVol = 0x7f; voice->GVSel = 1; voice->Pan = 0x7f; /* mute */ voice->Vol = 0x3ff; /* mute */ voice->EC = 0; voice->Alpha = 0; voice->FMS = 0; voice->Attribute = 0; /* set up capture channel */ outb(((voice->number & 0x3f) | 0x80), TRID_REG(trident, T4D_RCI + voice->foldback_chan)); snd_trident_write_voice_regs(trident, voice); if (evoice != NULL) { evoice->Delta = voice->Delta; evoice->spurious_threshold = voice->spurious_threshold; evoice->LBA = voice->LBA; evoice->CSO = 0; evoice->ESO = (runtime->period_size * 2) + 4 - 1; /* in samples */ evoice->CTRL = voice->CTRL; evoice->FMC = 3; evoice->GVSel = trident->device == TRIDENT_DEVICE_ID_SI7018 ? 0 : 1; evoice->EC = 0; evoice->Alpha = 0; evoice->FMS = 0; evoice->Vol = 0x3ff; /* mute */ evoice->RVol = evoice->CVol = 0x7f; /* mute */ evoice->Pan = 0x7f; /* mute */ evoice->Attribute = 0; snd_trident_write_voice_regs(trident, evoice); evoice->isync2 = 1; evoice->isync_mark = runtime->period_size; evoice->ESO = (runtime->period_size * 2) - 1; } spin_unlock_irq(&trident->reg_lock); return 0;}/*--------------------------------------------------------------------------- snd_trident_spdif_hw_params Description: Set the hardware parameters for the spdif device. Parameters: substream - PCM substream class hw_params - hardware parameters Returns: Error status ---------------------------------------------------------------------------*/static int snd_trident_spdif_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ trident_t *trident = snd_pcm_substream_chip(substream); unsigned int old_bits = 0, change = 0; int err; err = snd_trident_allocate_pcm_mem(substream, hw_params); if (err < 0) return err; if (trident->device == TRIDENT_DEVICE_ID_SI7018) { err = snd_trident_allocate_evoice(substream, hw_params); if (err < 0) return err; } /* prepare SPDIF channel */ spin_lock_irq(&trident->reg_lock); old_bits = trident->spdif_pcm_bits; if (old_bits & IEC958_AES0_PROFESSIONAL) trident->spdif_pcm_bits &= ~IEC958_AES0_PRO_FS; else trident->spdif_pcm_bits &= ~(IEC958_AES3_CON_FS << 24); if (params_rate(hw_params) >= 48000) { trident->spdif_pcm_ctrl = 0x3c; // 48000 Hz trident->spdif_pcm_bits |= trident->spdif_bits & IEC958_AES0_PROFESSIONAL ? IEC958_AES0_PRO_FS_48000 : (IEC958_AES3_CON_FS_48000 << 24); } else if (params_rate(hw_params) >= 44100) { trident->spdif_pcm_ctrl = 0x3e; // 44100 Hz trident->spdif_pcm_bits |= trident->spdif_bits & IEC958_AES0_PROFESSIONAL ? IEC958_AES0_PRO_FS_44100 : (IEC958_AES3_CON_FS_44100 << 24); } else { trident->spdif_pcm_ctrl = 0x3d; // 32000 Hz trident->spdif_pcm_bits |= trident->spdif_bits & IEC958_AES0_PROFESSIONAL ? IEC958_AES0_PRO_FS_32000 : (IEC958_AES3_CON_FS_32000 << 24); } change = old_bits != trident->spdif_pcm_bits; spin_unlock_irq(&trident->reg_lock); if (change) snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE, &trident->spdif_pcm_ctl->id); return 0;}/*--------------------------------------------------------------------------- snd_trident_spdif_prepare Description: Prepare SPDIF device for playback. Parameters: substream - PCM substream class Returns: Error status ---------------------------------------------------------------------------*/static int snd_trident_spdif_prepare(snd_pcm_substream_t * substream){ 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; snd_trident_pcm_mixer_t *mix = &trident->pcm_mixer[substream->number]; unsigned int RESO, LBAO; unsigned int temp; spin_lock_irq(&trident->reg_lock); if (trident->device != TRIDENT_DEVICE_ID_SI7018) { /* set delta (rate) value */ voice->Delta = snd_trident_convert_rate(runtime->rate); voice->spurious_threshold = snd_trident_spurious_threshold(runtime->rate, runtime->period_size); /* set Loop Back Address */ LBAO = runtime->dma_addr; if (voice->memblk) voice->LBA = voice->memblk->offset; else voice->LBA = LBAO; voice->isync = 1; voice->isync3 = 1; voice->isync_mark = runtime->period_size; voice->isync_max = runtime->buffer_size; /* set target ESO for channel */ RESO = runtime->buffer_size - 1; voice->ESO = voice->isync_ESO = (runtime->period_size * 2) + 6 - 1; /* set ctrl mode */ voice->CTRL = snd_trident_control_mode(substream); voice->FMC = 3; voice->RVol = 0x7f; voice->CVol = 0x7f; voice->GVSel = 1; voice->Pan = 0x7f; voice->Vol = 0x3ff; voice->EC = 0; voice->CSO = 0; voice->Alpha = 0; voice->FMS = 0; voice->Attribute = 0; /* prepare surrogate IRQ channel */ snd_trident_write_voice_regs(trident, voice); outw((RESO & 0xffff), TRID_REG(trident, NX_SPESO)); outb((RESO >> 16), TRID_REG(trident, NX_SPESO + 2)); outl((LBAO & 0xfffffffc), TRID_REG(trident, NX_SPLBA)); outw((voice->CSO & 0xffff), TRID_REG(trident, NX_SPCTRL_SPCSO)); outb((voice->CSO >> 16), TRID_REG(trident, NX_SPCTRL_SPCSO + 2)); /* set SPDIF setting */ outb(trident->spdif_pcm_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS)); } else { /* SiS */ /* set delta (rate) value */ voice->Delta = 0x800; voice->spurious_threshold = snd_trident_spurious_threshold(48000, runtime->period_size); /* set Loop Begin Address */ if (voice->memblk) voice->LBA = voice->memblk->offset; else voice->LBA = runtime->dma_addr; voice->CSO = 0; voice->ESO = runtime->buffer_size - 1; /* in samples */ voice->CTRL = snd_trident_control_mode(substream); voice->FMC = 3; voice->GVSel = 1; voice->EC = 0; voice->Alpha = 0; voice->FMS = 0; voice->Vol = mix->vol; voice->RVol = mix->rvol; voice->CVol = mix->cvol; voice->Pan = mix->pan; voice->Attribute = (1<<(30-16))|(7<<(26-16))| (0<<(24-16))|(0<<(19-16)); snd_trident_write_voice_regs(trident, voice); if (evoice != NULL) { evoice->Delta = voice->Delta; evoice->spurious_threshold = voice->spurious_threshold; evoice->LBA = voice->LBA; evoice->CSO = 0; evoice->ESO = (runtime->period_size * 2) + 4 - 1; /* in samples */ evoice->CTRL = voice->CTRL; evoice->FMC = 3; evoice->GVSel = trident->device == TRIDENT_DEVICE_ID_SI7018 ? 0 : 1; evoice->EC = 0; evoice->Alpha = 0; evoice->FMS = 0; evoice->Vol = 0x3ff; /* mute */ evoice->RVol = evoice->CVol = 0x7f; /* mute */ evoice->Pan = 0x7f; /* mute */ evoice->Attribute = 0; snd_trident_write_voice_regs(trident, evoice); evoice->isync2 = 1; evoice->isync_mark = runtime->period_size; evoice->ESO = (runtime->period_size * 2) - 1; } outl(trident->spdif_pcm_bits, TRID_REG(trident, SI_SPDIF_CS)); temp = inl(TRID_REG(trident, T4D_LFO_GC_CIR)); temp &= ~(1<<19); outl(temp, TRID_REG(trident, T4D_LFO_GC_CIR)); temp = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)); temp |= SPDIF_EN; outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL)); } spin_unlock_irq(&trident->reg_lock); return 0;}/*--------------------------------------------------------------------------- snd_trident_trigger Description: Start/stop devices Parameters: substream - PCM substream class cmd - trigger command (STOP, GO) Returns: Error status ---------------------------------------------------------------------------*/static int snd_trident_trigger(snd_pcm_substream_t *substream, int cmd) { trident_t *trident = snd_pcm_substream_chip(substream); struct list_head *pos; snd_pcm_substream_t *s; unsigned int what, whati, capture_flag, spdif_flag; snd_trident_voice_t *voice, *evoice; unsigned int val, go; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: go = 1; break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: go = 0; break; default: return -EINVAL; } what = whati = capture_flag = spdif_flag = 0; spin_lock(&trident->reg_lock); val = inl(TRID_REG(trident, T4D_STIMER)) & 0x00ffffff; snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); if ((trident_t *) snd_pcm_substream_chip(s) == trident) { voice = (snd_trident_voice_t *) s->runtime->private_data; evoice = voice->extra; what |= 1 << (voice->number & 0x1f); if (evoice == NULL) { whati |= 1 << (voice->number & 0x1f); } else { what |= 1 << (evoice->number & 0x1f); whati |= 1 << (evoice->number & 0x1f); if (go) evoice->stimer = val; } if (go) { voice->running = 1; voice->stimer = val; } else { voice->running = 0; } snd_pcm_trigger_done(s, substream); if (voice->capture) capture_flag = 1; if (voice->spdif) spdif_flag = 1; } } if (spdif_flag) { if (trident->device != TRIDENT_DEVICE_ID_SI7018) { outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS)); outb(trident->spdif_pcm_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); } else { outl(trident->spdif_pcm_bits, TRID_REG(trident, SI_SPDIF_CS)); val = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) | SPDIF_EN; outl(val, TRID_REG(trident, SI_SERIAL_INTF_CTRL)); } } if (!go) outl(what, TRID_REG(trident, T4D_STOP_B)); val = inl(TRID_REG(trident, T4D_AINTEN_B)); if (go) { val |= whati; } else { val &= ~whati; } outl(val, TRID_REG(trident, T4D_AINTEN_B)); if (go) { outl(what, TRID_REG(trident, T4D_START_B)); if (capture_flag && trident->device != TRIDENT_DEVICE_ID_SI7018) outb(trident->bDMAStart, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD)); } else { if (capture_flag && trident->device != TRIDENT_DEVICE_ID_SI7018) outb(0x00, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD)); } spin_unlock(&trident->reg_lock); return 0;}/*--------------------------------------------------------------------------- snd_trident_playback_pointer Description: This routine return the playback position Parameters: substream - PCM substream class Returns: position of buffer ---------------------------------------------------------------------------*/static snd_pcm_uframes_t snd_trident_playback_pointer(snd_pcm_substream_t * substream){ 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; unsigned int cso; if (!voice->running) return 0; spin_lock(&trident->reg_lock); outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); if (trident->device != TRIDENT_DEVICE_ID_NX) { cso = inw(TRID_REG(trident, CH_DX_CSO_ALPHA_FMS + 2)); } else { // ID_4DWAVE_NX cso = (unsigned int) inl(TRID_REG(trident, CH_NX_DELTA_CSO)) & 0x00ffffff; } spin_unlock(&trident->reg_lock); if (cso >= runtime->buffer_size) cso = 0; return cso;}/*--------------------------------------------------------------------------- snd_trident_capture_pointer Description: This routine return the capture position Paramters: pcm1 - PCM device class Returns: position of buffer ---------------------------------------------------------------------------*/static snd_pcm_uframes_t snd_trident_capture_pointer(snd_pcm_substream_t * substream){ 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; unsigned int result; if (!voice->running) return 0; result = inw(TRID_REG(trident, T4D_SBBL_SBCL)); if (runtime->channels > 1) result >>= 1; if (result > 0) result = runtime->buffer_size - result; return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -