📄 hdsp.c
字号:
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 ("Hammerfall-DSP: unknown spdif frequency status; bits = 0x%x, status = 0x%x\n", rate_bits, status); return 0;}static 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 &= (hdsp->period_bytes/2) - 1; return position;}static void hdsp_reset_hw_pointer(hdsp_t *hdsp){ hdsp_write (hdsp, HDSP_resetPointer, 0);}static void hdsp_start_audio(hdsp_t *s){ s->control_register |= (HDSP_AudioInterruptEnable | HDSP_Start); hdsp_write(s, HDSP_controlRegister, s->control_register);}static void hdsp_stop_audio(hdsp_t *s){ s->control_register &= ~(HDSP_Start | HDSP_AudioInterruptEnable); hdsp_write(s, HDSP_controlRegister, s->control_register);}static 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(KERN_ERR "Hammerfall-DSP: 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(KERN_INFO "Hammerfall-DSP: 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(KERN_INFO "Hammerfall-DSP: Detected ADAT in quad speed mode\n"); else if (rate != external_freq) { snd_printk(KERN_INFO "Hammerfall-DSP: 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 ("Hammerfall-DSP: 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;}/*---------------------------------------------------------------------------- MIDI ----------------------------------------------------------------------------*/static 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 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 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 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 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) snd_hdsp_midi_read_byte (hmidi->hdsp, hmidi->id); } } hmidi->pending = 0; if (hmidi->id) hmidi->hdsp->control_register |= HDSP_Midi1InterruptEnable; else hmidi->hdsp->control_register |= HDSP_Midi0InterruptEnable; hdsp_write(hmidi->hdsp, HDSP_controlRegister, hmidi->hdsp->control_register); spin_unlock_irqrestore (&hmidi->lock, flags); return snd_hdsp_midi_output_write (hmidi);}static void snd_hdsp_midi_input_trigger(snd_rawmidi_substream_t * substream, int up){ hdsp_t *hdsp; hdsp_midi_t *hmidi; unsigned long flags; u32 ie; hmidi = (hdsp_midi_t *) substream->rmidi->private_data; hdsp = hmidi->hdsp; ie = hmidi->id ? HDSP_Midi1InterruptEnable : HDSP_Midi0InterruptEnable; spin_lock_irqsave (&hdsp->lock, flags); if (up) { if (!(hdsp->control_register & ie)) { snd_hdsp_flush_midi_input (hdsp, hmidi->id); hdsp->control_register |= ie; } } else { hdsp->control_register &= ~ie; tasklet_kill(&hdsp->midi_tasklet); } hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); spin_unlock_irqrestore (&hdsp->lock, flags);}static void snd_hdsp_midi_output_timer(unsigned long data){ hdsp_midi_t *hmidi = (hdsp_midi_t *) data; unsigned long flags; snd_hdsp_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 void snd_hdsp_midi_output_trigger(snd_rawmidi_substream_t * substream, int up){ hdsp_midi_t *hmidi; unsigned long flags; hmidi = (hdsp_midi_t *) substream->rmidi->private_data; spin_lock_irqsave (&hmidi->lock, flags); if (up) { if (!hmidi->istimer) { init_timer(&hmidi->timer); hmidi->timer.function = snd_hdsp_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_hdsp_midi_output_write(hmidi);}static int snd_hdsp_midi_input_open(snd_rawmidi_substream_t * substream){ hdsp_midi_t *hmidi; hmidi = (hdsp_midi_t *) substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); snd_hdsp_flush_midi_input (hmidi->hdsp, hmidi->id); hmidi->input = substream; spin_unlock_irq (&hmidi->lock); return 0;}static int snd_hdsp_midi_output_open(snd_rawmidi_substream_t * substream){ hdsp_midi_t *hmidi; hmidi = (hdsp_midi_t *) substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); hmidi->output = substream; spin_unlock_irq (&hmidi->lock); return 0;}static int snd_hdsp_midi_input_close(snd_rawmidi_substream_t * substream){ hdsp_midi_t *hmidi; snd_hdsp_midi_input_trigger (substream, 0); hmidi = (hdsp_midi_t *) substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); hmidi->input = NULL; spin_unlock_irq (&hmidi->lock); return 0;}static int snd_hdsp_midi_output_close(snd_rawmidi_substream_t * substream){ hdsp_midi_t *hmidi;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -