📄 rme96.c
字号:
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(struct rme96 *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(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params){ struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err, rate, dummy; runtime->dma_area = (void __force *)(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(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params){ struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err, isadat, rate; runtime->dma_area = (void __force *)(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(struct rme96 *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(struct rme96 *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(struct rme96 *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(struct rme96 *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 rme96 *rme96 = (struct rme96 *)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 struct snd_pcm_hw_constraint_list hw_constraints_period_bytes = { .count = ARRAY_SIZE(period_bytes), .list = period_bytes, .mask = 0};static voidrme96_set_buffer_size_constraint(struct rme96 *rme96, struct snd_pcm_runtime *runtime){ unsigned int size; snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE); if ((size = rme96->playback_periodsize) != 0 || (size = rme96->capture_periodsize) != 0) snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, size, size); else snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);}static intsnd_rme96_playback_spdif_open(struct snd_pcm_substream *substream){ int rate, dummy; struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; 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_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } rme96_set_buffer_size_constraint(rme96, runtime); 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(struct snd_pcm_substream *substream){ int isadat, rate; struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; 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_pcm_rate_to_rate_bit(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); rme96_set_buffer_size_constraint(rme96, runtime); return 0;}static intsnd_rme96_playback_adat_open(struct snd_pcm_substream *substream){ int rate, dummy; struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; 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_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } rme96_set_buffer_size_constraint(rme96, runtime); return 0;}static intsnd_rme96_capture_adat_open(struct snd_pcm_substream *substream){ int isadat, rate; struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; 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_pcm_rate_to_rate_bit(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); rme96_set_buffer_size_constraint(rme96, runtime); return 0;}static intsnd_rme96_playback_close(struct snd_pcm_substream *substream){ struct rme96 *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(struct snd_pcm_substream *substream){ struct rme96 *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(struct snd_pcm_substream *substream){ struct rme96 *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(struct snd_pcm_substream *substream){ struct rme96 *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(struct snd_pcm_substream *substream, int cmd){ struct rme96 *rme96 = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_START: if (!RME96_ISPLAYING(rme96)) { if (substream != rme96->playback_substream) { return -EBUSY; } snd_rme96_playback_start(rme96, 0); } break; case SNDRV_PCM_TRIGGER_STOP: if (RME96_ISPLAYING(rme96)) { if (substream != rme96->playback_substream) { return -EBUSY;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -