📄 rme9652.c
字号:
spin_unlock_irq(&rme9652->lock); return err ? err : change;}/* Read-only switches */#define RME9652_SPDIF_RATE(xname, xindex) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ .info = snd_rme9652_info_spdif_rate, \ .get = snd_rme9652_get_spdif_rate }static int snd_rme9652_info_spdif_rate(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 96000; return 0;}static int snd_rme9652_get_spdif_rate(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); spin_lock_irq(&rme9652->lock); ucontrol->value.integer.value[0] = rme9652_spdif_sample_rate(rme9652); spin_unlock_irq(&rme9652->lock); return 0;}#define RME9652_ADAT_SYNC(xname, xindex, xidx) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ .info = snd_rme9652_info_adat_sync, \ .get = snd_rme9652_get_adat_sync, .private_value = xidx }static int snd_rme9652_info_adat_sync(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ static char *texts[4] = {"No Lock", "Lock", "No Lock Sync", "Lock Sync"}; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = 4; if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0;}static int snd_rme9652_get_adat_sync(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); unsigned int mask1, mask2, val; switch (kcontrol->private_value) { case 0: mask1 = RME9652_lock_0; mask2 = RME9652_sync_0; break; case 1: mask1 = RME9652_lock_1; mask2 = RME9652_sync_1; break; case 2: mask1 = RME9652_lock_2; mask2 = RME9652_sync_2; break; default: return -EINVAL; } val = rme9652_read(rme9652, RME9652_status_register); ucontrol->value.enumerated.item[0] = (val & mask1) ? 1 : 0; ucontrol->value.enumerated.item[0] |= (val & mask2) ? 2 : 0; return 0;}#define RME9652_TC_VALID(xname, xindex) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ .info = snd_rme9652_info_tc_valid, \ .get = snd_rme9652_get_tc_valid }static int snd_rme9652_info_tc_valid(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0;}static int snd_rme9652_get_tc_valid(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ rme9652_t *rme9652 = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = (rme9652_read(rme9652, RME9652_status_register) & RME9652_tc_valid) ? 1 : 0; return 0;}#ifdef ALSA_HAS_STANDARD_WAY_OF_RETURNING_TIMECODE/* FIXME: this routine needs a port to the new control API --jk */static int snd_rme9652_get_tc_value(void *private_data, snd_kswitch_t *kswitch, snd_switch_t *uswitch){ rme9652_t *s = (rme9652_t *) private_data; u32 value; int i; uswitch->type = SNDRV_SW_TYPE_DWORD; if ((rme9652_read(s, RME9652_status_register) & RME9652_tc_valid) == 0) { uswitch->value.data32[0] = 0; return 0; } /* timecode request */ rme9652_write(s, RME9652_time_code, 0); /* XXX bug alert: loop-based timing !!!! */ for (i = 0; i < 50; i++) { if (!(rme9652_read(s, i * 4) & RME9652_tc_busy)) break; } if (!(rme9652_read(s, i * 4) & RME9652_tc_busy)) { return -EIO; } value = 0; for (i = 0; i < 32; i++) { value >>= 1; if (rme9652_read(s, i * 4) & RME9652_tc_out) value |= 0x80000000; } if (value > 2 * 60 * 48000) { value -= 2 * 60 * 48000; } else { value = 0; } uswitch->value.data32[0] = value; return 0;}#endif /* ALSA_HAS_STANDARD_WAY_OF_RETURNING_TIMECODE */static snd_kcontrol_new_t snd_rme9652_controls[] = {{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), .info = snd_rme9652_control_spdif_info, .get = snd_rme9652_control_spdif_get, .put = snd_rme9652_control_spdif_put,},{ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM), .info = snd_rme9652_control_spdif_stream_info, .get = snd_rme9652_control_spdif_stream_get, .put = snd_rme9652_control_spdif_stream_put,},{ .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), .info = snd_rme9652_control_spdif_mask_info, .get = snd_rme9652_control_spdif_mask_get, .private_value = IEC958_AES0_NONAUDIO | IEC958_AES0_PROFESSIONAL | IEC958_AES0_CON_EMPHASIS, },{ .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), .info = snd_rme9652_control_spdif_mask_info, .get = snd_rme9652_control_spdif_mask_get, .private_value = IEC958_AES0_NONAUDIO | IEC958_AES0_PROFESSIONAL | IEC958_AES0_PRO_EMPHASIS,},RME9652_SPDIF_IN("IEC958 Input Connector", 0),RME9652_SPDIF_OUT("IEC958 Output also on ADAT1", 0),RME9652_SYNC_MODE("Sync Mode", 0),RME9652_SYNC_PREF("Preferred Sync Source", 0),{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channels Thru", .index = 0, .info = snd_rme9652_info_thru, .get = snd_rme9652_get_thru, .put = snd_rme9652_put_thru,},RME9652_SPDIF_RATE("IEC958 Sample Rate", 0),RME9652_ADAT_SYNC("ADAT1 Sync Check", 0, 0),RME9652_ADAT_SYNC("ADAT2 Sync Check", 0, 1),RME9652_TC_VALID("Timecode Valid", 0),RME9652_PASSTHRU("Passthru", 0)};static snd_kcontrol_new_t snd_rme9652_adat3_check =RME9652_ADAT_SYNC("ADAT3 Sync Check", 0, 2);static snd_kcontrol_new_t snd_rme9652_adat1_input =RME9652_ADAT1_IN("ADAT1 Input Source", 0);static int snd_rme9652_create_controls(snd_card_t *card, rme9652_t *rme9652){ unsigned int idx; int err; snd_kcontrol_t *kctl; for (idx = 0; idx < ARRAY_SIZE(snd_rme9652_controls); idx++) { if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_controls[idx], rme9652))) < 0) return err; if (idx == 1) /* IEC958 (S/PDIF) Stream */ rme9652->spdif_ctl = kctl; } if (rme9652->ss_channels == RME9652_NCHANNELS) if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_adat3_check, rme9652))) < 0) return err; if (rme9652->hw_rev >= 15) if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_rme9652_adat1_input, rme9652))) < 0) return err; return 0;}/*------------------------------------------------------------ /proc interface ------------------------------------------------------------*/static voidsnd_rme9652_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer){ rme9652_t *rme9652 = (rme9652_t *) entry->private_data; u32 thru_bits = rme9652->thru_bits; int show_auto_sync_source = 0; int i; unsigned int status; int x; status = rme9652_read(rme9652, RME9652_status_register); snd_iprintf(buffer, "%s (Card #%d)\n", rme9652->card_name, rme9652->card->number + 1); snd_iprintf(buffer, "Buffers: capture %p playback %p\n", rme9652->capture_buffer, rme9652->playback_buffer); snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", rme9652->irq, rme9652->port, (unsigned long)rme9652->iobase); snd_iprintf(buffer, "Control register: %x\n", rme9652->control_register); snd_iprintf(buffer, "\n"); x = 1 << (6 + rme9652_decode_latency(rme9652->control_register & RME9652_latency)); snd_iprintf(buffer, "Latency: %d samples (2 periods of %lu bytes)\n", x, (unsigned long) rme9652->period_bytes); snd_iprintf(buffer, "Hardware pointer (frames): %ld\n", rme9652_hw_pointer(rme9652)); snd_iprintf(buffer, "Passthru: %s\n", rme9652->passthru ? "yes" : "no"); if ((rme9652->control_register & (RME9652_Master | RME9652_wsel)) == 0) { snd_iprintf(buffer, "Clock mode: autosync\n"); show_auto_sync_source = 1; } else if (rme9652->control_register & RME9652_wsel) { if (status & RME9652_wsel_rd) { snd_iprintf(buffer, "Clock mode: word clock\n"); } else { snd_iprintf(buffer, "Clock mode: word clock (no signal)\n"); } } else { snd_iprintf(buffer, "Clock mode: master\n"); } if (show_auto_sync_source) { switch (rme9652->control_register & RME9652_SyncPref_Mask) { case RME9652_SyncPref_ADAT1: snd_iprintf(buffer, "Pref. sync source: ADAT1\n"); break; case RME9652_SyncPref_ADAT2: snd_iprintf(buffer, "Pref. sync source: ADAT2\n"); break; case RME9652_SyncPref_ADAT3: snd_iprintf(buffer, "Pref. sync source: ADAT3\n"); break; case RME9652_SyncPref_SPDIF: snd_iprintf(buffer, "Pref. sync source: IEC958\n"); break; default: snd_iprintf(buffer, "Pref. sync source: ???\n"); } } if (rme9652->hw_rev >= 15) snd_iprintf(buffer, "\nADAT1 Input source: %s\n", (rme9652->control_register & RME9652_ADAT1_INTERNAL) ? "Internal" : "ADAT1 optical"); snd_iprintf(buffer, "\n"); switch (rme9652_decode_spdif_in(rme9652->control_register & RME9652_inp)) { case RME9652_SPDIFIN_OPTICAL: snd_iprintf(buffer, "IEC958 input: ADAT1\n"); break; case RME9652_SPDIFIN_COAXIAL: snd_iprintf(buffer, "IEC958 input: Coaxial\n"); break; case RME9652_SPDIFIN_INTERN: snd_iprintf(buffer, "IEC958 input: Internal\n"); break; default: snd_iprintf(buffer, "IEC958 input: ???\n"); break; } if (rme9652->control_register & RME9652_opt_out) { snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n"); } else { snd_iprintf(buffer, "IEC958 output: Coaxial only\n"); } if (rme9652->control_register & RME9652_PRO) { snd_iprintf(buffer, "IEC958 quality: Professional\n"); } else { snd_iprintf(buffer, "IEC958 quality: Consumer\n"); } if (rme9652->control_register & RME9652_EMP) { snd_iprintf(buffer, "IEC958 emphasis: on\n"); } else { snd_iprintf(buffer, "IEC958 emphasis: off\n"); } if (rme9652->control_register & RME9652_Dolby) { snd_iprintf(buffer, "IEC958 Dolby: on\n"); } else { snd_iprintf(buffer, "IEC958 Dolby: off\n"); } i = rme9652_spdif_sample_rate(rme9652); if (i < 0) { snd_iprintf(buffer, "IEC958 sample rate: error flag set\n"); } else if (i == 0) { snd_iprintf(buffer, "IEC958 sample rate: undetermined\n"); } else { snd_iprintf(buffer, "IEC958 sample rate: %d\n", i); } snd_iprintf(buffer, "\n"); snd_iprintf(buffer, "ADAT Sample rate: %dHz\n", rme9652_adat_sample_rate(rme9652)); /* Sync Check */ x = status & RME9652_sync_0; if (status & RME9652_lock_0) { snd_iprintf(buffer, "ADAT1: %s\n", x ? "Sync" : "Lock"); } else { snd_iprintf(buffer, "ADAT1: No Lock\n"); } x = status & RME9652_sync_1; if (status & RME9652_lock_1) { snd_iprintf(buffer, "ADAT2: %s\n", x ? "Sync" : "Lock"); } else { snd_iprintf(buffer, "ADAT2: No Lock\n"); } x = status & RME9652_sync_2; if (status & RME9652_lock_2) { snd_iprintf(buffer, "ADAT3: %s\n", x ? "Sync" : "Lock"); } else { snd_iprintf(buffer, "ADAT3: No Lock\n"); } snd_iprintf(buffer, "\n"); snd_iprintf(buffer, "Timecode signal: %s\n", (status & RME9652_tc_valid) ? "yes" : "no"); /* thru modes */ snd_iprintf(buffer, "Punch Status:\n\n"); for (i = 0; i < rme9652->ss_channels; i++) { if (thru_bits & (1 << i)) { snd_iprintf(buffer, "%2d: on ", i + 1); } else { snd_iprintf(buffer, "%2d: off ", i + 1); } if (((i + 1) % 8) == 0) { snd_iprintf(buffer, "\n"); } } snd_iprintf(buffer, "\n");}static void __devinit snd_rme9652_proc_init(rme9652_t *rme9652){ snd_info_entry_t *entry; if (! snd_card_proc_new(rme9652->card, "rme9652", &entry)) snd_info_set_text_ops(entry, rme9652, 1024, snd_rme9652_proc_read);}static void snd_rme9652_free_buffers(rme9652_t *rme9652){ snd_hammerfall_free_buffer(&rme9652->capture_dma_buf, rme9652->pci); snd_hammerfall_free_buffer(&rme9652->playback_dma_buf, rme9652->pci);}static int snd_rme9652_free(rme9652_t *rme9652){ if (rme9652->irq >= 0) rme9652_stop(rme9652); snd_rme9652_free_buffers(rme9652); if (rme9652->irq >= 0) free_irq(rme9652->irq, (void *)rme9652); if (rme9652->iobase) iounmap(rme9652->iobase); if (rme9652->port) pci_release_regions(rme9652->pci); pci_disable_device(rme9652->pci); return 0;}static int __devinit snd_rme9652_initialize_memory(rme9652_t *rme9652){ unsigned long pb_bus, cb_bus; if (snd_hammerfall_get_buffer(rme9652->pci, &rme9652->capture_dma_buf, RME9652_DMA_AREA_BYTES) < 0 || snd_hammerfall_get_buffer(rme9652->pci, &rme9652->playback_dma_buf, RME9652_DMA_AREA_BYTES) < 0) { if (rme9652->capture_dma_buf.area) snd_dma_free_pages(&rme9652->capture_dma_buf); printk(KERN_ERR "%s: no buffers available\n", rme9652->card_name); return -ENOMEM; } /* Align to bus-space 64K boundary */ cb_bus = (rme9652->capture_dma_buf.addr + 0xFFFF) & ~0xFFFFl; pb_bus = (rme9652->playback_dma_buf.addr + 0xFFFF) & ~0xFFFFl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -