📄 hdspm.c
字号:
else target_speed = HDSPM_SPEED_QUAD; switch (rate) { case 32000: rate_bits = HDSPM_Frequency32KHz; break; case 44100: rate_bits = HDSPM_Frequency44_1KHz; break; case 48000: rate_bits = HDSPM_Frequency48KHz; break; case 64000: rate_bits = HDSPM_Frequency64KHz; break; case 88200: rate_bits = HDSPM_Frequency88_2KHz; break; case 96000: rate_bits = HDSPM_Frequency96KHz; break; case 128000: rate_bits = HDSPM_Frequency128KHz; break; case 176400: rate_bits = HDSPM_Frequency176_4KHz; break; case 192000: rate_bits = HDSPM_Frequency192KHz; break; default: return -EINVAL; } if (current_speed != target_speed && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) { snd_printk (KERN_ERR "HDSPM: " "cannot change from %s speed to %s speed mode " "(capture PID = %d, playback PID = %d)\n", hdspm_speed_names[current_speed], hdspm_speed_names[target_speed], hdspm->capture_pid, hdspm->playback_pid); return -EBUSY; } hdspm->control_register &= ~HDSPM_FrequencyMask; hdspm->control_register |= rate_bits; hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); /* For AES32, need to set DDS value in FREQ register For MADI, also apparently */ hdspm_set_dds_value(hdspm, rate); if (hdspm->is_aes32 && rate != current_rate) hdspm_write(hdspm, HDSPM_eeprom_wr, 0); /* For AES32 and for MADI (at least rev 204), channel_map needs to * always be channel_map_madi_ss, whatever the sample rate */ hdspm->channel_map = channel_map_madi_ss; hdspm->system_sample_rate = rate; if (not_set != 0) return -1; return 0;}/* mainly for init to 0 on load */static void all_in_all_mixer(struct hdspm * hdspm, int sgain){ int i, j; unsigned int gain; if (sgain > UNITY_GAIN) gain = UNITY_GAIN; else if (sgain < 0) gain = 0; else gain = sgain; for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) for (j = 0; j < HDSPM_MIXER_CHANNELS; j++) { hdspm_write_in_gain(hdspm, i, j, gain); hdspm_write_pb_gain(hdspm, i, j, gain); }}/*---------------------------------------------------------------------------- MIDI ----------------------------------------------------------------------------*/static inline unsigned char snd_hdspm_midi_read_byte (struct hdspm *hdspm, int id){ /* the hardware already does the relevant bit-mask with 0xff */ if (id) return hdspm_read(hdspm, HDSPM_midiDataIn1); else return hdspm_read(hdspm, HDSPM_midiDataIn0);}static inline void snd_hdspm_midi_write_byte (struct hdspm *hdspm, int id, int val){ /* the hardware already does the relevant bit-mask with 0xff */ if (id) return hdspm_write(hdspm, HDSPM_midiDataOut1, val); else return hdspm_write(hdspm, HDSPM_midiDataOut0, val);}static inline int snd_hdspm_midi_input_available (struct hdspm *hdspm, int id){ if (id) return (hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xff); else return (hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xff);}static inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id){ int fifo_bytes_used; if (id) fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut1); else fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut0); fifo_bytes_used &= 0xff; if (fifo_bytes_used < 128) return 128 - fifo_bytes_used; else return 0;}static inline void snd_hdspm_flush_midi_input (struct hdspm *hdspm, int id){ while (snd_hdspm_midi_input_available (hdspm, id)) snd_hdspm_midi_read_byte (hdspm, id);}static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi){ unsigned long flags; int n_pending; int to_write; int i; unsigned char buf[128]; /* Output is not interrupt driven */ spin_lock_irqsave (&hmidi->lock, flags); if (hmidi->output && !snd_rawmidi_transmit_empty (hmidi->output)) { n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, hmidi->id); if (n_pending > 0) { if (n_pending > (int)sizeof (buf)) n_pending = sizeof (buf); to_write = snd_rawmidi_transmit (hmidi->output, buf, n_pending); if (to_write > 0) { for (i = 0; i < to_write; ++i) snd_hdspm_midi_write_byte (hmidi->hdspm, hmidi->id, buf[i]); } } } spin_unlock_irqrestore (&hmidi->lock, flags); return 0;}static int snd_hdspm_midi_input_read (struct hdspm_midi *hmidi){ unsigned char buf[128]; /* this buffer is designed to match the MIDI * input FIFO size */ unsigned long flags; int n_pending; int i; spin_lock_irqsave (&hmidi->lock, flags); n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id); if (n_pending > 0) { if (hmidi->input) { if (n_pending > (int)sizeof (buf)) n_pending = sizeof (buf); for (i = 0; i < n_pending; ++i) buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm, hmidi->id); if (n_pending) snd_rawmidi_receive (hmidi->input, buf, n_pending); } else { /* flush the MIDI input FIFO */ while (n_pending--) snd_hdspm_midi_read_byte (hmidi->hdspm, hmidi->id); } } hmidi->pending = 0; if (hmidi->id) hmidi->hdspm->control_register |= HDSPM_Midi1InterruptEnable; else hmidi->hdspm->control_register |= HDSPM_Midi0InterruptEnable; hdspm_write(hmidi->hdspm, HDSPM_controlRegister, hmidi->hdspm->control_register); spin_unlock_irqrestore (&hmidi->lock, flags); return snd_hdspm_midi_output_write (hmidi);}static voidsnd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up){ struct hdspm *hdspm; struct hdspm_midi *hmidi; unsigned long flags; u32 ie; hmidi = substream->rmidi->private_data; hdspm = hmidi->hdspm; ie = hmidi->id ? HDSPM_Midi1InterruptEnable : HDSPM_Midi0InterruptEnable; spin_lock_irqsave (&hdspm->lock, flags); if (up) { if (!(hdspm->control_register & ie)) { snd_hdspm_flush_midi_input (hdspm, hmidi->id); hdspm->control_register |= ie; } } else { hdspm->control_register &= ~ie; } hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); spin_unlock_irqrestore (&hdspm->lock, flags);}static void snd_hdspm_midi_output_timer(unsigned long data){ struct hdspm_midi *hmidi = (struct hdspm_midi *) data; unsigned long flags; snd_hdspm_midi_output_write(hmidi); spin_lock_irqsave (&hmidi->lock, flags); /* this does not bump hmidi->istimer, because the kernel automatically removed the timer when it expired, and we are now adding it back, thus leaving istimer wherever it was set before. */ if (hmidi->istimer) { hmidi->timer.expires = 1 + jiffies; add_timer(&hmidi->timer); } spin_unlock_irqrestore (&hmidi->lock, flags);}static voidsnd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up){ struct hdspm_midi *hmidi; unsigned long flags; hmidi = substream->rmidi->private_data; spin_lock_irqsave (&hmidi->lock, flags); if (up) { if (!hmidi->istimer) { init_timer(&hmidi->timer); hmidi->timer.function = snd_hdspm_midi_output_timer; hmidi->timer.data = (unsigned long) hmidi; hmidi->timer.expires = 1 + jiffies; add_timer(&hmidi->timer); hmidi->istimer++; } } else { if (hmidi->istimer && --hmidi->istimer <= 0) del_timer (&hmidi->timer); } spin_unlock_irqrestore (&hmidi->lock, flags); if (up) snd_hdspm_midi_output_write(hmidi);}static int snd_hdspm_midi_input_open(struct snd_rawmidi_substream *substream){ struct hdspm_midi *hmidi; hmidi = substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id); hmidi->input = substream; spin_unlock_irq (&hmidi->lock); return 0;}static int snd_hdspm_midi_output_open(struct snd_rawmidi_substream *substream){ struct hdspm_midi *hmidi; hmidi = substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); hmidi->output = substream; spin_unlock_irq (&hmidi->lock); return 0;}static int snd_hdspm_midi_input_close(struct snd_rawmidi_substream *substream){ struct hdspm_midi *hmidi; snd_hdspm_midi_input_trigger (substream, 0); hmidi = substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); hmidi->input = NULL; spin_unlock_irq (&hmidi->lock); return 0;}static int snd_hdspm_midi_output_close(struct snd_rawmidi_substream *substream){ struct hdspm_midi *hmidi; snd_hdspm_midi_output_trigger (substream, 0); hmidi = substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); hmidi->output = NULL; spin_unlock_irq (&hmidi->lock); return 0;}static struct snd_rawmidi_ops snd_hdspm_midi_output ={ .open = snd_hdspm_midi_output_open, .close = snd_hdspm_midi_output_close, .trigger = snd_hdspm_midi_output_trigger,};static struct snd_rawmidi_ops snd_hdspm_midi_input ={ .open = snd_hdspm_midi_input_open, .close = snd_hdspm_midi_input_close, .trigger = snd_hdspm_midi_input_trigger,};static int __devinit snd_hdspm_create_midi (struct snd_card *card, struct hdspm *hdspm, int id){ int err; char buf[32]; hdspm->midi[id].id = id; hdspm->midi[id].hdspm = hdspm; spin_lock_init (&hdspm->midi[id].lock); sprintf (buf, "%s MIDI %d", card->shortname, id+1); err = snd_rawmidi_new (card, buf, id, 1, 1, &hdspm->midi[id].rmidi); if (err < 0) return err; sprintf (hdspm->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1); hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; snd_rawmidi_set_ops(hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdspm_midi_output); snd_rawmidi_set_ops(hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_hdspm_midi_input); hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; return 0;}static void hdspm_midi_tasklet(unsigned long arg){ struct hdspm *hdspm = (struct hdspm *)arg; if (hdspm->midi[0].pending) snd_hdspm_midi_input_read (&hdspm->midi[0]); if (hdspm->midi[1].pending) snd_hdspm_midi_input_read (&hdspm->midi[1]);} /*----------------------------------------------------------------------------- Status Interface ----------------------------------------------------------------------------*//* get the system sample rate which is set */#define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ .index = xindex, \ .access = SNDRV_CTL_ELEM_ACCESS_READ, \ .info = snd_hdspm_info_system_sample_rate, \ .get = snd_hdspm_get_system_sample_rate \}static int snd_hdspm_info_system_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; return 0;}static int snd_hdspm_get_system_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value * ucontrol){ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = hdspm->system_sample_rate; return 0;}#define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ .index = xindex, \ .access = SNDRV_CTL_ELEM_ACCESS_READ, \ .info = snd_hdspm_info_autosync_sample_rate, \ .get = snd_hdspm_get_autosync_sample_rate \}static int snd_hdspm_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ static char *texts[] = { "32000", "44100", "48000", "64000", "88200", "96000", "128000", "176400", "192000", "None" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = 10; 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_autosync_sample_rate(struct snd_kcontrol *kcontrol,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -