📄 rme96.c
字号:
static intsnd_rme96_playback_setformat(rme96_t *rme96, int format){ switch (format) { case SNDRV_PCM_FORMAT_S16_LE: rme96->wcreg &= ~RME96_WCR_MODE24; break; case SNDRV_PCM_FORMAT_S32_LE: rme96->wcreg |= RME96_WCR_MODE24; break; default: return -EINVAL; } writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); return 0;}static intsnd_rme96_capture_setformat(rme96_t *rme96, int format){ switch (format) { case SNDRV_PCM_FORMAT_S16_LE: rme96->wcreg &= ~RME96_WCR_MODE24_2; break; case SNDRV_PCM_FORMAT_S32_LE: rme96->wcreg |= RME96_WCR_MODE24_2; break; default: return -EINVAL; } writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); return 0;}static voidsnd_rme96_set_period_properties(rme96_t *rme96, size_t period_bytes){ switch (period_bytes) { case RME96_LARGE_BLOCK_SIZE: rme96->wcreg &= ~RME96_WCR_ISEL; break; case RME96_SMALL_BLOCK_SIZE: rme96->wcreg |= RME96_WCR_ISEL; break; default: snd_BUG(); break; } rme96->wcreg &= ~RME96_WCR_IDIS; writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);}static intsnd_rme96_playback_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params){ rme96_t *rme96 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err, rate, dummy; runtime->dma_area = (void *)(rme96->iobase + RME96_IO_PLAY_BUFFER); runtime->dma_addr = rme96->port + RME96_IO_PLAY_BUFFER; runtime->dma_bytes = RME96_BUFFER_SIZE; spin_lock_irq(&rme96->lock); if (!(rme96->wcreg & RME96_WCR_MASTER) && snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && (rate = snd_rme96_capture_getrate(rme96, &dummy)) > 0) { /* slave clock */ if ((int)params_rate(params) != rate) { spin_unlock_irq(&rme96->lock); return -EIO; } } else if ((err = snd_rme96_playback_setrate(rme96, params_rate(params))) < 0) { spin_unlock_irq(&rme96->lock); return err; } if ((err = snd_rme96_playback_setformat(rme96, params_format(params))) < 0) { spin_unlock_irq(&rme96->lock); return err; } snd_rme96_setframelog(rme96, params_channels(params), 1); if (rme96->capture_periodsize != 0) { if (params_period_size(params) << rme96->playback_frlog != rme96->capture_periodsize) { spin_unlock_irq(&rme96->lock); return -EBUSY; } } rme96->playback_periodsize = params_period_size(params) << rme96->playback_frlog; snd_rme96_set_period_properties(rme96, rme96->playback_periodsize); /* S/PDIF setup */ if ((rme96->wcreg & RME96_WCR_ADAT) == 0) { rme96->wcreg &= ~(RME96_WCR_PRO | RME96_WCR_DOLBY | RME96_WCR_EMP); writel(rme96->wcreg |= rme96->wcreg_spdif_stream, rme96->iobase + RME96_IO_CONTROL_REGISTER); } spin_unlock_irq(&rme96->lock); return 0;}static intsnd_rme96_capture_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params){ rme96_t *rme96 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err, isadat, rate; runtime->dma_area = (void *)(rme96->iobase + RME96_IO_REC_BUFFER); runtime->dma_addr = rme96->port + RME96_IO_REC_BUFFER; runtime->dma_bytes = RME96_BUFFER_SIZE; spin_lock_irq(&rme96->lock); if ((err = snd_rme96_capture_setformat(rme96, params_format(params))) < 0) { spin_unlock_irq(&rme96->lock); return err; } if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) { if ((err = snd_rme96_capture_analog_setrate(rme96, params_rate(params))) < 0) { spin_unlock_irq(&rme96->lock); return err; } } else if ((rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0) { if ((int)params_rate(params) != rate) { spin_unlock_irq(&rme96->lock); return -EIO; } if ((isadat && runtime->hw.channels_min == 2) || (!isadat && runtime->hw.channels_min == 8)) { spin_unlock_irq(&rme96->lock); return -EIO; } } snd_rme96_setframelog(rme96, params_channels(params), 0); if (rme96->playback_periodsize != 0) { if (params_period_size(params) << rme96->capture_frlog != rme96->playback_periodsize) { spin_unlock_irq(&rme96->lock); return -EBUSY; } } rme96->capture_periodsize = params_period_size(params) << rme96->capture_frlog; snd_rme96_set_period_properties(rme96, rme96->capture_periodsize); spin_unlock_irq(&rme96->lock); return 0;}static voidsnd_rme96_playback_start(rme96_t *rme96, int from_pause){ if (!from_pause) { writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS); } rme96->wcreg |= RME96_WCR_START; writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);}static voidsnd_rme96_capture_start(rme96_t *rme96, int from_pause){ if (!from_pause) { writel(0, rme96->iobase + RME96_IO_RESET_REC_POS); } rme96->wcreg |= RME96_WCR_START_2; writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);}static voidsnd_rme96_playback_stop(rme96_t *rme96){ /* * Check if there is an unconfirmed IRQ, if so confirm it, or else * the hardware will not stop generating interrupts */ rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); if (rme96->rcreg & RME96_RCR_IRQ) { writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ); } rme96->wcreg &= ~RME96_WCR_START; writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);}static voidsnd_rme96_capture_stop(rme96_t *rme96){ rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); if (rme96->rcreg & RME96_RCR_IRQ_2) { writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ); } rme96->wcreg &= ~RME96_WCR_START_2; writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);}static irqreturn_tsnd_rme96_interrupt(int irq, void *dev_id, struct pt_regs *regs){ rme96_t *rme96 = (rme96_t *)dev_id; rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); /* fastpath out, to ease interrupt sharing */ if (!((rme96->rcreg & RME96_RCR_IRQ) || (rme96->rcreg & RME96_RCR_IRQ_2))) { return IRQ_NONE; } if (rme96->rcreg & RME96_RCR_IRQ) { /* playback */ snd_pcm_period_elapsed(rme96->playback_substream); writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ); } if (rme96->rcreg & RME96_RCR_IRQ_2) { /* capture */ snd_pcm_period_elapsed(rme96->capture_substream); writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ); } return IRQ_HANDLED;}static unsigned int period_bytes[] = { RME96_SMALL_BLOCK_SIZE, RME96_LARGE_BLOCK_SIZE };static snd_pcm_hw_constraint_list_t hw_constraints_period_bytes = { .count = ARRAY_SIZE(period_bytes), .list = period_bytes, .mask = 0};static intsnd_rme96_playback_spdif_open(snd_pcm_substream_t *substream){ int rate, dummy; rme96_t *rme96 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_set_sync(substream); spin_lock_irq(&rme96->lock); if (rme96->playback_substream != NULL) { spin_unlock_irq(&rme96->lock); return -EBUSY; } rme96->wcreg &= ~RME96_WCR_ADAT; writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); rme96->playback_substream = substream; spin_unlock_irq(&rme96->lock); runtime->hw = snd_rme96_playback_spdif_info; if (!(rme96->wcreg & RME96_WCR_MASTER) && snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && (rate = snd_rme96_capture_getrate(rme96, &dummy)) > 0) { /* slave clock */ runtime->hw.rates = snd_rme96_ratecode(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes); rme96->wcreg_spdif_stream = rme96->wcreg_spdif; rme96->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(rme96->card, SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &rme96->spdif_ctl->id); return 0;}static intsnd_rme96_capture_spdif_open(snd_pcm_substream_t *substream){ int isadat, rate; rme96_t *rme96 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_set_sync(substream); runtime->hw = snd_rme96_capture_spdif_info; if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && (rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0) { if (isadat) { return -EIO; } runtime->hw.rates = snd_rme96_ratecode(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } spin_lock_irq(&rme96->lock); if (rme96->capture_substream != NULL) { spin_unlock_irq(&rme96->lock); return -EBUSY; } rme96->capture_substream = substream; spin_unlock_irq(&rme96->lock); snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes); return 0;}static intsnd_rme96_playback_adat_open(snd_pcm_substream_t *substream){ int rate, dummy; rme96_t *rme96 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_set_sync(substream); spin_lock_irq(&rme96->lock); if (rme96->playback_substream != NULL) { spin_unlock_irq(&rme96->lock); return -EBUSY; } rme96->wcreg |= RME96_WCR_ADAT; writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); rme96->playback_substream = substream; spin_unlock_irq(&rme96->lock); runtime->hw = snd_rme96_playback_adat_info; if (!(rme96->wcreg & RME96_WCR_MASTER) && snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && (rate = snd_rme96_capture_getrate(rme96, &dummy)) > 0) { /* slave clock */ runtime->hw.rates = snd_rme96_ratecode(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes); return 0;}static intsnd_rme96_capture_adat_open(snd_pcm_substream_t *substream){ int isadat, rate; rme96_t *rme96 = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_set_sync(substream); runtime->hw = snd_rme96_capture_adat_info; if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) { /* makes no sense to use analog input. Note that analog expension cards AEB4/8-I are RME96_INPUT_INTERNAL */ return -EIO; } if ((rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0) { if (!isadat) { return -EIO; } runtime->hw.rates = snd_rme96_ratecode(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } spin_lock_irq(&rme96->lock); if (rme96->capture_substream != NULL) { spin_unlock_irq(&rme96->lock); return -EBUSY; } rme96->capture_substream = substream; spin_unlock_irq(&rme96->lock); snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes); return 0;}static intsnd_rme96_playback_close(snd_pcm_substream_t *substream){ rme96_t *rme96 = snd_pcm_substream_chip(substream); int spdif = 0; spin_lock_irq(&rme96->lock); if (RME96_ISPLAYING(rme96)) { snd_rme96_playback_stop(rme96); } rme96->playback_substream = NULL; rme96->playback_periodsize = 0; spdif = (rme96->wcreg & RME96_WCR_ADAT) == 0; spin_unlock_irq(&rme96->lock); if (spdif) { rme96->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(rme96->card, SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &rme96->spdif_ctl->id); } return 0;}static intsnd_rme96_capture_close(snd_pcm_substream_t *substream){ rme96_t *rme96 = snd_pcm_substream_chip(substream); spin_lock_irq(&rme96->lock); if (RME96_ISRECORDING(rme96)) { snd_rme96_capture_stop(rme96); } rme96->capture_substream = NULL; rme96->capture_periodsize = 0; spin_unlock_irq(&rme96->lock); return 0;}static intsnd_rme96_playback_prepare(snd_pcm_substream_t *substream){ rme96_t *rme96 = snd_pcm_substream_chip(substream); spin_lock_irq(&rme96->lock); if (RME96_ISPLAYING(rme96)) { snd_rme96_playback_stop(rme96); } writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS); spin_unlock_irq(&rme96->lock); return 0;}static intsnd_rme96_capture_prepare(snd_pcm_substream_t *substream){ rme96_t *rme96 = snd_pcm_substream_chip(substream); spin_lock_irq(&rme96->lock); if (RME96_ISRECORDING(rme96)) { snd_rme96_capture_stop(rme96); } writel(0, rme96->iobase + RME96_IO_RESET_REC_POS); spin_unlock_irq(&rme96->lock); return 0;}static intsnd_rme96_playback_trigger(snd_pcm_substream_t *substream, int cmd){ rme96_t *rme96 = snd_pcm_substream_chip(substream);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -