📄 rme32.c
字号:
rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_0) & ~RME32_WCR_FREQ_1; break; case 44100: rme32->wcreg &= ~RME32_WCR_DS_BM; rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_1) & ~RME32_WCR_FREQ_0; break; case 48000: rme32->wcreg &= ~RME32_WCR_DS_BM; rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_0) | RME32_WCR_FREQ_1; break; case 64000: if (rme32->pci->device != PCI_DEVICE_ID_RME_DIGI32_PRO) return -EINVAL; rme32->wcreg |= RME32_WCR_DS_BM; rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_0) & ~RME32_WCR_FREQ_1; break; case 88200: if (rme32->pci->device != PCI_DEVICE_ID_RME_DIGI32_PRO) return -EINVAL; rme32->wcreg |= RME32_WCR_DS_BM; rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_1) & ~RME32_WCR_FREQ_0; break; case 96000: if (rme32->pci->device != PCI_DEVICE_ID_RME_DIGI32_PRO) return -EINVAL; rme32->wcreg |= RME32_WCR_DS_BM; rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_0) | RME32_WCR_FREQ_1; break; default: return -EINVAL; } if ((!ds && rme32->wcreg & RME32_WCR_DS_BM) || (ds && !(rme32->wcreg & RME32_WCR_DS_BM))) { /* change to/from double-speed: reset the DAC (if available) */ snd_rme32_reset_dac(rme32); } else { writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); } return 0;}static int snd_rme32_setclockmode(struct rme32 * rme32, int mode){ switch (mode) { case RME32_CLOCKMODE_SLAVE: /* AutoSync */ rme32->wcreg = (rme32->wcreg & ~RME32_WCR_FREQ_0) & ~RME32_WCR_FREQ_1; break; case RME32_CLOCKMODE_MASTER_32: /* Internal 32.0kHz */ rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_0) & ~RME32_WCR_FREQ_1; break; case RME32_CLOCKMODE_MASTER_44: /* Internal 44.1kHz */ rme32->wcreg = (rme32->wcreg & ~RME32_WCR_FREQ_0) | RME32_WCR_FREQ_1; break; case RME32_CLOCKMODE_MASTER_48: /* Internal 48.0kHz */ rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_0) | RME32_WCR_FREQ_1; break; default: return -EINVAL; } writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); return 0;}static int snd_rme32_getclockmode(struct rme32 * rme32){ return ((rme32->wcreg >> RME32_WCR_BITPOS_FREQ_0) & 1) + (((rme32->wcreg >> RME32_WCR_BITPOS_FREQ_1) & 1) << 1);}static int snd_rme32_setinputtype(struct rme32 * rme32, int type){ switch (type) { case RME32_INPUT_OPTICAL: rme32->wcreg = (rme32->wcreg & ~RME32_WCR_INP_0) & ~RME32_WCR_INP_1; break; case RME32_INPUT_COAXIAL: rme32->wcreg = (rme32->wcreg | RME32_WCR_INP_0) & ~RME32_WCR_INP_1; break; case RME32_INPUT_INTERNAL: rme32->wcreg = (rme32->wcreg & ~RME32_WCR_INP_0) | RME32_WCR_INP_1; break; case RME32_INPUT_XLR: rme32->wcreg = (rme32->wcreg | RME32_WCR_INP_0) | RME32_WCR_INP_1; break; default: return -EINVAL; } writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); return 0;}static int snd_rme32_getinputtype(struct rme32 * rme32){ return ((rme32->wcreg >> RME32_WCR_BITPOS_INP_0) & 1) + (((rme32->wcreg >> RME32_WCR_BITPOS_INP_1) & 1) << 1);}static voidsnd_rme32_setframelog(struct rme32 * rme32, int n_channels, int is_playback){ int frlog; if (n_channels == 2) { frlog = 1; } else { /* assume 8 channels */ frlog = 3; } if (is_playback) { frlog += (rme32->wcreg & RME32_WCR_MODE24) ? 2 : 1; rme32->playback_frlog = frlog; } else { frlog += (rme32->wcreg & RME32_WCR_MODE24) ? 2 : 1; rme32->capture_frlog = frlog; }}static int snd_rme32_setformat(struct rme32 * rme32, int format){ switch (format) { case SNDRV_PCM_FORMAT_S16_LE: rme32->wcreg &= ~RME32_WCR_MODE24; break; case SNDRV_PCM_FORMAT_S32_LE: rme32->wcreg |= RME32_WCR_MODE24; break; default: return -EINVAL; } writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); return 0;}static intsnd_rme32_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params){ int err, rate, dummy; struct rme32 *rme32 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; if (rme32->fullduplex_mode) { err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); if (err < 0) return err; } else { runtime->dma_area = (void __force *)(rme32->iobase + RME32_IO_DATA_BUFFER); runtime->dma_addr = rme32->port + RME32_IO_DATA_BUFFER; runtime->dma_bytes = RME32_BUFFER_SIZE; } spin_lock_irq(&rme32->lock); if ((rme32->rcreg & RME32_RCR_KMODE) && (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) { /* AutoSync */ if ((int)params_rate(params) != rate) { spin_unlock_irq(&rme32->lock); return -EIO; } } else if ((err = snd_rme32_playback_setrate(rme32, params_rate(params))) < 0) { spin_unlock_irq(&rme32->lock); return err; } if ((err = snd_rme32_setformat(rme32, params_format(params))) < 0) { spin_unlock_irq(&rme32->lock); return err; } snd_rme32_setframelog(rme32, params_channels(params), 1); if (rme32->capture_periodsize != 0) { if (params_period_size(params) << rme32->playback_frlog != rme32->capture_periodsize) { spin_unlock_irq(&rme32->lock); return -EBUSY; } } rme32->playback_periodsize = params_period_size(params) << rme32->playback_frlog; /* S/PDIF setup */ if ((rme32->wcreg & RME32_WCR_ADAT) == 0) { rme32->wcreg &= ~(RME32_WCR_PRO | RME32_WCR_EMP); rme32->wcreg |= rme32->wcreg_spdif_stream; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); } spin_unlock_irq(&rme32->lock); return 0;}static intsnd_rme32_capture_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params){ int err, isadat, rate; struct rme32 *rme32 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; if (rme32->fullduplex_mode) { err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); if (err < 0) return err; } else { runtime->dma_area = (void __force *)rme32->iobase + RME32_IO_DATA_BUFFER; runtime->dma_addr = rme32->port + RME32_IO_DATA_BUFFER; runtime->dma_bytes = RME32_BUFFER_SIZE; } spin_lock_irq(&rme32->lock); /* enable AutoSync for record-preparing */ rme32->wcreg |= RME32_WCR_AUTOSYNC; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); if ((err = snd_rme32_setformat(rme32, params_format(params))) < 0) { spin_unlock_irq(&rme32->lock); return err; } if ((err = snd_rme32_playback_setrate(rme32, params_rate(params))) < 0) { spin_unlock_irq(&rme32->lock); return err; } if ((rate = snd_rme32_capture_getrate(rme32, &isadat)) > 0) { if ((int)params_rate(params) != rate) { spin_unlock_irq(&rme32->lock); return -EIO; } if ((isadat && runtime->hw.channels_min == 2) || (!isadat && runtime->hw.channels_min == 8)) { spin_unlock_irq(&rme32->lock); return -EIO; } } /* AutoSync off for recording */ rme32->wcreg &= ~RME32_WCR_AUTOSYNC; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); snd_rme32_setframelog(rme32, params_channels(params), 0); if (rme32->playback_periodsize != 0) { if (params_period_size(params) << rme32->capture_frlog != rme32->playback_periodsize) { spin_unlock_irq(&rme32->lock); return -EBUSY; } } rme32->capture_periodsize = params_period_size(params) << rme32->capture_frlog; spin_unlock_irq(&rme32->lock); return 0;}static int snd_rme32_pcm_hw_free(struct snd_pcm_substream *substream){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); if (! rme32->fullduplex_mode) return 0; return snd_pcm_lib_free_pages(substream);}static void snd_rme32_pcm_start(struct rme32 * rme32, int from_pause){ if (!from_pause) { writel(0, rme32->iobase + RME32_IO_RESET_POS); } rme32->wcreg |= RME32_WCR_START; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);}static void snd_rme32_pcm_stop(struct rme32 * rme32, int to_pause){ /* * Check if there is an unconfirmed IRQ, if so confirm it, or else * the hardware will not stop generating interrupts */ rme32->rcreg = readl(rme32->iobase + RME32_IO_CONTROL_REGISTER); if (rme32->rcreg & RME32_RCR_IRQ) { writel(0, rme32->iobase + RME32_IO_CONFIRM_ACTION_IRQ); } rme32->wcreg &= ~RME32_WCR_START; if (rme32->wcreg & RME32_WCR_SEL) rme32->wcreg |= RME32_WCR_MUTE; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); if (! to_pause) writel(0, rme32->iobase + RME32_IO_RESET_POS);}static irqreturn_t snd_rme32_interrupt(int irq, void *dev_id){ struct rme32 *rme32 = (struct rme32 *) dev_id; rme32->rcreg = readl(rme32->iobase + RME32_IO_CONTROL_REGISTER); if (!(rme32->rcreg & RME32_RCR_IRQ)) { return IRQ_NONE; } else { if (rme32->capture_substream) { snd_pcm_period_elapsed(rme32->capture_substream); } if (rme32->playback_substream) { snd_pcm_period_elapsed(rme32->playback_substream); } writel(0, rme32->iobase + RME32_IO_CONFIRM_ACTION_IRQ); } return IRQ_HANDLED;}static unsigned int period_bytes[] = { RME32_BLOCK_SIZE };static struct snd_pcm_hw_constraint_list hw_constraints_period_bytes = { .count = ARRAY_SIZE(period_bytes), .list = period_bytes, .mask = 0};static void snd_rme32_set_buffer_constraint(struct rme32 *rme32, struct snd_pcm_runtime *runtime){ if (! rme32->fullduplex_mode) { snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME32_BUFFER_SIZE, RME32_BUFFER_SIZE); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes); }}static int snd_rme32_playback_spdif_open(struct snd_pcm_substream *substream){ int rate, dummy; struct rme32 *rme32 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_set_sync(substream); spin_lock_irq(&rme32->lock); if (rme32->playback_substream != NULL) { spin_unlock_irq(&rme32->lock); return -EBUSY; } rme32->wcreg &= ~RME32_WCR_ADAT; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); rme32->playback_substream = substream; spin_unlock_irq(&rme32->lock); if (rme32->fullduplex_mode) runtime->hw = snd_rme32_spdif_fd_info; else runtime->hw = snd_rme32_spdif_info; if (rme32->pci->device == PCI_DEVICE_ID_RME_DIGI32_PRO) { runtime->hw.rates |= SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000; runtime->hw.rate_max = 96000; } if ((rme32->rcreg & RME32_RCR_KMODE) && (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) { /* AutoSync */ runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } snd_rme32_set_buffer_constraint(rme32, runtime); rme32->wcreg_spdif_stream = rme32->wcreg_spdif; rme32->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(rme32->card, SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &rme32->spdif_ctl->id); return 0;}static int snd_rme32_capture_spdif_open(struct snd_pcm_substream *substream){ int isadat, rate; struct rme32 *rme32 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_set_sync(substream); spin_lock_irq(&rme32->lock); if (rme32->capture_substream != NULL) { spin_unlock_irq(&rme32->lock); return -EBUSY; } rme32->capture_substream = substream; spin_unlock_irq(&rme32->lock); if (rme32->fullduplex_mode) runtime->hw = snd_rme32_spdif_fd_info; else runtime->hw = snd_rme32_spdif_info; if (RME32_PRO_WITH_8414(rme32)) { runtime->hw.rates |= SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000; runtime->hw.rate_max = 96000; } if ((rate = snd_rme32_capture_getrate(rme32, &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; } snd_rme32_set_buffer_constraint(rme32, runtime); return 0;}static intsnd_rme32_playback_adat_open(struct snd_pcm_substream *substream){ int rate, dummy; struct rme32 *rme32 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_set_sync(substream); spin_lock_irq(&rme32->lock); if (rme32->playback_substream != NULL) { spin_unlock_irq(&rme32->lock); return -EBUSY; } rme32->wcreg |= RME32_WCR_ADAT; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); rme32->playback_substream = substream; spin_unlock_irq(&rme32->lock); if (rme32->fullduplex_mode) runtime->hw = snd_rme32_adat_fd_info; else runtime->hw = snd_rme32_adat_info; if ((rme32->rcreg & RME32_RCR_KMODE) && (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) { /* AutoSync */ runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } snd_rme32_set_buffer_constraint(rme32, runtime); return 0;}static intsnd_rme32_capture_adat_open(struct snd_pcm_substream *substream){ int isadat, rate; struct rme32 *rme32 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; if (rme32->fullduplex_mode) runtime->hw = snd_rme32_adat_fd_info; else runtime->hw = snd_rme32_adat_info; if ((rate = snd_rme32_capture_getrate(rme32, &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; } snd_pcm_set_sync(substream); spin_lock_irq(&rme32->lock); if (rme32->capture_substream != NULL) { spin_unlock_irq(&rme32->lock); return -EBUSY; } rme32->capture_substream = substream; spin_unlock_irq(&rme32->lock); snd_rme32_set_buffer_constraint(rme32, runtime); return 0;}static int snd_rme32_playback_close(struct snd_pcm_substream *substream){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); int spdif = 0; spin_lock_irq(&rme32->lock); rme32->playback_substream = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -