📄 trident_main.c
字号:
Returns: Error status ---------------------------------------------------------------------------*/static int snd_trident_foldback_hw_free(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 ? voice->extra : NULL; if (trident->tlb.entries && voice && voice->memblk) { snd_trident_free_pages(trident, voice->memblk); voice->memblk = NULL; } snd_pcm_lib_free_pages(substream); if (evoice != NULL) { snd_trident_free_voice(trident, evoice); voice->extra = NULL; } return 0;}/*--------------------------------------------------------------------------- snd_trident_foldback_prepare Description: Prepare foldback capture device for playback. Parameters: substream - PCM substream class Returns: Error status ---------------------------------------------------------------------------*/static int snd_trident_foldback_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; unsigned long flags; spin_lock_irqsave(&trident->reg_lock, flags); /* Set channel buffer Address */ if (voice->memblk) voice->LBA = voice->memblk->offset; else voice->LBA = runtime->dma_addr; /* set target ESO for channel */ voice->ESO = runtime->buffer_size - 1; /* in samples */ /* set sample rate */ voice->Delta = 0x1000; voice->spurious_threshold = snd_trident_spurious_threshold(48000, runtime->period_size); voice->CSO = 0; voice->CTRL = snd_trident_control_mode(substream); 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) - 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); } spin_unlock_irqrestore(&trident->reg_lock, flags); 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); snd_pcm_runtime_t *runtime = substream->runtime; snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data; unsigned long flags; unsigned int old_bits = 0, change = 0; int err; if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) return err; if (err > 0 && trident->tlb.entries) { if (voice->memblk) snd_trident_free_pages(trident, voice->memblk); spin_lock_irqsave(&trident->reg_lock, flags); voice->memblk = snd_trident_alloc_pages(trident, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); spin_unlock_irqrestore(&trident->reg_lock, flags); if (voice->memblk == NULL) return -ENOMEM; } /* prepare SPDIF channel */ spin_lock_irqsave(&trident->reg_lock, flags); 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_irqrestore(&trident->reg_lock, flags); if (change) snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE, &trident->spdif_pcm_ctl->id); return 0;}/*--------------------------------------------------------------------------- snd_trident_spdif_hw_free Description: Release the hardware resources for the spdif device. Parameters: substream - PCM substream class Returns: Error status ---------------------------------------------------------------------------*/static int snd_trident_spdif_hw_free(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; if (trident->tlb.entries && voice && voice->memblk) { snd_trident_free_pages(trident, voice->memblk); voice->memblk = NULL; } snd_pcm_lib_free_pages(substream); 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; unsigned int RESO, LBAO; unsigned long flags; spin_lock_irqsave(&trident->reg_lock, flags); /* 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; /* set target ESO for channel */ RESO = runtime->buffer_size - 1; voice->ESO = (runtime->period_size * 2) - 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)); spin_unlock_irqrestore(&trident->reg_lock, flags); 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); 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; s = substream; spin_lock(&trident->reg_lock); val = inl(TRID_REG(trident, T4D_STIMER)) & 0x00ffffff; do { if ((trident_t *) _snd_pcm_chip(s->pcm) == 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) { 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; } s = s->link_next; } while (s != substream); if (spdif_flag) { outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS)); outb(trident->spdif_pcm_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); } 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; } if (++cso > runtime->buffer_size) cso = runtime->buffer_size; spin_unlock(&trident->reg_lock); 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -