18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * amdtp-motu.c - a part of driver for MOTU FireWire series
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/slab.h>
98c2ecf20Sopenharmony_ci#include <sound/pcm.h>
108c2ecf20Sopenharmony_ci#include "motu.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS
138c2ecf20Sopenharmony_ci#include "amdtp-motu-trace.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define CIP_FMT_MOTU		0x02
168c2ecf20Sopenharmony_ci#define CIP_FMT_MOTU_TX_V3	0x22
178c2ecf20Sopenharmony_ci#define MOTU_FDF_AM824		0x22
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * Nominally 3125 bytes/second, but the MIDI port's clock might be
218c2ecf20Sopenharmony_ci * 1% too slow, and the bus clock 100 ppm too fast.
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ci#define MIDI_BYTES_PER_SECOND	3093
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistruct amdtp_motu {
268c2ecf20Sopenharmony_ci	/* For timestamp processing.  */
278c2ecf20Sopenharmony_ci	unsigned int quotient_ticks_per_event;
288c2ecf20Sopenharmony_ci	unsigned int remainder_ticks_per_event;
298c2ecf20Sopenharmony_ci	unsigned int next_ticks;
308c2ecf20Sopenharmony_ci	unsigned int next_accumulated;
318c2ecf20Sopenharmony_ci	unsigned int next_cycles;
328c2ecf20Sopenharmony_ci	unsigned int next_seconds;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	unsigned int pcm_chunks;
358c2ecf20Sopenharmony_ci	unsigned int pcm_byte_offset;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	struct snd_rawmidi_substream *midi;
388c2ecf20Sopenharmony_ci	unsigned int midi_ports;
398c2ecf20Sopenharmony_ci	unsigned int midi_flag_offset;
408c2ecf20Sopenharmony_ci	unsigned int midi_byte_offset;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	int midi_db_count;
438c2ecf20Sopenharmony_ci	unsigned int midi_db_interval;
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ciint amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate,
478c2ecf20Sopenharmony_ci			      unsigned int midi_ports,
488c2ecf20Sopenharmony_ci			      struct snd_motu_packet_format *formats)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	static const struct {
518c2ecf20Sopenharmony_ci		unsigned int quotient_ticks_per_event;
528c2ecf20Sopenharmony_ci		unsigned int remainder_ticks_per_event;
538c2ecf20Sopenharmony_ci	} params[] = {
548c2ecf20Sopenharmony_ci		[CIP_SFC_44100]  = { 557, 123 },
558c2ecf20Sopenharmony_ci		[CIP_SFC_48000]  = { 512,   0 },
568c2ecf20Sopenharmony_ci		[CIP_SFC_88200]  = { 278, 282 },
578c2ecf20Sopenharmony_ci		[CIP_SFC_96000]  = { 256,   0 },
588c2ecf20Sopenharmony_ci		[CIP_SFC_176400] = { 139, 141 },
598c2ecf20Sopenharmony_ci		[CIP_SFC_192000] = { 128,   0 },
608c2ecf20Sopenharmony_ci	};
618c2ecf20Sopenharmony_ci	struct amdtp_motu *p = s->protocol;
628c2ecf20Sopenharmony_ci	unsigned int pcm_chunks, data_chunks, data_block_quadlets;
638c2ecf20Sopenharmony_ci	unsigned int delay;
648c2ecf20Sopenharmony_ci	unsigned int mode;
658c2ecf20Sopenharmony_ci	int i, err;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (amdtp_stream_running(s))
688c2ecf20Sopenharmony_ci		return -EBUSY;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
718c2ecf20Sopenharmony_ci		if (snd_motu_clock_rates[i] == rate) {
728c2ecf20Sopenharmony_ci			mode = i >> 1;
738c2ecf20Sopenharmony_ci			break;
748c2ecf20Sopenharmony_ci		}
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci	if (i == ARRAY_SIZE(snd_motu_clock_rates))
778c2ecf20Sopenharmony_ci		return -EINVAL;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	// Each data block includes SPH in its head. Data chunks follow with
808c2ecf20Sopenharmony_ci	// 3 byte alignment. Padding follows with zero to conform to quadlet
818c2ecf20Sopenharmony_ci	// alignment.
828c2ecf20Sopenharmony_ci	pcm_chunks = formats->pcm_chunks[mode];
838c2ecf20Sopenharmony_ci	data_chunks = formats->msg_chunks + pcm_chunks;
848c2ecf20Sopenharmony_ci	data_block_quadlets = 1 + DIV_ROUND_UP(data_chunks * 3, 4);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	err = amdtp_stream_set_parameters(s, rate, data_block_quadlets);
878c2ecf20Sopenharmony_ci	if (err < 0)
888c2ecf20Sopenharmony_ci		return err;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	p->pcm_chunks = pcm_chunks;
918c2ecf20Sopenharmony_ci	p->pcm_byte_offset = formats->pcm_byte_offset;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	p->midi_ports = midi_ports;
948c2ecf20Sopenharmony_ci	p->midi_flag_offset = formats->midi_flag_offset;
958c2ecf20Sopenharmony_ci	p->midi_byte_offset = formats->midi_byte_offset;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	p->midi_db_count = 0;
988c2ecf20Sopenharmony_ci	p->midi_db_interval = rate / MIDI_BYTES_PER_SECOND;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	/* IEEE 1394 bus requires. */
1018c2ecf20Sopenharmony_ci	delay = 0x2e00;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	/* For no-data or empty packets to adjust PCM sampling frequency. */
1048c2ecf20Sopenharmony_ci	delay += 8000 * 3072 * s->syt_interval / rate;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	p->next_seconds = 0;
1078c2ecf20Sopenharmony_ci	p->next_cycles = delay / 3072;
1088c2ecf20Sopenharmony_ci	p->quotient_ticks_per_event = params[s->sfc].quotient_ticks_per_event;
1098c2ecf20Sopenharmony_ci	p->remainder_ticks_per_event = params[s->sfc].remainder_ticks_per_event;
1108c2ecf20Sopenharmony_ci	p->next_ticks = delay % 3072;
1118c2ecf20Sopenharmony_ci	p->next_accumulated = 0;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return 0;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
1178c2ecf20Sopenharmony_ci			 __be32 *buffer, unsigned int data_blocks,
1188c2ecf20Sopenharmony_ci			 unsigned int pcm_frames)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	struct amdtp_motu *p = s->protocol;
1218c2ecf20Sopenharmony_ci	unsigned int channels = p->pcm_chunks;
1228c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = pcm->runtime;
1238c2ecf20Sopenharmony_ci	unsigned int pcm_buffer_pointer;
1248c2ecf20Sopenharmony_ci	int remaining_frames;
1258c2ecf20Sopenharmony_ci	u8 *byte;
1268c2ecf20Sopenharmony_ci	u32 *dst;
1278c2ecf20Sopenharmony_ci	int i, c;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames;
1308c2ecf20Sopenharmony_ci	pcm_buffer_pointer %= runtime->buffer_size;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	dst = (void *)runtime->dma_area +
1338c2ecf20Sopenharmony_ci				frames_to_bytes(runtime, pcm_buffer_pointer);
1348c2ecf20Sopenharmony_ci	remaining_frames = runtime->buffer_size - pcm_buffer_pointer;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	for (i = 0; i < data_blocks; ++i) {
1378c2ecf20Sopenharmony_ci		byte = (u8 *)buffer + p->pcm_byte_offset;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci		for (c = 0; c < channels; ++c) {
1408c2ecf20Sopenharmony_ci			*dst = (byte[0] << 24) |
1418c2ecf20Sopenharmony_ci			       (byte[1] << 16) |
1428c2ecf20Sopenharmony_ci			       (byte[2] << 8);
1438c2ecf20Sopenharmony_ci			byte += 3;
1448c2ecf20Sopenharmony_ci			dst++;
1458c2ecf20Sopenharmony_ci		}
1468c2ecf20Sopenharmony_ci		buffer += s->data_block_quadlets;
1478c2ecf20Sopenharmony_ci		if (--remaining_frames == 0)
1488c2ecf20Sopenharmony_ci			dst = (void *)runtime->dma_area;
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
1538c2ecf20Sopenharmony_ci			  __be32 *buffer, unsigned int data_blocks,
1548c2ecf20Sopenharmony_ci			  unsigned int pcm_frames)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	struct amdtp_motu *p = s->protocol;
1578c2ecf20Sopenharmony_ci	unsigned int channels = p->pcm_chunks;
1588c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = pcm->runtime;
1598c2ecf20Sopenharmony_ci	unsigned int pcm_buffer_pointer;
1608c2ecf20Sopenharmony_ci	int remaining_frames;
1618c2ecf20Sopenharmony_ci	u8 *byte;
1628c2ecf20Sopenharmony_ci	const u32 *src;
1638c2ecf20Sopenharmony_ci	int i, c;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames;
1668c2ecf20Sopenharmony_ci	pcm_buffer_pointer %= runtime->buffer_size;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	src = (void *)runtime->dma_area +
1698c2ecf20Sopenharmony_ci				frames_to_bytes(runtime, pcm_buffer_pointer);
1708c2ecf20Sopenharmony_ci	remaining_frames = runtime->buffer_size - pcm_buffer_pointer;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	for (i = 0; i < data_blocks; ++i) {
1738c2ecf20Sopenharmony_ci		byte = (u8 *)buffer + p->pcm_byte_offset;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci		for (c = 0; c < channels; ++c) {
1768c2ecf20Sopenharmony_ci			byte[0] = (*src >> 24) & 0xff;
1778c2ecf20Sopenharmony_ci			byte[1] = (*src >> 16) & 0xff;
1788c2ecf20Sopenharmony_ci			byte[2] = (*src >>  8) & 0xff;
1798c2ecf20Sopenharmony_ci			byte += 3;
1808c2ecf20Sopenharmony_ci			src++;
1818c2ecf20Sopenharmony_ci		}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci		buffer += s->data_block_quadlets;
1848c2ecf20Sopenharmony_ci		if (--remaining_frames == 0)
1858c2ecf20Sopenharmony_ci			src = (void *)runtime->dma_area;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic void write_pcm_silence(struct amdtp_stream *s, __be32 *buffer,
1908c2ecf20Sopenharmony_ci			      unsigned int data_blocks)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	struct amdtp_motu *p = s->protocol;
1938c2ecf20Sopenharmony_ci	unsigned int channels, i, c;
1948c2ecf20Sopenharmony_ci	u8 *byte;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	channels = p->pcm_chunks;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	for (i = 0; i < data_blocks; ++i) {
1998c2ecf20Sopenharmony_ci		byte = (u8 *)buffer + p->pcm_byte_offset;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		for (c = 0; c < channels; ++c) {
2028c2ecf20Sopenharmony_ci			byte[0] = 0;
2038c2ecf20Sopenharmony_ci			byte[1] = 0;
2048c2ecf20Sopenharmony_ci			byte[2] = 0;
2058c2ecf20Sopenharmony_ci			byte += 3;
2068c2ecf20Sopenharmony_ci		}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci		buffer += s->data_block_quadlets;
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ciint amdtp_motu_add_pcm_hw_constraints(struct amdtp_stream *s,
2138c2ecf20Sopenharmony_ci				      struct snd_pcm_runtime *runtime)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	int err;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	/* TODO: how to set an constraint for exactly 24bit PCM sample? */
2188c2ecf20Sopenharmony_ci	err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
2198c2ecf20Sopenharmony_ci	if (err < 0)
2208c2ecf20Sopenharmony_ci		return err;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	return amdtp_stream_add_pcm_hw_constraints(s, runtime);
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_civoid amdtp_motu_midi_trigger(struct amdtp_stream *s, unsigned int port,
2268c2ecf20Sopenharmony_ci			     struct snd_rawmidi_substream *midi)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	struct amdtp_motu *p = s->protocol;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	if (port < p->midi_ports)
2318c2ecf20Sopenharmony_ci		WRITE_ONCE(p->midi, midi);
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic void write_midi_messages(struct amdtp_stream *s, __be32 *buffer,
2358c2ecf20Sopenharmony_ci				unsigned int data_blocks)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	struct amdtp_motu *p = s->protocol;
2388c2ecf20Sopenharmony_ci	struct snd_rawmidi_substream *midi = READ_ONCE(p->midi);
2398c2ecf20Sopenharmony_ci	u8 *b;
2408c2ecf20Sopenharmony_ci	int i;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	for (i = 0; i < data_blocks; i++) {
2438c2ecf20Sopenharmony_ci		b = (u8 *)buffer;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci		if (midi && p->midi_db_count == 0 &&
2468c2ecf20Sopenharmony_ci		    snd_rawmidi_transmit(midi, b + p->midi_byte_offset, 1) == 1) {
2478c2ecf20Sopenharmony_ci			b[p->midi_flag_offset] = 0x01;
2488c2ecf20Sopenharmony_ci		} else {
2498c2ecf20Sopenharmony_ci			b[p->midi_byte_offset] = 0x00;
2508c2ecf20Sopenharmony_ci			b[p->midi_flag_offset] = 0x00;
2518c2ecf20Sopenharmony_ci		}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci		buffer += s->data_block_quadlets;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci		if (--p->midi_db_count < 0)
2568c2ecf20Sopenharmony_ci			p->midi_db_count = p->midi_db_interval;
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic void read_midi_messages(struct amdtp_stream *s, __be32 *buffer,
2618c2ecf20Sopenharmony_ci			       unsigned int data_blocks)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct amdtp_motu *p = s->protocol;
2648c2ecf20Sopenharmony_ci	struct snd_rawmidi_substream *midi;
2658c2ecf20Sopenharmony_ci	u8 *b;
2668c2ecf20Sopenharmony_ci	int i;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	for (i = 0; i < data_blocks; i++) {
2698c2ecf20Sopenharmony_ci		b = (u8 *)buffer;
2708c2ecf20Sopenharmony_ci		midi = READ_ONCE(p->midi);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci		if (midi && (b[p->midi_flag_offset] & 0x01))
2738c2ecf20Sopenharmony_ci			snd_rawmidi_receive(midi, b + p->midi_byte_offset, 1);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		buffer += s->data_block_quadlets;
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci/* For tracepoints. */
2808c2ecf20Sopenharmony_cistatic void __maybe_unused copy_sph(u32 *frames, __be32 *buffer,
2818c2ecf20Sopenharmony_ci				    unsigned int data_blocks,
2828c2ecf20Sopenharmony_ci				    unsigned int data_block_quadlets)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	unsigned int i;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	for (i = 0; i < data_blocks; ++i) {
2878c2ecf20Sopenharmony_ci		*frames = be32_to_cpu(*buffer);
2888c2ecf20Sopenharmony_ci		buffer += data_block_quadlets;
2898c2ecf20Sopenharmony_ci		frames++;
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci/* For tracepoints. */
2948c2ecf20Sopenharmony_cistatic void __maybe_unused copy_message(u64 *frames, __be32 *buffer,
2958c2ecf20Sopenharmony_ci					unsigned int data_blocks,
2968c2ecf20Sopenharmony_ci					unsigned int data_block_quadlets)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	unsigned int i;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	/* This is just for v2/v3 protocol. */
3018c2ecf20Sopenharmony_ci	for (i = 0; i < data_blocks; ++i) {
3028c2ecf20Sopenharmony_ci		*frames = (be32_to_cpu(buffer[1]) << 16) |
3038c2ecf20Sopenharmony_ci			  (be32_to_cpu(buffer[2]) >> 16);
3048c2ecf20Sopenharmony_ci		buffer += data_block_quadlets;
3058c2ecf20Sopenharmony_ci		frames++;
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic void probe_tracepoints_events(struct amdtp_stream *s,
3108c2ecf20Sopenharmony_ci				     const struct pkt_desc *descs,
3118c2ecf20Sopenharmony_ci				     unsigned int packets)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	int i;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	for (i = 0; i < packets; ++i) {
3168c2ecf20Sopenharmony_ci		const struct pkt_desc *desc = descs + i;
3178c2ecf20Sopenharmony_ci		__be32 *buf = desc->ctx_payload;
3188c2ecf20Sopenharmony_ci		unsigned int data_blocks = desc->data_blocks;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci		trace_data_block_sph(s, data_blocks, buf);
3218c2ecf20Sopenharmony_ci		trace_data_block_message(s, data_blocks, buf);
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
3268c2ecf20Sopenharmony_ci					    const struct pkt_desc *descs,
3278c2ecf20Sopenharmony_ci					    unsigned int packets,
3288c2ecf20Sopenharmony_ci					    struct snd_pcm_substream *pcm)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	struct amdtp_motu *p = s->protocol;
3318c2ecf20Sopenharmony_ci	unsigned int pcm_frames = 0;
3328c2ecf20Sopenharmony_ci	int i;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	// For data block processing.
3358c2ecf20Sopenharmony_ci	for (i = 0; i < packets; ++i) {
3368c2ecf20Sopenharmony_ci		const struct pkt_desc *desc = descs + i;
3378c2ecf20Sopenharmony_ci		__be32 *buf = desc->ctx_payload;
3388c2ecf20Sopenharmony_ci		unsigned int data_blocks = desc->data_blocks;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci		if (pcm) {
3418c2ecf20Sopenharmony_ci			read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
3428c2ecf20Sopenharmony_ci			pcm_frames += data_blocks;
3438c2ecf20Sopenharmony_ci		}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		if (p->midi_ports)
3468c2ecf20Sopenharmony_ci			read_midi_messages(s, buf, data_blocks);
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	// For tracepoints.
3508c2ecf20Sopenharmony_ci	if (trace_data_block_sph_enabled() ||
3518c2ecf20Sopenharmony_ci	    trace_data_block_message_enabled())
3528c2ecf20Sopenharmony_ci		probe_tracepoints_events(s, descs, packets);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	return pcm_frames;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic inline void compute_next_elapse_from_start(struct amdtp_motu *p)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	p->next_accumulated += p->remainder_ticks_per_event;
3608c2ecf20Sopenharmony_ci	if (p->next_accumulated >= 441) {
3618c2ecf20Sopenharmony_ci		p->next_accumulated -= 441;
3628c2ecf20Sopenharmony_ci		p->next_ticks++;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	p->next_ticks += p->quotient_ticks_per_event;
3668c2ecf20Sopenharmony_ci	if (p->next_ticks >= 3072) {
3678c2ecf20Sopenharmony_ci		p->next_ticks -= 3072;
3688c2ecf20Sopenharmony_ci		p->next_cycles++;
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	if (p->next_cycles >= 8000) {
3728c2ecf20Sopenharmony_ci		p->next_cycles -= 8000;
3738c2ecf20Sopenharmony_ci		p->next_seconds++;
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	if (p->next_seconds >= 128)
3778c2ecf20Sopenharmony_ci		p->next_seconds -= 128;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic void write_sph(struct amdtp_stream *s, __be32 *buffer,
3818c2ecf20Sopenharmony_ci		      unsigned int data_blocks)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	struct amdtp_motu *p = s->protocol;
3848c2ecf20Sopenharmony_ci	unsigned int next_cycles;
3858c2ecf20Sopenharmony_ci	unsigned int i;
3868c2ecf20Sopenharmony_ci	u32 sph;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	for (i = 0; i < data_blocks; i++) {
3898c2ecf20Sopenharmony_ci		next_cycles = (s->start_cycle + p->next_cycles) % 8000;
3908c2ecf20Sopenharmony_ci		sph = ((next_cycles << 12) | p->next_ticks) & 0x01ffffff;
3918c2ecf20Sopenharmony_ci		*buffer = cpu_to_be32(sph);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		compute_next_elapse_from_start(p);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci		buffer += s->data_block_quadlets;
3968c2ecf20Sopenharmony_ci	}
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic unsigned int process_it_ctx_payloads(struct amdtp_stream *s,
4008c2ecf20Sopenharmony_ci					    const struct pkt_desc *descs,
4018c2ecf20Sopenharmony_ci					    unsigned int packets,
4028c2ecf20Sopenharmony_ci					    struct snd_pcm_substream *pcm)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	struct amdtp_motu *p = s->protocol;
4058c2ecf20Sopenharmony_ci	unsigned int pcm_frames = 0;
4068c2ecf20Sopenharmony_ci	int i;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	// For data block processing.
4098c2ecf20Sopenharmony_ci	for (i = 0; i < packets; ++i) {
4108c2ecf20Sopenharmony_ci		const struct pkt_desc *desc = descs + i;
4118c2ecf20Sopenharmony_ci		__be32 *buf = desc->ctx_payload;
4128c2ecf20Sopenharmony_ci		unsigned int data_blocks = desc->data_blocks;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci		if (pcm) {
4158c2ecf20Sopenharmony_ci			write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
4168c2ecf20Sopenharmony_ci			pcm_frames += data_blocks;
4178c2ecf20Sopenharmony_ci		} else {
4188c2ecf20Sopenharmony_ci			write_pcm_silence(s, buf, data_blocks);
4198c2ecf20Sopenharmony_ci		}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci		if (p->midi_ports)
4228c2ecf20Sopenharmony_ci			write_midi_messages(s, buf, data_blocks);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		// TODO: how to interact control messages between userspace?
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		write_sph(s, buf, data_blocks);
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	// For tracepoints.
4308c2ecf20Sopenharmony_ci	if (trace_data_block_sph_enabled() ||
4318c2ecf20Sopenharmony_ci	    trace_data_block_message_enabled())
4328c2ecf20Sopenharmony_ci		probe_tracepoints_events(s, descs, packets);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	return pcm_frames;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ciint amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
4388c2ecf20Sopenharmony_ci		    enum amdtp_stream_direction dir,
4398c2ecf20Sopenharmony_ci		    const struct snd_motu_spec *spec)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	amdtp_stream_process_ctx_payloads_t process_ctx_payloads;
4428c2ecf20Sopenharmony_ci	int fmt = CIP_FMT_MOTU;
4438c2ecf20Sopenharmony_ci	int flags = CIP_BLOCKING;
4448c2ecf20Sopenharmony_ci	int err;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	if (dir == AMDTP_IN_STREAM) {
4478c2ecf20Sopenharmony_ci		process_ctx_payloads = process_ir_ctx_payloads;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci		/*
4508c2ecf20Sopenharmony_ci		 * Units of version 3 transmits packets with invalid CIP header
4518c2ecf20Sopenharmony_ci		 * against IEC 61883-1.
4528c2ecf20Sopenharmony_ci		 */
4538c2ecf20Sopenharmony_ci		if (spec->protocol_version == SND_MOTU_PROTOCOL_V3) {
4548c2ecf20Sopenharmony_ci			flags |= CIP_WRONG_DBS |
4558c2ecf20Sopenharmony_ci				 CIP_SKIP_DBC_ZERO_CHECK |
4568c2ecf20Sopenharmony_ci				 CIP_HEADER_WITHOUT_EOH;
4578c2ecf20Sopenharmony_ci			fmt = CIP_FMT_MOTU_TX_V3;
4588c2ecf20Sopenharmony_ci		}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci		if (spec == &snd_motu_spec_8pre ||
4618c2ecf20Sopenharmony_ci		    spec == &snd_motu_spec_ultralite) {
4628c2ecf20Sopenharmony_ci			// 8pre has some quirks.
4638c2ecf20Sopenharmony_ci			flags |= CIP_WRONG_DBS |
4648c2ecf20Sopenharmony_ci				 CIP_SKIP_DBC_ZERO_CHECK;
4658c2ecf20Sopenharmony_ci		}
4668c2ecf20Sopenharmony_ci	} else {
4678c2ecf20Sopenharmony_ci		process_ctx_payloads = process_it_ctx_payloads;
4688c2ecf20Sopenharmony_ci		flags |= CIP_DBC_IS_END_EVENT;
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	err = amdtp_stream_init(s, unit, dir, flags, fmt, process_ctx_payloads,
4728c2ecf20Sopenharmony_ci				sizeof(struct amdtp_motu));
4738c2ecf20Sopenharmony_ci	if (err < 0)
4748c2ecf20Sopenharmony_ci		return err;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	s->sph = 1;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	if (dir == AMDTP_OUT_STREAM) {
4798c2ecf20Sopenharmony_ci		// Use fixed value for FDF field.
4808c2ecf20Sopenharmony_ci		s->ctx_data.rx.fdf = MOTU_FDF_AM824;
4818c2ecf20Sopenharmony_ci		// Not used.
4828c2ecf20Sopenharmony_ci		s->ctx_data.rx.syt_override = 0xffff;
4838c2ecf20Sopenharmony_ci	}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	return 0;
4868c2ecf20Sopenharmony_ci}
487