📄 hdspm.c
字号:
{ return readl(hdspm->iobase + reg);}/* for each output channel (chan) I have an Input (in) and Playback (pb) Fader mixer is write only on hardware so we have to cache him for read each fader is a u32, but uses only the first 16 bit */static inline int hdspm_read_in_gain(struct hdspm * hdspm, unsigned int chan, unsigned int in){ if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS) return 0; return hdspm->mixer->ch[chan].in[in];}static inline int hdspm_read_pb_gain(struct hdspm * hdspm, unsigned int chan, unsigned int pb){ if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS) return 0; return hdspm->mixer->ch[chan].pb[pb];}static inline int hdspm_write_in_gain(struct hdspm * hdspm, unsigned int chan, unsigned int in, unsigned short data){ if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS) return -1; hdspm_write(hdspm, HDSPM_MADI_mixerBase + ((in + 128 * chan) * sizeof(u32)), (hdspm->mixer->ch[chan].in[in] = data & 0xFFFF)); return 0;}static inline int hdspm_write_pb_gain(struct hdspm * hdspm, unsigned int chan, unsigned int pb, unsigned short data){ if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS) return -1; hdspm_write(hdspm, HDSPM_MADI_mixerBase + ((64 + pb + 128 * chan) * sizeof(u32)), (hdspm->mixer->ch[chan].pb[pb] = data & 0xFFFF)); return 0;}/* enable DMA for specific channels, now available for DSP-MADI */static inline void snd_hdspm_enable_in(struct hdspm * hdspm, int i, int v){ hdspm_write(hdspm, HDSPM_inputEnableBase + (4 * i), v);}static inline void snd_hdspm_enable_out(struct hdspm * hdspm, int i, int v){ hdspm_write(hdspm, HDSPM_outputEnableBase + (4 * i), v);}/* check if same process is writing and reading */static inline int snd_hdspm_use_is_exclusive(struct hdspm * hdspm){ unsigned long flags; int ret = 1; spin_lock_irqsave(&hdspm->lock, flags); if ((hdspm->playback_pid != hdspm->capture_pid) && (hdspm->playback_pid >= 0) && (hdspm->capture_pid >= 0)) { ret = 0; } spin_unlock_irqrestore(&hdspm->lock, flags); return ret;}/* check for external sample rate */static inline int hdspm_external_sample_rate(struct hdspm * hdspm){ unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); unsigned int rate_bits; int rate = 0; /* if wordclock has synced freq and wordclock is valid */ if ((status2 & HDSPM_wcLock) != 0 && (status & HDSPM_SelSyncRef0) == 0) { rate_bits = status2 & HDSPM_wcFreqMask; switch (rate_bits) { case HDSPM_wcFreq32: rate = 32000; break; case HDSPM_wcFreq44_1: rate = 44100; break; case HDSPM_wcFreq48: rate = 48000; break; case HDSPM_wcFreq64: rate = 64000; break; case HDSPM_wcFreq88_2: rate = 88200; break; case HDSPM_wcFreq96: rate = 96000; break; /* Quadspeed Bit missing ???? */ default: rate = 0; break; } } /* if rate detected and Syncref is Word than have it, word has priority to MADI */ if (rate != 0 && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) return rate; /* maby a madi input (which is taken if sel sync is madi) */ if (status & HDSPM_madiLock) { rate_bits = status & HDSPM_madiFreqMask; switch (rate_bits) { case HDSPM_madiFreq32: rate = 32000; break; case HDSPM_madiFreq44_1: rate = 44100; break; case HDSPM_madiFreq48: rate = 48000; break; case HDSPM_madiFreq64: rate = 64000; break; case HDSPM_madiFreq88_2: rate = 88200; break; case HDSPM_madiFreq96: rate = 96000; break; case HDSPM_madiFreq128: rate = 128000; break; case HDSPM_madiFreq176_4: rate = 176400; break; case HDSPM_madiFreq192: rate = 192000; break; default: rate = 0; break; } } return rate;}/* Latency function */static inline void hdspm_compute_period_size(struct hdspm * hdspm){ hdspm->period_bytes = 1 << ((hdspm_decode_latency(hdspm->control_register) + 8));}static snd_pcm_uframes_t hdspm_hw_pointer(struct hdspm * hdspm){ int position; position = hdspm_read(hdspm, HDSPM_statusRegister); if (!hdspm->precise_ptr) { return (position & HDSPM_BufferID) ? (hdspm->period_bytes / 4) : 0; } /* hwpointer comes in bytes and is 64Bytes accurate (by docu since PCI Burst) i have experimented that it is at most 64 Byte to much for playing so substraction of 64 byte should be ok for ALSA, but use it only for application where you know what you do since if you come to near with record pointer it can be a disaster */ position &= HDSPM_BufferPositionMask; position = ((position - 64) % (2 * hdspm->period_bytes)) / 4; return position;}static inline void hdspm_start_audio(struct hdspm * s){ s->control_register |= (HDSPM_AudioInterruptEnable | HDSPM_Start); hdspm_write(s, HDSPM_controlRegister, s->control_register);}static inline void hdspm_stop_audio(struct hdspm * s){ s->control_register &= ~(HDSPM_Start | HDSPM_AudioInterruptEnable); hdspm_write(s, HDSPM_controlRegister, s->control_register);}/* should I silence all or only opened ones ? doit all for first even is 4MB*/static inline void hdspm_silence_playback(struct hdspm * hdspm){ int i; int n = hdspm->period_bytes; void *buf = hdspm->playback_buffer; snd_assert(buf != NULL, return); for (i = 0; i < HDSPM_MAX_CHANNELS; i++) { memset(buf, 0, n); buf += HDSPM_CHANNEL_BUFFER_BYTES; }}static int hdspm_set_interrupt_interval(struct hdspm * s, unsigned int frames){ int n; spin_lock_irq(&s->lock); frames >>= 7; n = 0; while (frames) { n++; frames >>= 1; } s->control_register &= ~HDSPM_LatencyMask; s->control_register |= hdspm_encode_latency(n); hdspm_write(s, HDSPM_controlRegister, s->control_register); hdspm_compute_period_size(s); spin_unlock_irq(&s->lock); return 0;}/* dummy set rate lets see what happens */static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally){ int reject_if_open = 0; int current_rate; int rate_bits; int not_set = 0; /* ASSUMPTION: hdspm->lock is either set, or there is no need for it (e.g. during module initialization). */ if (!(hdspm->control_register & HDSPM_ClockModeMaster)) { /* SLAVE --- */ if (called_internally) { /* request from ctl or card initialization just make a warning an remember setting for future master mode switching */ snd_printk (KERN_WARNING "HDSPM: Warning: device is not running as a clock master.\n"); not_set = 1; } else { /* hw_param request while in AutoSync mode */ int external_freq = hdspm_external_sample_rate(hdspm); if ((hdspm_autosync_ref(hdspm) == HDSPM_AUTOSYNC_FROM_NONE)) { snd_printk(KERN_WARNING "HDSPM: Detected no Externel Sync \n"); not_set = 1; } else if (rate != external_freq) { snd_printk (KERN_WARNING "HDSPM: Warning: No AutoSync source for requested rate\n"); not_set = 1; } } } current_rate = hdspm->system_sample_rate; /* Changing between Singe, Double and Quad speed 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. */ switch (rate) { case 32000: if (current_rate > 48000) { reject_if_open = 1; } rate_bits = HDSPM_Frequency32KHz; break; case 44100: if (current_rate > 48000) { reject_if_open = 1; } rate_bits = HDSPM_Frequency44_1KHz; break; case 48000: if (current_rate > 48000) { reject_if_open = 1; } rate_bits = HDSPM_Frequency48KHz; break; case 64000: if (current_rate <= 48000) { reject_if_open = 1; } rate_bits = HDSPM_Frequency64KHz; break; case 88200: if (current_rate <= 48000) { reject_if_open = 1; } rate_bits = HDSPM_Frequency88_2KHz; break; case 96000: if (current_rate <= 48000) { reject_if_open = 1; } rate_bits = HDSPM_Frequency96KHz; break; default: return -EINVAL; } if (reject_if_open && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) { snd_printk (KERN_ERR "HDSPM: cannot change between single- and double-speed mode (capture PID = %d, playback PID = %d)\n", 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); if (rate > 64000) hdspm->channel_map = channel_map_madi_qs; else if (rate > 48000) hdspm->channel_map = channel_map_madi_ds; else 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 = (sgain > UNITY_GAIN) ? UNITY_GAIN : (sgain < 0) ? 0 : 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) & 0xff; else fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut0) & 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) { if (!snd_rawmidi_transmit_empty (hmidi->output)) { if ((n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, 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_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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -