📄 hdspm.c
字号:
hdspm->control_register |= HDSPM_InputSelect0; else hdspm->control_register &= ~HDSPM_InputSelect0; hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); return 0;}static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ static char *texts[] = { "optical", "coaxial" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = 2; 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_hdspm_get_input_select(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); spin_lock_irq(&hdspm->lock); ucontrol->value.enumerated.item[0] = hdspm_input_select(hdspm); spin_unlock_irq(&hdspm->lock); return 0;}static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); int change; unsigned int val; if (!snd_hdspm_use_is_exclusive(hdspm)) return -EBUSY; val = ucontrol->value.integer.value[0] & 1; spin_lock_irq(&hdspm->lock); change = (int) val != hdspm_input_select(hdspm); hdspm_set_input_select(hdspm, val); spin_unlock_irq(&hdspm->lock); return change;}/* Simple Mixer deprecated since to much faders ??? MIXER interface says output (source, destination, value) where source > MAX_channels are playback channels on MADICARD - playback mixer matrix: [channelout+64] [output] [value] - input(thru) mixer matrix: [channelin] [output] [value] (better do 2 kontrols for seperation ?)*/#define HDSPM_MIXER(xname, xindex) \{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ .name = xname, \ .index = xindex, \ .device = 0, \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ .info = snd_hdspm_info_mixer, \ .get = snd_hdspm_get_mixer, \ .put = snd_hdspm_put_mixer \}static int snd_hdspm_info_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 3; uinfo->value.integer.min = 0; uinfo->value.integer.max = 65535; uinfo->value.integer.step = 1; return 0;}static int snd_hdspm_get_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); int source; int destination; source = ucontrol->value.integer.value[0]; if (source < 0) source = 0; else if (source >= 2 * HDSPM_MAX_CHANNELS) source = 2 * HDSPM_MAX_CHANNELS - 1; destination = ucontrol->value.integer.value[1]; if (destination < 0) destination = 0; else if (destination >= HDSPM_MAX_CHANNELS) destination = HDSPM_MAX_CHANNELS - 1; spin_lock_irq(&hdspm->lock); if (source >= HDSPM_MAX_CHANNELS) ucontrol->value.integer.value[2] = hdspm_read_pb_gain(hdspm, destination, source - HDSPM_MAX_CHANNELS); else ucontrol->value.integer.value[2] = hdspm_read_in_gain(hdspm, destination, source); spin_unlock_irq(&hdspm->lock); return 0;}static int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); int change; int source; int destination; int gain; if (!snd_hdspm_use_is_exclusive(hdspm)) return -EBUSY; source = ucontrol->value.integer.value[0]; destination = ucontrol->value.integer.value[1]; if (source < 0 || source >= 2 * HDSPM_MAX_CHANNELS) return -1; if (destination < 0 || destination >= HDSPM_MAX_CHANNELS) return -1; gain = ucontrol->value.integer.value[2]; spin_lock_irq(&hdspm->lock); if (source >= HDSPM_MAX_CHANNELS) change = gain != hdspm_read_pb_gain(hdspm, destination, source - HDSPM_MAX_CHANNELS); else change = gain != hdspm_read_in_gain(hdspm, destination, source); if (change) { if (source >= HDSPM_MAX_CHANNELS) hdspm_write_pb_gain(hdspm, destination, source - HDSPM_MAX_CHANNELS, gain); else hdspm_write_in_gain(hdspm, destination, source, gain); } spin_unlock_irq(&hdspm->lock); return change;}/* The simple mixer control(s) provide gain control for the basic 1:1 mappings of playback streams to output streams. */#define HDSPM_PLAYBACK_MIXER \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ .info = snd_hdspm_info_playback_mixer, \ .get = snd_hdspm_get_playback_mixer, \ .put = snd_hdspm_put_playback_mixer \}static int snd_hdspm_info_playback_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 65536; uinfo->value.integer.step = 1; return 0;}static int snd_hdspm_get_playback_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); int channel; int mapped_channel; channel = ucontrol->id.index - 1; snd_assert(channel >= 0 || channel < HDSPM_MAX_CHANNELS, return -EINVAL); if ((mapped_channel = hdspm->channel_map[channel]) < 0) return -EINVAL; spin_lock_irq(&hdspm->lock); ucontrol->value.integer.value[0] = hdspm_read_pb_gain(hdspm, mapped_channel, mapped_channel); spin_unlock_irq(&hdspm->lock); /* snd_printdd("get pb mixer index %d, channel %d, mapped_channel %d, value %d\n", ucontrol->id.index, channel, mapped_channel, ucontrol->value.integer.value[0]); */ return 0;}static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); int change; int channel; int mapped_channel; int gain; if (!snd_hdspm_use_is_exclusive(hdspm)) return -EBUSY; channel = ucontrol->id.index - 1; snd_assert(channel >= 0 || channel < HDSPM_MAX_CHANNELS, return -EINVAL); if ((mapped_channel = hdspm->channel_map[channel]) < 0) return -EINVAL; gain = ucontrol->value.integer.value[0]; spin_lock_irq(&hdspm->lock); change = gain != hdspm_read_pb_gain(hdspm, mapped_channel, mapped_channel); if (change) hdspm_write_pb_gain(hdspm, mapped_channel, mapped_channel, gain); spin_unlock_irq(&hdspm->lock); return change;}#define HDSPM_WC_SYNC_CHECK(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_hdspm_info_sync_check, \ .get = snd_hdspm_get_wc_sync_check \}static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ static char *texts[] = { "No Lock", "Lock", "Sync" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = 3; 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 hdspm_wc_sync_check(struct hdspm * hdspm){ int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); if (status2 & HDSPM_wcLock) { if (status2 & HDSPM_wcSync) return 2; else return 1; } return 0;}static int snd_hdspm_get_wc_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdspm_wc_sync_check(hdspm); return 0;}#define HDSPM_MADI_SYNC_CHECK(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_hdspm_info_sync_check, \ .get = snd_hdspm_get_madisync_sync_check \}static int hdspm_madisync_sync_check(struct hdspm * hdspm){ int status = hdspm_read(hdspm, HDSPM_statusRegister); if (status & HDSPM_madiLock) { if (status & HDSPM_madiSync) return 2; else return 1; } return 0;}static int snd_hdspm_get_madisync_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value * ucontrol){ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdspm_madisync_sync_check(hdspm); return 0;}static struct snd_kcontrol_new snd_hdspm_controls[] = { HDSPM_MIXER("Mixer", 0),/* 'Sample Clock Source' complies with the alsa control naming scheme */ HDSPM_CLOCK_SOURCE("Sample Clock Source", 0), HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),/* 'External Rate' complies with the alsa control naming scheme */ HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), HDSPM_WC_SYNC_CHECK("Word Clock Lock Status", 0), HDSPM_MADI_SYNC_CHECK("MADI Sync Lock Status", 0), HDSPM_LINE_OUT("Line Out", 0), HDSPM_TX_64("TX 64 channels mode", 0), HDSPM_C_TMS("Clear Track Marker", 0), HDSPM_SAFE_MODE("Safe Mode", 0), HDSPM_INPUT_SELECT("Input Select", 0),};static struct snd_kcontrol_new snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER;static int hdspm_update_simple_mixer_controls(struct hdspm * hdspm){ int i; for (i = hdspm->ds_channels; i < hdspm->ss_channels; ++i) { if (hdspm->system_sample_rate > 48000) { hdspm->playback_mixer_ctls[i]->vd[0].access = SNDRV_CTL_ELEM_ACCESS_INACTIVE | SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE; } else { hdspm->playback_mixer_ctls[i]->vd[0].access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_VOLATILE; } snd_ctl_notify(hdspm->card, SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &hdspm->playback_mixer_ctls[i]->id); } return 0;}static int snd_hdspm_create_controls(struct snd_card *card, struct hdspm * hdspm){ unsigned int idx, limit; int err; struct snd_kcontrol *kctl; /* add control list first */ for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls); idx++) { if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdspm_controls[idx], hdspm))) < 0) { return err; } } /* Channel playback mixer as default control Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats too big for any alsamixer they are accesible via special IOCTL on hwdep and the mixer 2dimensional mixer control */ snd_hdspm_playback_mixer.name = "Chn"; limit = HDSPM_MAX_CHANNELS; /* The index values are one greater than the channel ID so that alsamixer will display them correctly. We want to use the index for fast lookup of the relevant channel, but if we use it at all, most ALSA software does the wrong thing with it ... */ for (idx = 0; idx < limit; ++idx) { snd_hdspm_playback_mixer.index = idx + 1; if ((err = snd_ctl_add(card, kctl = snd_ctl_new1 (&snd_hdspm_playback_mixer, hdspm)))) { return err; } hdspm->playback_mixer_ctls[idx] = kctl; } return 0;}/*------------------------------------------------------------ /proc interface ------------------------------------------------------------*/static voidsnd_hdspm_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer){ struct hdspm *hdspm = (struct hdspm *) entry->private_data; unsigned int status; unsigned int status2; char *pref_sync_ref; char *autosync_ref; char *system_clock_mode; char *clock_source; char *insel; char *syncref; int x, x2; status = hdspm_read(hdspm, HDSPM_statusRegister); status2 = hdspm_read(hdspm, HDSPM_statusRegister2); snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", hdspm->card_name, hdspm->card->number + 1, hdspm->firmware_rev, (status2 & HDSPM_version0) | (status2 & HDSPM_version1) | (status2 & HDSPM_version2)); snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); snd_iprintf(buffer, "--- System ---\n"); snd_iprintf(buffer, "IRQ Pending: Au
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -