📄 rme32.c
字号:
rme32->playback_periodsize = 0; spdif = (rme32->wcreg & RME32_WCR_ADAT) == 0; spin_unlock_irq(&rme32->lock); if (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_close(struct snd_pcm_substream *substream){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); spin_lock_irq(&rme32->lock); rme32->capture_substream = NULL; rme32->capture_periodsize = 0; spin_unlock(&rme32->lock); return 0;}static int snd_rme32_playback_prepare(struct snd_pcm_substream *substream){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); spin_lock_irq(&rme32->lock); if (rme32->fullduplex_mode) { memset(&rme32->playback_pcm, 0, sizeof(rme32->playback_pcm)); rme32->playback_pcm.hw_buffer_size = RME32_BUFFER_SIZE; rme32->playback_pcm.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); } else { writel(0, rme32->iobase + RME32_IO_RESET_POS); } if (rme32->wcreg & RME32_WCR_SEL) rme32->wcreg &= ~RME32_WCR_MUTE; writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); spin_unlock_irq(&rme32->lock); return 0;}static int snd_rme32_capture_prepare(struct snd_pcm_substream *substream){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); spin_lock_irq(&rme32->lock); if (rme32->fullduplex_mode) { memset(&rme32->capture_pcm, 0, sizeof(rme32->capture_pcm)); rme32->capture_pcm.hw_buffer_size = RME32_BUFFER_SIZE; rme32->capture_pcm.hw_queue_size = RME32_BUFFER_SIZE / 2; rme32->capture_pcm.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); } else { writel(0, rme32->iobase + RME32_IO_RESET_POS); } spin_unlock_irq(&rme32->lock); return 0;}static intsnd_rme32_pcm_trigger(struct snd_pcm_substream *substream, int cmd){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); struct snd_pcm_substream *s; spin_lock(&rme32->lock); snd_pcm_group_for_each_entry(s, substream) { if (s != rme32->playback_substream && s != rme32->capture_substream) continue; switch (cmd) { case SNDRV_PCM_TRIGGER_START: rme32->running |= (1 << s->stream); if (rme32->fullduplex_mode) { /* remember the current DMA position */ if (s == rme32->playback_substream) { rme32->playback_pcm.hw_io = rme32->playback_pcm.hw_data = snd_rme32_pcm_byteptr(rme32); } else { rme32->capture_pcm.hw_io = rme32->capture_pcm.hw_data = snd_rme32_pcm_byteptr(rme32); } } break; case SNDRV_PCM_TRIGGER_STOP: rme32->running &= ~(1 << s->stream); break; } snd_pcm_trigger_done(s, substream); } /* prefill playback buffer */ if (cmd == SNDRV_PCM_TRIGGER_START && rme32->fullduplex_mode) { snd_pcm_group_for_each_entry(s, substream) { if (s == rme32->playback_substream) { s->ops->ack(s); break; } } } switch (cmd) { case SNDRV_PCM_TRIGGER_START: if (rme32->running && ! RME32_ISWORKING(rme32)) snd_rme32_pcm_start(rme32, 0); break; case SNDRV_PCM_TRIGGER_STOP: if (! rme32->running && RME32_ISWORKING(rme32)) snd_rme32_pcm_stop(rme32, 0); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (rme32->running && RME32_ISWORKING(rme32)) snd_rme32_pcm_stop(rme32, 1); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (rme32->running && ! RME32_ISWORKING(rme32)) snd_rme32_pcm_start(rme32, 1); break; } spin_unlock(&rme32->lock); return 0;}/* pointer callback for halfduplex mode */static snd_pcm_uframes_tsnd_rme32_playback_pointer(struct snd_pcm_substream *substream){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); return snd_rme32_pcm_byteptr(rme32) >> rme32->playback_frlog;}static snd_pcm_uframes_tsnd_rme32_capture_pointer(struct snd_pcm_substream *substream){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); return snd_rme32_pcm_byteptr(rme32) >> rme32->capture_frlog;}/* ack and pointer callbacks for fullduplex mode */static void snd_rme32_pb_trans_copy(struct snd_pcm_substream *substream, struct snd_pcm_indirect *rec, size_t bytes){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); memcpy_toio(rme32->iobase + RME32_IO_DATA_BUFFER + rec->hw_data, substream->runtime->dma_area + rec->sw_data, bytes);}static int snd_rme32_playback_fd_ack(struct snd_pcm_substream *substream){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); struct snd_pcm_indirect *rec, *cprec; rec = &rme32->playback_pcm; cprec = &rme32->capture_pcm; spin_lock(&rme32->lock); rec->hw_queue_size = RME32_BUFFER_SIZE; if (rme32->running & (1 << SNDRV_PCM_STREAM_CAPTURE)) rec->hw_queue_size -= cprec->hw_ready; spin_unlock(&rme32->lock); snd_pcm_indirect_playback_transfer(substream, rec, snd_rme32_pb_trans_copy); return 0;}static void snd_rme32_cp_trans_copy(struct snd_pcm_substream *substream, struct snd_pcm_indirect *rec, size_t bytes){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); memcpy_fromio(substream->runtime->dma_area + rec->sw_data, rme32->iobase + RME32_IO_DATA_BUFFER + rec->hw_data, bytes);}static int snd_rme32_capture_fd_ack(struct snd_pcm_substream *substream){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); snd_pcm_indirect_capture_transfer(substream, &rme32->capture_pcm, snd_rme32_cp_trans_copy); return 0;}static snd_pcm_uframes_tsnd_rme32_playback_fd_pointer(struct snd_pcm_substream *substream){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); return snd_pcm_indirect_playback_pointer(substream, &rme32->playback_pcm, snd_rme32_pcm_byteptr(rme32));}static snd_pcm_uframes_tsnd_rme32_capture_fd_pointer(struct snd_pcm_substream *substream){ struct rme32 *rme32 = snd_pcm_substream_chip(substream); return snd_pcm_indirect_capture_pointer(substream, &rme32->capture_pcm, snd_rme32_pcm_byteptr(rme32));}/* for halfduplex mode */static struct snd_pcm_ops snd_rme32_playback_spdif_ops = { .open = snd_rme32_playback_spdif_open, .close = snd_rme32_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme32_playback_hw_params, .hw_free = snd_rme32_pcm_hw_free, .prepare = snd_rme32_playback_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_playback_pointer, .copy = snd_rme32_playback_copy, .silence = snd_rme32_playback_silence, .mmap = snd_pcm_lib_mmap_iomem,};static struct snd_pcm_ops snd_rme32_capture_spdif_ops = { .open = snd_rme32_capture_spdif_open, .close = snd_rme32_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme32_capture_hw_params, .hw_free = snd_rme32_pcm_hw_free, .prepare = snd_rme32_capture_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_capture_pointer, .copy = snd_rme32_capture_copy, .mmap = snd_pcm_lib_mmap_iomem,};static struct snd_pcm_ops snd_rme32_playback_adat_ops = { .open = snd_rme32_playback_adat_open, .close = snd_rme32_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme32_playback_hw_params, .prepare = snd_rme32_playback_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_playback_pointer, .copy = snd_rme32_playback_copy, .silence = snd_rme32_playback_silence, .mmap = snd_pcm_lib_mmap_iomem,};static struct snd_pcm_ops snd_rme32_capture_adat_ops = { .open = snd_rme32_capture_adat_open, .close = snd_rme32_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme32_capture_hw_params, .prepare = snd_rme32_capture_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_capture_pointer, .copy = snd_rme32_capture_copy, .mmap = snd_pcm_lib_mmap_iomem,};/* for fullduplex mode */static struct snd_pcm_ops snd_rme32_playback_spdif_fd_ops = { .open = snd_rme32_playback_spdif_open, .close = snd_rme32_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme32_playback_hw_params, .hw_free = snd_rme32_pcm_hw_free, .prepare = snd_rme32_playback_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_playback_fd_pointer, .ack = snd_rme32_playback_fd_ack,};static struct snd_pcm_ops snd_rme32_capture_spdif_fd_ops = { .open = snd_rme32_capture_spdif_open, .close = snd_rme32_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme32_capture_hw_params, .hw_free = snd_rme32_pcm_hw_free, .prepare = snd_rme32_capture_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_capture_fd_pointer, .ack = snd_rme32_capture_fd_ack,};static struct snd_pcm_ops snd_rme32_playback_adat_fd_ops = { .open = snd_rme32_playback_adat_open, .close = snd_rme32_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme32_playback_hw_params, .prepare = snd_rme32_playback_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_playback_fd_pointer, .ack = snd_rme32_playback_fd_ack,};static struct snd_pcm_ops snd_rme32_capture_adat_fd_ops = { .open = snd_rme32_capture_adat_open, .close = snd_rme32_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_rme32_capture_hw_params, .prepare = snd_rme32_capture_prepare, .trigger = snd_rme32_pcm_trigger, .pointer = snd_rme32_capture_fd_pointer, .ack = snd_rme32_capture_fd_ack,};static void snd_rme32_free(void *private_data){ struct rme32 *rme32 = (struct rme32 *) private_data; if (rme32 == NULL) { return; } if (rme32->irq >= 0) { snd_rme32_pcm_stop(rme32, 0); free_irq(rme32->irq, (void *) rme32); rme32->irq = -1; } if (rme32->iobase) { iounmap(rme32->iobase); rme32->iobase = NULL; } if (rme32->port) { pci_release_regions(rme32->pci); rme32->port = 0; } pci_disable_device(rme32->pci);}static void snd_rme32_free_spdif_pcm(struct snd_pcm *pcm){ struct rme32 *rme32 = (struct rme32 *) pcm->private_data; rme32->spdif_pcm = NULL;}static voidsnd_rme32_free_adat_pcm(struct snd_pcm *pcm){ struct rme32 *rme32 = (struct rme32 *) pcm->private_data; rme32->adat_pcm = NULL;}static int __devinit snd_rme32_create(struct rme32 * rme32){ struct pci_dev *pci = rme32->pci; int err; rme32->irq = -1; spin_lock_init(&rme32->lock); if ((err = pci_enable_device(pci)) < 0) return err; if ((err = pci_request_regions(pci, "RME32")) < 0) return err; rme32->port = pci_resource_start(rme32->pci, 0); if ((rme32->iobase = ioremap_nocache(rme32->port, RME32_IO_SIZE)) == 0) { snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", rme32->port, rme32->port + RME32_IO_SIZE - 1); return -ENOMEM; } if (request_irq(pci->irq, snd_rme32_interrupt, IRQF_SHARED, "RME32", rme32)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); return -EBUSY; } rme32->irq = pci->irq; /* read the card's revision number */ pci_read_config_byte(pci, 8, &rme32->rev); /* set up ALSA pcm device for S/PDIF */ if ((err = snd_pcm_new(rme32->card, "Digi32 IEC958", 0, 1, 1, &rme32->spdif_pcm)) < 0) { return err; } rme32->spdif_pcm->private_data = rme32; rme32->spdif_pcm->private_free = snd_rme32_free_spdif_pcm; strcpy(rme32->spdif_pcm->name, "Digi32 IEC958"); if (rme32->fullduplex_mode) { snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme32_playback_spdif_fd_ops); snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme32_capture_spdif_fd_ops); snd_pcm_lib_preallocate_pages_for_all(rme32->spdif_pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), 0, RME32_MID_BUFFER_SIZE); rme32->spdif_pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; } else { snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme32_playback_spdif_ops); snd_pcm_set_ops(rme32->spdif_pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme32_capture_spdif_ops); rme32->spdif_pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; } /* set up ALSA pcm device for ADAT */ if ((pci->device == PCI_DEVICE_ID_RME_DIGI32) || (pci->device == PCI_DEVICE_ID_RME_DIGI32_PRO)) { /* ADAT is not available on DIGI32 and DIGI32 Pro */ rme32->adat_pcm = NULL; } else { if ((err = snd_pcm_new(rme32->card, "Digi32 ADAT", 1, 1, 1, &rme32->adat_pcm)) < 0) { return err; } rme32->adat_pcm->private_data = rme32; rme32->adat_pcm->private_free = snd_rme32_free_adat_pcm; strcpy(rme32->adat_pcm->name, "Digi32 ADAT"); if (rme32->fullduplex_mode) { snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme32_playback_adat_fd_ops); snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme32_capture_adat_fd_ops); snd_pcm_lib_preallocate_pages_for_all(rme32->adat_pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), 0, RME32_MID_BUFFER_SIZE); rme32->adat_pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; } else { snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_rme32_playback_adat_ops); snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_rme32_capture_adat_ops); rme32->adat_pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; } } rme32->playback_periodsize = 0; rme32->capture_periodsize = 0; /* make sure playback/capture is stopped, if by some reason active */ snd_rme32_pcm_stop(rme32, 0); /* reset DAC */ snd_rme32_reset_dac(rme32); /* reset buffer pointer */ writel(0, rme32->iobase + RME32_IO_RESET_POS); /* set default values in registers */ rme32->wcreg = RME32_WCR_SEL | /* normal playback */ RME32_WCR_INP_0 | /* input select */ RME32_WCR_MUTE; /* muting on */ writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER); /* init switch interface */ if ((err = snd_rme32_create_switches(rme32->card, rme32)) < 0) { return err; } /* init proc interface */ snd_rme32_proc_init(rme32); rme32->capture_substream = NULL; rme32->playback_substream = NULL; return 0;}/* * proc interface */static voidsnd_rme32_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer){ int n; struct rme32 *rme32 = (struct rme32 *) entry->private_data; rme32->rcreg = readl(rme32->iobase + RME32_IO_CONTROL_REGISTER); snd_iprintf(buffer, rme32->card->longname); snd_iprintf(buffer, " (index #%d)\n", rme32->card->number + 1); snd_iprintf(buffer, "\nGeneral settings\n"); if (rme32->fullduplex_mode) snd_iprintf(buffer, " Full-duplex mode\n"); else snd_iprintf(buffer, " Half-duplex mode\n"); if (RME32_PRO_WITH_8414(rme32)) { snd_iprintf(buffer, " receiver: CS8414\n"); } else { snd_iprintf(buffer, " receiver: CS8412\n"); } if (rme32->wcreg & RME32_WCR_MODE24) { snd_iprintf(buffer, " format: 24 bit"); } else { snd_iprintf(buffer, " format: 16 bit"); } if (rme32->wcreg & RME32_WCR_MONO) { snd_iprintf(buffer, ", Mono\n"); } else { snd_iprintf(buffer, ", Stereo\n"); } snd_iprintf(buffer, "\nInput settings\n"); switch (snd_rme32_getinputtype(rme32)) { case RME32_INPUT_OPTICAL: snd_iprintf(buffer, " input: optical"); break; case RME32_INPUT_COAXIAL: snd_iprintf(buffer, " input: coaxial"); break; case RME32_INPUT_INTERNAL: snd_iprintf(buffer, " input: internal");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -