162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * amdtp-dot.c - a part of driver for Digidesign Digi 002/003 family
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2014-2015 Takashi Sakamoto
662306a36Sopenharmony_ci * Copyright (C) 2012 Robin Gareus <robin@gareus.org>
762306a36Sopenharmony_ci * Copyright (C) 2012 Damien Zammit <damien@zamaudio.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <sound/pcm.h>
1162306a36Sopenharmony_ci#include "digi00x.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define CIP_FMT_AM		0x10
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* 'Clock-based rate control mode' is just supported. */
1662306a36Sopenharmony_ci#define AMDTP_FDF_AM824		0x00
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/*
1962306a36Sopenharmony_ci * Nominally 3125 bytes/second, but the MIDI port's clock might be
2062306a36Sopenharmony_ci * 1% too slow, and the bus clock 100 ppm too fast.
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci#define MIDI_BYTES_PER_SECOND	3093
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/*
2562306a36Sopenharmony_ci * Several devices look only at the first eight data blocks.
2662306a36Sopenharmony_ci * In any case, this is more than enough for the MIDI data rate.
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ci#define MAX_MIDI_RX_BLOCKS	8
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/* 3 = MAX(DOT_MIDI_IN_PORTS, DOT_MIDI_OUT_PORTS) + 1. */
3162306a36Sopenharmony_ci#define MAX_MIDI_PORTS		3
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/*
3462306a36Sopenharmony_ci * The double-oh-three algorithm was discovered by Robin Gareus and Damien
3562306a36Sopenharmony_ci * Zammit in 2012, with reverse-engineering for Digi 003 Rack.
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_cistruct dot_state {
3862306a36Sopenharmony_ci	u8 carry;
3962306a36Sopenharmony_ci	u8 idx;
4062306a36Sopenharmony_ci	unsigned int off;
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct amdtp_dot {
4462306a36Sopenharmony_ci	unsigned int pcm_channels;
4562306a36Sopenharmony_ci	struct dot_state state;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	struct snd_rawmidi_substream *midi[MAX_MIDI_PORTS];
4862306a36Sopenharmony_ci	int midi_fifo_used[MAX_MIDI_PORTS];
4962306a36Sopenharmony_ci	int midi_fifo_limit;
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/*
5362306a36Sopenharmony_ci * double-oh-three look up table
5462306a36Sopenharmony_ci *
5562306a36Sopenharmony_ci * @param idx index byte (audio-sample data) 0x00..0xff
5662306a36Sopenharmony_ci * @param off channel offset shift
5762306a36Sopenharmony_ci * @return salt to XOR with given data
5862306a36Sopenharmony_ci */
5962306a36Sopenharmony_ci#define BYTE_PER_SAMPLE (4)
6062306a36Sopenharmony_ci#define MAGIC_DOT_BYTE (2)
6162306a36Sopenharmony_ci#define MAGIC_BYTE_OFF(x) (((x) * BYTE_PER_SAMPLE) + MAGIC_DOT_BYTE)
6262306a36Sopenharmony_cistatic u8 dot_scrt(const u8 idx, const unsigned int off)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	/*
6562306a36Sopenharmony_ci	 * the length of the added pattern only depends on the lower nibble
6662306a36Sopenharmony_ci	 * of the last non-zero data
6762306a36Sopenharmony_ci	 */
6862306a36Sopenharmony_ci	static const u8 len[16] = {0, 1, 3, 5, 7, 9, 11, 13, 14,
6962306a36Sopenharmony_ci				   12, 10, 8, 6, 4, 2, 0};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/*
7262306a36Sopenharmony_ci	 * the lower nibble of the salt. Interleaved sequence.
7362306a36Sopenharmony_ci	 * this is walked backwards according to len[]
7462306a36Sopenharmony_ci	 */
7562306a36Sopenharmony_ci	static const u8 nib[15] = {0x8, 0x7, 0x9, 0x6, 0xa, 0x5, 0xb, 0x4,
7662306a36Sopenharmony_ci				   0xc, 0x3, 0xd, 0x2, 0xe, 0x1, 0xf};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/* circular list for the salt's hi nibble. */
7962306a36Sopenharmony_ci	static const u8 hir[15] = {0x0, 0x6, 0xf, 0x8, 0x7, 0x5, 0x3, 0x4,
8062306a36Sopenharmony_ci				   0xc, 0xd, 0xe, 0x1, 0x2, 0xb, 0xa};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	/*
8362306a36Sopenharmony_ci	 * start offset for upper nibble mapping.
8462306a36Sopenharmony_ci	 * note: 9 is /special/. In the case where the high nibble == 0x9,
8562306a36Sopenharmony_ci	 * hir[] is not used and - coincidentally - the salt's hi nibble is
8662306a36Sopenharmony_ci	 * 0x09 regardless of the offset.
8762306a36Sopenharmony_ci	 */
8862306a36Sopenharmony_ci	static const u8 hio[16] = {0, 11, 12, 6, 7, 5, 1, 4,
8962306a36Sopenharmony_ci				   3, 0x00, 14, 13, 8, 9, 10, 2};
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	const u8 ln = idx & 0xf;
9262306a36Sopenharmony_ci	const u8 hn = (idx >> 4) & 0xf;
9362306a36Sopenharmony_ci	const u8 hr = (hn == 0x9) ? 0x9 : hir[(hio[hn] + off) % 15];
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	if (len[ln] < off)
9662306a36Sopenharmony_ci		return 0x00;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return ((nib[14 + off - len[ln]]) | (hr << 4));
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic void dot_encode_step(struct dot_state *state, __be32 *const buffer)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	u8 * const data = (u8 *) buffer;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (data[MAGIC_DOT_BYTE] != 0x00) {
10662306a36Sopenharmony_ci		state->off = 0;
10762306a36Sopenharmony_ci		state->idx = data[MAGIC_DOT_BYTE] ^ state->carry;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci	data[MAGIC_DOT_BYTE] ^= state->carry;
11062306a36Sopenharmony_ci	state->carry = dot_scrt(state->idx, ++(state->off));
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ciint amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate,
11462306a36Sopenharmony_ci			     unsigned int pcm_channels)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct amdtp_dot *p = s->protocol;
11762306a36Sopenharmony_ci	int err;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (amdtp_stream_running(s))
12062306a36Sopenharmony_ci		return -EBUSY;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/*
12362306a36Sopenharmony_ci	 * A first data channel is for MIDI messages, the rest is Multi Bit
12462306a36Sopenharmony_ci	 * Linear Audio data channel.
12562306a36Sopenharmony_ci	 */
12662306a36Sopenharmony_ci	err = amdtp_stream_set_parameters(s, rate, pcm_channels + 1, 1);
12762306a36Sopenharmony_ci	if (err < 0)
12862306a36Sopenharmony_ci		return err;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	s->ctx_data.rx.fdf = AMDTP_FDF_AM824 | s->sfc;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	p->pcm_channels = pcm_channels;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	/*
13562306a36Sopenharmony_ci	 * We do not know the actual MIDI FIFO size of most devices.  Just
13662306a36Sopenharmony_ci	 * assume two bytes, i.e., one byte can be received over the bus while
13762306a36Sopenharmony_ci	 * the previous one is transmitted over MIDI.
13862306a36Sopenharmony_ci	 * (The value here is adjusted for midi_ratelimit_per_packet().)
13962306a36Sopenharmony_ci	 */
14062306a36Sopenharmony_ci	p->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	return 0;
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
14662306a36Sopenharmony_ci			  __be32 *buffer, unsigned int frames,
14762306a36Sopenharmony_ci			  unsigned int pcm_frames)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	struct amdtp_dot *p = s->protocol;
15062306a36Sopenharmony_ci	unsigned int channels = p->pcm_channels;
15162306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = pcm->runtime;
15262306a36Sopenharmony_ci	unsigned int pcm_buffer_pointer;
15362306a36Sopenharmony_ci	int remaining_frames;
15462306a36Sopenharmony_ci	const u32 *src;
15562306a36Sopenharmony_ci	int i, c;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames;
15862306a36Sopenharmony_ci	pcm_buffer_pointer %= runtime->buffer_size;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	src = (void *)runtime->dma_area +
16162306a36Sopenharmony_ci				frames_to_bytes(runtime, pcm_buffer_pointer);
16262306a36Sopenharmony_ci	remaining_frames = runtime->buffer_size - pcm_buffer_pointer;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	buffer++;
16562306a36Sopenharmony_ci	for (i = 0; i < frames; ++i) {
16662306a36Sopenharmony_ci		for (c = 0; c < channels; ++c) {
16762306a36Sopenharmony_ci			buffer[c] = cpu_to_be32((*src >> 8) | 0x40000000);
16862306a36Sopenharmony_ci			dot_encode_step(&p->state, &buffer[c]);
16962306a36Sopenharmony_ci			src++;
17062306a36Sopenharmony_ci		}
17162306a36Sopenharmony_ci		buffer += s->data_block_quadlets;
17262306a36Sopenharmony_ci		if (--remaining_frames == 0)
17362306a36Sopenharmony_ci			src = (void *)runtime->dma_area;
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
17862306a36Sopenharmony_ci			 __be32 *buffer, unsigned int frames,
17962306a36Sopenharmony_ci			 unsigned int pcm_frames)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct amdtp_dot *p = s->protocol;
18262306a36Sopenharmony_ci	unsigned int channels = p->pcm_channels;
18362306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = pcm->runtime;
18462306a36Sopenharmony_ci	unsigned int pcm_buffer_pointer;
18562306a36Sopenharmony_ci	int remaining_frames;
18662306a36Sopenharmony_ci	u32 *dst;
18762306a36Sopenharmony_ci	int i, c;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames;
19062306a36Sopenharmony_ci	pcm_buffer_pointer %= runtime->buffer_size;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	dst  = (void *)runtime->dma_area +
19362306a36Sopenharmony_ci				frames_to_bytes(runtime, pcm_buffer_pointer);
19462306a36Sopenharmony_ci	remaining_frames = runtime->buffer_size - pcm_buffer_pointer;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	buffer++;
19762306a36Sopenharmony_ci	for (i = 0; i < frames; ++i) {
19862306a36Sopenharmony_ci		for (c = 0; c < channels; ++c) {
19962306a36Sopenharmony_ci			*dst = be32_to_cpu(buffer[c]) << 8;
20062306a36Sopenharmony_ci			dst++;
20162306a36Sopenharmony_ci		}
20262306a36Sopenharmony_ci		buffer += s->data_block_quadlets;
20362306a36Sopenharmony_ci		if (--remaining_frames == 0)
20462306a36Sopenharmony_ci			dst = (void *)runtime->dma_area;
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic void write_pcm_silence(struct amdtp_stream *s, __be32 *buffer,
20962306a36Sopenharmony_ci			      unsigned int data_blocks)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	struct amdtp_dot *p = s->protocol;
21262306a36Sopenharmony_ci	unsigned int channels, i, c;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	channels = p->pcm_channels;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	buffer++;
21762306a36Sopenharmony_ci	for (i = 0; i < data_blocks; ++i) {
21862306a36Sopenharmony_ci		for (c = 0; c < channels; ++c)
21962306a36Sopenharmony_ci			buffer[c] = cpu_to_be32(0x40000000);
22062306a36Sopenharmony_ci		buffer += s->data_block_quadlets;
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	struct amdtp_dot *p = s->protocol;
22762306a36Sopenharmony_ci	int used;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	used = p->midi_fifo_used[port];
23062306a36Sopenharmony_ci	if (used == 0)
23162306a36Sopenharmony_ci		return true;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	used -= MIDI_BYTES_PER_SECOND * s->syt_interval;
23462306a36Sopenharmony_ci	used = max(used, 0);
23562306a36Sopenharmony_ci	p->midi_fifo_used[port] = used;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	return used < p->midi_fifo_limit;
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic inline void midi_use_bytes(struct amdtp_stream *s,
24162306a36Sopenharmony_ci				  unsigned int port, unsigned int count)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	struct amdtp_dot *p = s->protocol;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	p->midi_fifo_used[port] += amdtp_rate_table[s->sfc] * count;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic void write_midi_messages(struct amdtp_stream *s, __be32 *buffer,
24962306a36Sopenharmony_ci		unsigned int data_blocks, unsigned int data_block_counter)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct amdtp_dot *p = s->protocol;
25262306a36Sopenharmony_ci	unsigned int f, port;
25362306a36Sopenharmony_ci	int len;
25462306a36Sopenharmony_ci	u8 *b;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	for (f = 0; f < data_blocks; f++) {
25762306a36Sopenharmony_ci		port = (data_block_counter + f) % 8;
25862306a36Sopenharmony_ci		b = (u8 *)&buffer[0];
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci		len = 0;
26162306a36Sopenharmony_ci		if (port < MAX_MIDI_PORTS &&
26262306a36Sopenharmony_ci		    midi_ratelimit_per_packet(s, port) &&
26362306a36Sopenharmony_ci		    p->midi[port] != NULL)
26462306a36Sopenharmony_ci			len = snd_rawmidi_transmit(p->midi[port], b + 1, 2);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		if (len > 0) {
26762306a36Sopenharmony_ci			/*
26862306a36Sopenharmony_ci			 * Upper 4 bits of LSB represent port number.
26962306a36Sopenharmony_ci			 * - 0000b: physical MIDI port 1.
27062306a36Sopenharmony_ci			 * - 0010b: physical MIDI port 2.
27162306a36Sopenharmony_ci			 * - 1110b: console MIDI port.
27262306a36Sopenharmony_ci			 */
27362306a36Sopenharmony_ci			if (port == 2)
27462306a36Sopenharmony_ci				b[3] = 0xe0;
27562306a36Sopenharmony_ci			else if (port == 1)
27662306a36Sopenharmony_ci				b[3] = 0x20;
27762306a36Sopenharmony_ci			else
27862306a36Sopenharmony_ci				b[3] = 0x00;
27962306a36Sopenharmony_ci			b[3] |= len;
28062306a36Sopenharmony_ci			midi_use_bytes(s, port, len);
28162306a36Sopenharmony_ci		} else {
28262306a36Sopenharmony_ci			b[1] = 0;
28362306a36Sopenharmony_ci			b[2] = 0;
28462306a36Sopenharmony_ci			b[3] = 0;
28562306a36Sopenharmony_ci		}
28662306a36Sopenharmony_ci		b[0] = 0x80;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		buffer += s->data_block_quadlets;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic void read_midi_messages(struct amdtp_stream *s, __be32 *buffer,
29362306a36Sopenharmony_ci			       unsigned int data_blocks)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct amdtp_dot *p = s->protocol;
29662306a36Sopenharmony_ci	unsigned int f, port, len;
29762306a36Sopenharmony_ci	u8 *b;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	for (f = 0; f < data_blocks; f++) {
30062306a36Sopenharmony_ci		b = (u8 *)&buffer[0];
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		len = b[3] & 0x0f;
30362306a36Sopenharmony_ci		if (len > 0) {
30462306a36Sopenharmony_ci			/*
30562306a36Sopenharmony_ci			 * Upper 4 bits of LSB represent port number.
30662306a36Sopenharmony_ci			 * - 0000b: physical MIDI port 1. Use port 0.
30762306a36Sopenharmony_ci			 * - 1110b: console MIDI port. Use port 2.
30862306a36Sopenharmony_ci			 */
30962306a36Sopenharmony_ci			if (b[3] >> 4 > 0)
31062306a36Sopenharmony_ci				port = 2;
31162306a36Sopenharmony_ci			else
31262306a36Sopenharmony_ci				port = 0;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci			if (port < MAX_MIDI_PORTS && p->midi[port])
31562306a36Sopenharmony_ci				snd_rawmidi_receive(p->midi[port], b + 1, len);
31662306a36Sopenharmony_ci		}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci		buffer += s->data_block_quadlets;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ciint amdtp_dot_add_pcm_hw_constraints(struct amdtp_stream *s,
32362306a36Sopenharmony_ci				     struct snd_pcm_runtime *runtime)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	int err;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/* This protocol delivers 24 bit data in 32bit data channel. */
32862306a36Sopenharmony_ci	err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
32962306a36Sopenharmony_ci	if (err < 0)
33062306a36Sopenharmony_ci		return err;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return amdtp_stream_add_pcm_hw_constraints(s, runtime);
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_civoid amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port,
33662306a36Sopenharmony_ci			  struct snd_rawmidi_substream *midi)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct amdtp_dot *p = s->protocol;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (port < MAX_MIDI_PORTS)
34162306a36Sopenharmony_ci		WRITE_ONCE(p->midi[port], midi);
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic void process_ir_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *desc,
34562306a36Sopenharmony_ci				    unsigned int count, struct snd_pcm_substream *pcm)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	unsigned int pcm_frames = 0;
34862306a36Sopenharmony_ci	int i;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	for (i = 0; i < count; ++i) {
35162306a36Sopenharmony_ci		__be32 *buf = desc->ctx_payload;
35262306a36Sopenharmony_ci		unsigned int data_blocks = desc->data_blocks;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci		if (pcm) {
35562306a36Sopenharmony_ci			read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
35662306a36Sopenharmony_ci			pcm_frames += data_blocks;
35762306a36Sopenharmony_ci		}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci		read_midi_messages(s, buf, data_blocks);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		desc = amdtp_stream_next_packet_desc(s, desc);
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic void process_it_ctx_payloads(struct amdtp_stream *s, const struct pkt_desc *desc,
36662306a36Sopenharmony_ci				    unsigned int count, struct snd_pcm_substream *pcm)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	unsigned int pcm_frames = 0;
36962306a36Sopenharmony_ci	int i;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	for (i = 0; i < count; ++i) {
37262306a36Sopenharmony_ci		__be32 *buf = desc->ctx_payload;
37362306a36Sopenharmony_ci		unsigned int data_blocks = desc->data_blocks;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci		if (pcm) {
37662306a36Sopenharmony_ci			write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
37762306a36Sopenharmony_ci			pcm_frames += data_blocks;
37862306a36Sopenharmony_ci		} else {
37962306a36Sopenharmony_ci			write_pcm_silence(s, buf, data_blocks);
38062306a36Sopenharmony_ci		}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci		write_midi_messages(s, buf, data_blocks,
38362306a36Sopenharmony_ci				    desc->data_block_counter);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci		desc = amdtp_stream_next_packet_desc(s, desc);
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ciint amdtp_dot_init(struct amdtp_stream *s, struct fw_unit *unit,
39062306a36Sopenharmony_ci		 enum amdtp_stream_direction dir)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	amdtp_stream_process_ctx_payloads_t process_ctx_payloads;
39362306a36Sopenharmony_ci	unsigned int flags = CIP_NONBLOCKING | CIP_UNAWARE_SYT;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	// Use different mode between incoming/outgoing.
39662306a36Sopenharmony_ci	if (dir == AMDTP_IN_STREAM)
39762306a36Sopenharmony_ci		process_ctx_payloads = process_ir_ctx_payloads;
39862306a36Sopenharmony_ci	else
39962306a36Sopenharmony_ci		process_ctx_payloads = process_it_ctx_payloads;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM,
40262306a36Sopenharmony_ci				process_ctx_payloads, sizeof(struct amdtp_dot));
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_civoid amdtp_dot_reset(struct amdtp_stream *s)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	struct amdtp_dot *p = s->protocol;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	p->state.carry = 0x00;
41062306a36Sopenharmony_ci	p->state.idx = 0x00;
41162306a36Sopenharmony_ci	p->state.off = 0;
41262306a36Sopenharmony_ci}
413