📄 hdspm.c
字号:
pid_t capture_pid; /* process id which uses capture */ pid_t playback_pid; /* process id which uses capture */ int running; /* running status */ int last_external_sample_rate; /* samplerate mystic ... */ int last_internal_sample_rate; int system_sample_rate; char *channel_map; /* channel map for DS and Quadspeed */ int dev; /* Hardware vars... */ int irq; unsigned long port; void __iomem *iobase; int irq_count; /* for debug */ struct snd_card *card; /* one card */ struct snd_pcm *pcm; /* has one pcm */ struct snd_hwdep *hwdep; /* and a hwdep for additional ioctl */ struct pci_dev *pci; /* and an pci info */ /* Mixer vars */ /* fast alsa mixer */ struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; /* but input to much, so not used */ struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS]; /* full mixer accessable over mixer ioctl or hwdep-device */ struct hdspm_mixer *mixer;};/* These tables map the ALSA channels 1..N to the channels that we need to use in order to find the relevant channel buffer. RME refer to this kind of mapping as between "the ADAT channel and the DMA channel." We index it using the logical audio channel, and the value is the DMA channel (i.e. channel buffer number) where the data for that channel can be read/written from/to.*/static char channel_map_madi_ss[HDSPM_MAX_CHANNELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};static struct pci_device_id snd_hdspm_ids[] __devinitdata = { { .vendor = PCI_VENDOR_ID_XILINX, .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .class = 0, .class_mask = 0, .driver_data = 0}, {0,}};MODULE_DEVICE_TABLE(pci, snd_hdspm_ids);/* prototypes */static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card, struct hdspm * hdspm);static int __devinit snd_hdspm_create_pcm(struct snd_card *card, struct hdspm * hdspm);static inline void snd_hdspm_initialize_midi_flush(struct hdspm * hdspm);static int hdspm_update_simple_mixer_controls(struct hdspm * hdspm);static int hdspm_autosync_ref(struct hdspm * hdspm);static int snd_hdspm_set_defaults(struct hdspm * hdspm);static void hdspm_set_sgbuf(struct hdspm * hdspm, struct snd_sg_buf *sgbuf, unsigned int reg, int channels);static inline int HDSPM_bit2freq(int n){ static int bit2freq_tab[] = { 0, 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 }; if (n < 1 || n > 9) return 0; return bit2freq_tab[n];}/* Write/read to/from HDSPM with Adresses in Bytes not words but only 32Bit writes are allowed */static inline void hdspm_write(struct hdspm * hdspm, unsigned int reg, unsigned int val){ writel(val, hdspm->iobase + reg);}static inline unsigned int hdspm_read(struct hdspm * hdspm, unsigned int reg){ 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){ if (hdspm->is_aes32) { unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); unsigned int timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); int syncref = hdspm_autosync_ref(hdspm); if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD && status & HDSPM_AES32_wcLock) return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF); if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 && syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 && status2 & (HDSPM_LockAES >> (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1))) return HDSPM_bit2freq((timecode >> (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF); return 0; } else { 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; if (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;}static void hdspm_set_dds_value(struct hdspm *hdspm, int rate){ u64 n; u32 r; if (rate >= 112000) rate /= 4; else if (rate >= 56000) rate /= 2; /* RME says n = 104857600000000, but in the windows MADI driver, I see:// return 104857600000000 / rate; // 100 MHz return 110100480000000 / rate; // 105 MHz */ /* n = 104857600000000ULL; */ /* = 2^20 * 10^8 */ n = 110100480000000ULL; /* Value checked for AES32 and MADI */ div64_32(&n, rate, &r); /* n should be less than 2^32 for being written to FREQ register */ snd_assert((n >> 32) == 0); hdspm_write(hdspm, HDSPM_freqReg, (u32)n);}/* dummy set rate lets see what happens */static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally){ int current_rate; int rate_bits; int not_set = 0; int current_speed, target_speed; /* 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. */ if (current_rate <= 48000) current_speed = HDSPM_SPEED_SINGLE; else if (current_rate <= 96000) current_speed = HDSPM_SPEED_DOUBLE; else current_speed = HDSPM_SPEED_QUAD; if (rate <= 48000) target_speed = HDSPM_SPEED_SINGLE; else if (rate <= 96000) target_speed = HDSPM_SPEED_DOUBLE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -