📄 hdsp.c
字号:
int ret = 1; spin_lock_irqsave(&hdsp->lock, flags); if ((hdsp->playback_pid != hdsp->capture_pid) && (hdsp->playback_pid >= 0) && (hdsp->capture_pid >= 0)) { ret = 0; } spin_unlock_irqrestore(&hdsp->lock, flags); return ret;}static inline int hdsp_external_sample_rate (hdsp_t *hdsp){ unsigned int status2 = hdsp_read(hdsp, HDSP_status2Register); unsigned int rate_bits = status2 & HDSP_systemFrequencyMask; switch (rate_bits) { case HDSP_systemFrequency32: return 32000; case HDSP_systemFrequency44_1: return 44100; case HDSP_systemFrequency48: return 48000; case HDSP_systemFrequency64: return 64000; case HDSP_systemFrequency88_2: return 88200; case HDSP_systemFrequency96: return 96000; default: return 0; }}static inline int hdsp_spdif_sample_rate(hdsp_t *hdsp){ unsigned int status = hdsp_read(hdsp, HDSP_statusRegister); unsigned int rate_bits = (status & HDSP_spdifFrequencyMask); if (status & HDSP_SPDIFErrorFlag) { return 0; } switch (rate_bits) { case HDSP_spdifFrequency32KHz: return 32000; case HDSP_spdifFrequency44_1KHz: return 44100; case HDSP_spdifFrequency48KHz: return 48000; case HDSP_spdifFrequency64KHz: return 64000; case HDSP_spdifFrequency88_2KHz: return 88200; case HDSP_spdifFrequency96KHz: return 96000; case HDSP_spdifFrequency128KHz: if (hdsp->io_type == H9632) return 128000; break; case HDSP_spdifFrequency176_4KHz: if (hdsp->io_type == H9632) return 176400; break; case HDSP_spdifFrequency192KHz: if (hdsp->io_type == H9632) return 192000; break; default: break; } snd_printk ("unknown spdif frequency status; bits = 0x%x, status = 0x%x\n", rate_bits, status); return 0;}static inline void hdsp_compute_period_size(hdsp_t *hdsp){ hdsp->period_bytes = 1 << ((hdsp_decode_latency(hdsp->control_register) + 8));}static snd_pcm_uframes_t hdsp_hw_pointer(hdsp_t *hdsp){ int position; position = hdsp_read(hdsp, HDSP_statusRegister); if (!hdsp->precise_ptr) { return (position & HDSP_BufferID) ? (hdsp->period_bytes / 4) : 0; } position &= HDSP_BufferPositionMask; position /= 4; position -= 32; position &= (HDSP_CHANNEL_BUFFER_SAMPLES-1); return position;}static inline void hdsp_reset_hw_pointer(hdsp_t *hdsp){ hdsp_write (hdsp, HDSP_resetPointer, 0);}static inline void hdsp_start_audio(hdsp_t *s){ s->control_register |= (HDSP_AudioInterruptEnable | HDSP_Start); hdsp_write(s, HDSP_controlRegister, s->control_register);}static inline void hdsp_stop_audio(hdsp_t *s){ s->control_register &= ~(HDSP_Start | HDSP_AudioInterruptEnable); hdsp_write(s, HDSP_controlRegister, s->control_register);}static inline void hdsp_silence_playback(hdsp_t *hdsp){ memset(hdsp->playback_buffer, 0, HDSP_DMA_AREA_BYTES);}static int hdsp_set_interrupt_interval(hdsp_t *s, unsigned int frames){ int n; spin_lock_irq(&s->lock); frames >>= 7; n = 0; while (frames) { n++; frames >>= 1; } s->control_register &= ~HDSP_LatencyMask; s->control_register |= hdsp_encode_latency(n); hdsp_write(s, HDSP_controlRegister, s->control_register); hdsp_compute_period_size(s); spin_unlock_irq(&s->lock); return 0;}static int hdsp_set_rate(hdsp_t *hdsp, int rate, int called_internally){ int reject_if_open = 0; int current_rate; int rate_bits; /* ASSUMPTION: hdsp->lock is either held, or there is no need for it (e.g. during module initialization). */ if (!(hdsp->control_register & HDSP_ClockModeMaster)) { if (called_internally) { /* request from ctl or card initialization */ snd_printk("device is not running as a clock master: cannot set sample rate.\n"); return -1; } else { /* hw_param request while in AutoSync mode */ int external_freq = hdsp_external_sample_rate(hdsp); int spdif_freq = hdsp_spdif_sample_rate(hdsp); if ((spdif_freq == external_freq*2) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1)) { snd_printk("Detected ADAT in double speed mode\n"); } else if (hdsp->io_type == H9632 && (spdif_freq == external_freq*4) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1)) { snd_printk("Detected ADAT in quad speed mode\n"); } else if (rate != external_freq) { snd_printk("No AutoSync source for requested rate\n"); return -1; } } } current_rate = hdsp->system_sample_rate; /* Changing from a "single speed" to a "double speed" rate is not allowed if any substreams are open. This is because such a change causes a shift in the location of the DMA buffers and a reduction in the number of available buffers. Note that a similar but essentially insoluble problem exists for externally-driven rate changes. All we can do is to flag rate changes in the read/write routines. */ if (rate > 96000 && hdsp->io_type != H9632) { return -EINVAL; } switch (rate) { case 32000: if (current_rate > 48000) { reject_if_open = 1; } rate_bits = HDSP_Frequency32KHz; break; case 44100: if (current_rate > 48000) { reject_if_open = 1; } rate_bits = HDSP_Frequency44_1KHz; break; case 48000: if (current_rate > 48000) { reject_if_open = 1; } rate_bits = HDSP_Frequency48KHz; break; case 64000: if (current_rate <= 48000 || current_rate > 96000) { reject_if_open = 1; } rate_bits = HDSP_Frequency64KHz; break; case 88200: if (current_rate <= 48000 || current_rate > 96000) { reject_if_open = 1; } rate_bits = HDSP_Frequency88_2KHz; break; case 96000: if (current_rate <= 48000 || current_rate > 96000) { reject_if_open = 1; } rate_bits = HDSP_Frequency96KHz; break; case 128000: if (current_rate < 128000) { reject_if_open = 1; } rate_bits = HDSP_Frequency128KHz; break; case 176400: if (current_rate < 128000) { reject_if_open = 1; } rate_bits = HDSP_Frequency176_4KHz; break; case 192000: if (current_rate < 128000) { reject_if_open = 1; } rate_bits = HDSP_Frequency192KHz; break; default: return -EINVAL; } if (reject_if_open && (hdsp->capture_pid >= 0 || hdsp->playback_pid >= 0)) { snd_printk ("cannot change speed mode (capture PID = %d, playback PID = %d)\n", hdsp->capture_pid, hdsp->playback_pid); return -EBUSY; } hdsp->control_register &= ~HDSP_FrequencyMask; hdsp->control_register |= rate_bits; hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); if (rate >= 128000) { hdsp->channel_map = channel_map_H9632_qs; } else if (rate > 48000) { if (hdsp->io_type == H9632) { hdsp->channel_map = channel_map_H9632_ds; } else { hdsp->channel_map = channel_map_ds; } } else { switch (hdsp->io_type) { case Multiface: hdsp->channel_map = channel_map_mf_ss; break; case Digiface: case H9652: hdsp->channel_map = channel_map_df_ss; break; case H9632: hdsp->channel_map = channel_map_H9632_ss; break; default: /* should never happen */ break; } } hdsp->system_sample_rate = rate; return 0;}static void hdsp_set_thru(hdsp_t *hdsp, int channel, int enable){ hdsp->passthru = 0; if (channel < 0) { int i; /* set thru for all channels */ if (enable) { for (i = 0; i < hdsp->max_channels; i++) { hdsp_write_gain (hdsp, hdsp_input_to_output_key(hdsp,i,i), UNITY_GAIN); } } else { for (i = 0; i < hdsp->max_channels; i++) { hdsp_write_gain (hdsp, hdsp_input_to_output_key(hdsp,i,i), MINUS_INFINITY_GAIN); } } } else { int mapped_channel; snd_assert(channel < hdsp->max_channels, return); mapped_channel = hdsp->channel_map[channel]; snd_assert(mapped_channel > -1, return); if (enable) { hdsp_write_gain (hdsp, hdsp_input_to_output_key(hdsp,mapped_channel,mapped_channel), UNITY_GAIN); } else { hdsp_write_gain (hdsp, hdsp_input_to_output_key(hdsp,mapped_channel,mapped_channel), MINUS_INFINITY_GAIN); } }}static int hdsp_set_passthru(hdsp_t *hdsp, int onoff){ if (onoff) { hdsp_set_thru(hdsp, -1, 1); hdsp_reset_hw_pointer(hdsp); hdsp_silence_playback(hdsp); /* we don't want interrupts, so do a custom version of hdsp_start_audio(). */ hdsp->control_register |= (HDSP_Start|HDSP_AudioInterruptEnable|hdsp_encode_latency(7)); hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); hdsp->passthru = 1; } else { hdsp_set_thru(hdsp, -1, 0); hdsp_stop_audio(hdsp); hdsp->passthru = 0; } return 0;}/*---------------------------------------------------------------------------- MIDI ----------------------------------------------------------------------------*/static inline unsigned char snd_hdsp_midi_read_byte (hdsp_t *hdsp, int id){ /* the hardware already does the relevant bit-mask with 0xff */ if (id) { return hdsp_read(hdsp, HDSP_midiDataIn1); } else { return hdsp_read(hdsp, HDSP_midiDataIn0); }}static inline void snd_hdsp_midi_write_byte (hdsp_t *hdsp, int id, int val){ /* the hardware already does the relevant bit-mask with 0xff */ if (id) { hdsp_write(hdsp, HDSP_midiDataOut1, val); } else { hdsp_write(hdsp, HDSP_midiDataOut0, val); }}static inline int snd_hdsp_midi_input_available (hdsp_t *hdsp, int id){ if (id) { return (hdsp_read(hdsp, HDSP_midiStatusIn1) & 0xff); } else { return (hdsp_read(hdsp, HDSP_midiStatusIn0) & 0xff); }}static inline int snd_hdsp_midi_output_possible (hdsp_t *hdsp, int id){ int fifo_bytes_used; if (id) { fifo_bytes_used = hdsp_read(hdsp, HDSP_midiStatusOut1) & 0xff; } else { fifo_bytes_used = hdsp_read(hdsp, HDSP_midiStatusOut0) & 0xff; } if (fifo_bytes_used < 128) { return 128 - fifo_bytes_used; } else { return 0; }}static inline void snd_hdsp_flush_midi_input (hdsp_t *hdsp, int id){ while (snd_hdsp_midi_input_available (hdsp, id)) { snd_hdsp_midi_read_byte (hdsp, id); }}static int snd_hdsp_midi_output_write (hdsp_midi_t *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) { if (!snd_rawmidi_transmit_empty (hmidi->output)) { if ((n_pending = snd_hdsp_midi_output_possible (hmidi->hdsp, hmidi->id)) > 0) { if (n_pending > (int)sizeof (buf)) n_pending = sizeof (buf); if ((to_write = snd_rawmidi_transmit (hmidi->output, buf, n_pending)) > 0) { for (i = 0; i < to_write; ++i) snd_hdsp_midi_write_byte (hmidi->hdsp, hmidi->id, buf[i]); } } } } spin_unlock_irqrestore (&hmidi->lock, flags); return 0;}static int snd_hdsp_midi_input_read (hdsp_midi_t *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); if ((n_pending = snd_hdsp_midi_input_available (hmidi->hdsp, hmidi->id)) > 0) { if (hmidi->input) { if (n_pending > (int)sizeof (buf)) { n_pending = sizeof (buf); } for (i = 0; i < n_pending; ++i) { buf[i] = snd_hdsp_midi_read_byte (hmidi->hdsp, hmidi->id); } if (n_pending) { snd_rawmidi_receive (hmidi->input, buf, n_pending); } } else { /* flush the MIDI input FIFO */ while (--n_pending) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -