diff options
Diffstat (limited to 'sound/firewire/motu/amdtp-motu.c')
-rw-r--r-- | sound/firewire/motu/amdtp-motu.c | 199 |
1 files changed, 99 insertions, 100 deletions
diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c index edb31ac26868..39ed57d2c5a0 100644 --- a/sound/firewire/motu/amdtp-motu.c +++ b/sound/firewire/motu/amdtp-motu.c @@ -16,6 +16,14 @@ #define CIP_FMT_MOTU_TX_V3 0x22 #define MOTU_FDF_AM824 0x22 +#define TICKS_PER_CYCLE 3072 +#define CYCLES_PER_SECOND 8000 +#define TICKS_PER_SECOND (TICKS_PER_CYCLE * CYCLES_PER_SECOND) + +#define CIP_SPH_CYCLE_SHIFT 12 +#define CIP_SPH_CYCLE_MASK 0x01fff000 +#define CIP_SPH_OFFSET_MASK 0x00000fff + /* * Nominally 3125 bytes/second, but the MIDI port's clock might be * 1% too slow, and the bus clock 100 ppm too fast. @@ -23,14 +31,6 @@ #define MIDI_BYTES_PER_SECOND 3093 struct amdtp_motu { - /* For timestamp processing. */ - unsigned int quotient_ticks_per_event; - unsigned int remainder_ticks_per_event; - unsigned int next_ticks; - unsigned int next_accumulated; - unsigned int next_cycles; - unsigned int next_seconds; - unsigned int pcm_chunks; unsigned int pcm_byte_offset; @@ -41,26 +41,16 @@ struct amdtp_motu { int midi_db_count; unsigned int midi_db_interval; + + struct amdtp_motu_cache *cache; }; int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate, unsigned int midi_ports, struct snd_motu_packet_format *formats) { - static const struct { - unsigned int quotient_ticks_per_event; - unsigned int remainder_ticks_per_event; - } params[] = { - [CIP_SFC_44100] = { 557, 123 }, - [CIP_SFC_48000] = { 512, 0 }, - [CIP_SFC_88200] = { 278, 282 }, - [CIP_SFC_96000] = { 256, 0 }, - [CIP_SFC_176400] = { 139, 141 }, - [CIP_SFC_192000] = { 128, 0 }, - }; struct amdtp_motu *p = s->protocol; unsigned int pcm_chunks, data_chunks, data_block_quadlets; - unsigned int delay; unsigned int mode; int i, err; @@ -83,7 +73,7 @@ int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate, data_chunks = formats->msg_chunks + pcm_chunks; data_block_quadlets = 1 + DIV_ROUND_UP(data_chunks * 3, 4); - err = amdtp_stream_set_parameters(s, rate, data_block_quadlets); + err = amdtp_stream_set_parameters(s, rate, data_block_quadlets, 1); if (err < 0) return err; @@ -97,19 +87,6 @@ int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate, p->midi_db_count = 0; p->midi_db_interval = rate / MIDI_BYTES_PER_SECOND; - /* IEEE 1394 bus requires. */ - delay = 0x2e00; - - /* For no-data or empty packets to adjust PCM sampling frequency. */ - delay += 8000 * 3072 * s->syt_interval / rate; - - p->next_seconds = 0; - p->next_cycles = delay / 3072; - p->quotient_ticks_per_event = params[s->sfc].quotient_ticks_per_event; - p->remainder_ticks_per_event = params[s->sfc].remainder_ticks_per_event; - p->next_ticks = delay % 3072; - p->next_accumulated = 0; - return 0; } @@ -299,44 +276,77 @@ static void __maybe_unused copy_message(u64 *frames, __be32 *buffer, /* This is just for v2/v3 protocol. */ for (i = 0; i < data_blocks; ++i) { - *frames = (be32_to_cpu(buffer[1]) << 16) | - (be32_to_cpu(buffer[2]) >> 16); + *frames = be32_to_cpu(buffer[1]); + *frames <<= 16; + *frames |= be32_to_cpu(buffer[2]) >> 16; + ++frames; buffer += data_block_quadlets; - frames++; } } -static void probe_tracepoints_events(struct amdtp_stream *s, - const struct pkt_desc *descs, - unsigned int packets) +static void probe_tracepoints_events(struct amdtp_stream *s, const struct pkt_desc *desc, + unsigned int count) { int i; - for (i = 0; i < packets; ++i) { - const struct pkt_desc *desc = descs + i; + for (i = 0; i < count; ++i) { __be32 *buf = desc->ctx_payload; unsigned int data_blocks = desc->data_blocks; trace_data_block_sph(s, data_blocks, buf); trace_data_block_message(s, data_blocks, buf); + + desc = amdtp_stream_next_packet_desc(s, desc); } } -static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, - const struct pkt_desc *descs, - unsigned int packets, - struct snd_pcm_substream *pcm) +static void cache_event_offsets(struct amdtp_motu_cache *cache, const __be32 *buf, + unsigned int data_blocks, unsigned int data_block_quadlets) { + unsigned int *event_offsets = cache->event_offsets; + const unsigned int cache_size = cache->size; + unsigned int cache_tail = cache->tail; + unsigned int base_tick = cache->tx_cycle_count * TICKS_PER_CYCLE; + int i; + + for (i = 0; i < data_blocks; ++i) { + u32 sph = be32_to_cpu(*buf); + unsigned int tick; + + tick = ((sph & CIP_SPH_CYCLE_MASK) >> CIP_SPH_CYCLE_SHIFT) * TICKS_PER_CYCLE + + (sph & CIP_SPH_OFFSET_MASK); + + if (tick < base_tick) + tick += TICKS_PER_SECOND; + event_offsets[cache_tail] = tick - base_tick; + + cache_tail = (cache_tail + 1) % cache_size; + buf += data_block_quadlets; + } + + cache->tail = cache_tail; + cache->tx_cycle_count = (cache->tx_cycle_count + 1) % CYCLES_PER_SECOND; +} + +static void process_ir_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *desc, + unsigned int count, struct snd_pcm_substream *pcm) +{ + struct snd_motu *motu = container_of(s, struct snd_motu, tx_stream); struct amdtp_motu *p = s->protocol; + const struct pkt_desc *cursor = desc; unsigned int pcm_frames = 0; int i; + if (p->cache->tx_cycle_count == UINT_MAX) + p->cache->tx_cycle_count = (s->domain->processing_cycle.tx_start % CYCLES_PER_SECOND); + // For data block processing. - for (i = 0; i < packets; ++i) { - const struct pkt_desc *desc = descs + i; + for (i = 0; i < count; ++i) { __be32 *buf = desc->ctx_payload; unsigned int data_blocks = desc->data_blocks; + cache_event_offsets(p->cache, buf, data_blocks, s->data_block_quadlets); + if (pcm) { read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames); pcm_frames += data_blocks; @@ -344,70 +354,57 @@ static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s, if (p->midi_ports) read_midi_messages(s, buf, data_blocks); + + desc = amdtp_stream_next_packet_desc(s, desc); } + desc = cursor; + if (motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP) + snd_motu_register_dsp_message_parser_parse(s, desc, count); + else if (motu->spec->flags & SND_MOTU_SPEC_COMMAND_DSP) + snd_motu_command_dsp_message_parser_parse(s, desc, count); + // For tracepoints. if (trace_data_block_sph_enabled() || trace_data_block_message_enabled()) - probe_tracepoints_events(s, descs, packets); - - return pcm_frames; -} - -static inline void compute_next_elapse_from_start(struct amdtp_motu *p) -{ - p->next_accumulated += p->remainder_ticks_per_event; - if (p->next_accumulated >= 441) { - p->next_accumulated -= 441; - p->next_ticks++; - } - - p->next_ticks += p->quotient_ticks_per_event; - if (p->next_ticks >= 3072) { - p->next_ticks -= 3072; - p->next_cycles++; - } - - if (p->next_cycles >= 8000) { - p->next_cycles -= 8000; - p->next_seconds++; - } - - if (p->next_seconds >= 128) - p->next_seconds -= 128; + probe_tracepoints_events(s, desc, count); } -static void write_sph(struct amdtp_stream *s, __be32 *buffer, - unsigned int data_blocks) +static void write_sph(struct amdtp_motu_cache *cache, __be32 *buffer, unsigned int data_blocks, + unsigned int data_block_quadlets) { - struct amdtp_motu *p = s->protocol; - unsigned int next_cycles; - unsigned int i; - u32 sph; + unsigned int *event_offsets = cache->event_offsets; + const unsigned int cache_size = cache->size; + unsigned int cache_head = cache->head; + unsigned int base_tick = cache->rx_cycle_count * TICKS_PER_CYCLE; + int i; for (i = 0; i < data_blocks; i++) { - next_cycles = (s->start_cycle + p->next_cycles) % 8000; - sph = ((next_cycles << 12) | p->next_ticks) & 0x01ffffff; + unsigned int tick = (base_tick + event_offsets[cache_head]) % TICKS_PER_SECOND; + u32 sph = ((tick / TICKS_PER_CYCLE) << CIP_SPH_CYCLE_SHIFT) | (tick % TICKS_PER_CYCLE); *buffer = cpu_to_be32(sph); - compute_next_elapse_from_start(p); - - buffer += s->data_block_quadlets; + cache_head = (cache_head + 1) % cache_size; + buffer += data_block_quadlets; } + + cache->head = cache_head; + cache->rx_cycle_count = (cache->rx_cycle_count + 1) % CYCLES_PER_SECOND; } -static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, - const struct pkt_desc *descs, - unsigned int packets, - struct snd_pcm_substream *pcm) +static void process_it_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *desc, + unsigned int count, struct snd_pcm_substream *pcm) { struct amdtp_motu *p = s->protocol; + const struct pkt_desc *cursor = desc; unsigned int pcm_frames = 0; int i; + if (p->cache->rx_cycle_count == UINT_MAX) + p->cache->rx_cycle_count = (s->domain->processing_cycle.rx_start % CYCLES_PER_SECOND); + // For data block processing. - for (i = 0; i < packets; ++i) { - const struct pkt_desc *desc = descs + i; + for (i = 0; i < count; ++i) { __be32 *buf = desc->ctx_payload; unsigned int data_blocks = desc->data_blocks; @@ -421,26 +418,27 @@ static unsigned int process_it_ctx_payloads(struct amdtp_stream *s, if (p->midi_ports) write_midi_messages(s, buf, data_blocks); - // TODO: how to interact control messages between userspace? + write_sph(p->cache, buf, data_blocks, s->data_block_quadlets); - write_sph(s, buf, data_blocks); + desc = amdtp_stream_next_packet_desc(s, desc); } + desc = cursor; + // For tracepoints. if (trace_data_block_sph_enabled() || trace_data_block_message_enabled()) - probe_tracepoints_events(s, descs, packets); - - return pcm_frames; + probe_tracepoints_events(s, desc, count); } int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, enum amdtp_stream_direction dir, - const struct snd_motu_spec *spec) + const struct snd_motu_spec *spec, struct amdtp_motu_cache *cache) { amdtp_stream_process_ctx_payloads_t process_ctx_payloads; int fmt = CIP_FMT_MOTU; - int flags = CIP_BLOCKING; + unsigned int flags = CIP_BLOCKING | CIP_UNAWARE_SYT; + struct amdtp_motu *p; int err; if (dir == AMDTP_IN_STREAM) { @@ -478,9 +476,10 @@ int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, if (dir == AMDTP_OUT_STREAM) { // Use fixed value for FDF field. s->ctx_data.rx.fdf = MOTU_FDF_AM824; - // Not used. - s->ctx_data.rx.syt_override = 0xffff; } + p = s->protocol; + p->cache = cache; + return 0; } |