xref: /linux/sound/firewire/amdtp-am824.c (revision 976e3645923bdd2fe7893aae33fd7a21098bfb28)
1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25955815eSTakashi Sakamoto /*
35955815eSTakashi Sakamoto  * AM824 format in Audio and Music Data Transmission Protocol (IEC 61883-6)
45955815eSTakashi Sakamoto  *
5df075feeSTakashi Sakamoto  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
65955815eSTakashi Sakamoto  * Copyright (c) 2015 Takashi Sakamoto <o-takashi@sakamocchi.jp>
75955815eSTakashi Sakamoto  */
85955815eSTakashi Sakamoto 
9df075feeSTakashi Sakamoto #include <linux/slab.h>
10df075feeSTakashi Sakamoto 
115955815eSTakashi Sakamoto #include "amdtp-am824.h"
125955815eSTakashi Sakamoto 
135955815eSTakashi Sakamoto #define CIP_FMT_AM		0x10
145955815eSTakashi Sakamoto 
1551c29fd2STakashi Sakamoto /* "Clock-based rate control mode" is just supported. */
1651c29fd2STakashi Sakamoto #define AMDTP_FDF_AM824		0x00
1751c29fd2STakashi Sakamoto 
18df075feeSTakashi Sakamoto /*
19df075feeSTakashi Sakamoto  * Nominally 3125 bytes/second, but the MIDI port's clock might be
20df075feeSTakashi Sakamoto  * 1% too slow, and the bus clock 100 ppm too fast.
21df075feeSTakashi Sakamoto  */
22df075feeSTakashi Sakamoto #define MIDI_BYTES_PER_SECOND	3093
23df075feeSTakashi Sakamoto 
24df075feeSTakashi Sakamoto /*
25df075feeSTakashi Sakamoto  * Several devices look only at the first eight data blocks.
26df075feeSTakashi Sakamoto  * In any case, this is more than enough for the MIDI data rate.
27df075feeSTakashi Sakamoto  */
28df075feeSTakashi Sakamoto #define MAX_MIDI_RX_BLOCKS	8
29df075feeSTakashi Sakamoto 
30df075feeSTakashi Sakamoto struct amdtp_am824 {
31df075feeSTakashi Sakamoto 	struct snd_rawmidi_substream *midi[AM824_MAX_CHANNELS_FOR_MIDI * 8];
32df075feeSTakashi Sakamoto 	int midi_fifo_limit;
33df075feeSTakashi Sakamoto 	int midi_fifo_used[AM824_MAX_CHANNELS_FOR_MIDI * 8];
34df075feeSTakashi Sakamoto 	unsigned int pcm_channels;
35df075feeSTakashi Sakamoto 	unsigned int midi_ports;
36df075feeSTakashi Sakamoto 
37df075feeSTakashi Sakamoto 	u8 pcm_positions[AM824_MAX_CHANNELS_FOR_PCM];
38df075feeSTakashi Sakamoto 	u8 midi_position;
39df075feeSTakashi Sakamoto 
40df075feeSTakashi Sakamoto 	unsigned int frame_multiplier;
41df075feeSTakashi Sakamoto };
42df075feeSTakashi Sakamoto 
4351c29fd2STakashi Sakamoto /**
4451c29fd2STakashi Sakamoto  * amdtp_am824_set_parameters - set stream parameters
4551c29fd2STakashi Sakamoto  * @s: the AMDTP stream to configure
4651c29fd2STakashi Sakamoto  * @rate: the sample rate
4751c29fd2STakashi Sakamoto  * @pcm_channels: the number of PCM samples in each data block, to be encoded
4851c29fd2STakashi Sakamoto  *                as AM824 multi-bit linear audio
4951c29fd2STakashi Sakamoto  * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels)
5051c29fd2STakashi Sakamoto  * @double_pcm_frames: one data block transfers two PCM frames
5151c29fd2STakashi Sakamoto  *
5251c29fd2STakashi Sakamoto  * The parameters must be set before the stream is started, and must not be
5351c29fd2STakashi Sakamoto  * changed while the stream is running.
5451c29fd2STakashi Sakamoto  */
5551c29fd2STakashi Sakamoto int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate,
5651c29fd2STakashi Sakamoto 			       unsigned int pcm_channels,
5751c29fd2STakashi Sakamoto 			       unsigned int midi_ports,
5851c29fd2STakashi Sakamoto 			       bool double_pcm_frames)
5951c29fd2STakashi Sakamoto {
60df075feeSTakashi Sakamoto 	struct amdtp_am824 *p = s->protocol;
61df075feeSTakashi Sakamoto 	unsigned int midi_channels;
62df075feeSTakashi Sakamoto 	unsigned int i;
6351c29fd2STakashi Sakamoto 	int err;
6451c29fd2STakashi Sakamoto 
65df075feeSTakashi Sakamoto 	if (amdtp_stream_running(s))
66df075feeSTakashi Sakamoto 		return -EINVAL;
67df075feeSTakashi Sakamoto 
68df075feeSTakashi Sakamoto 	if (pcm_channels > AM824_MAX_CHANNELS_FOR_PCM)
69df075feeSTakashi Sakamoto 		return -EINVAL;
70df075feeSTakashi Sakamoto 
71df075feeSTakashi Sakamoto 	midi_channels = DIV_ROUND_UP(midi_ports, 8);
72df075feeSTakashi Sakamoto 	if (midi_channels > AM824_MAX_CHANNELS_FOR_MIDI)
73df075feeSTakashi Sakamoto 		return -EINVAL;
74df075feeSTakashi Sakamoto 
75df075feeSTakashi Sakamoto 	if (WARN_ON(amdtp_stream_running(s)) ||
76df075feeSTakashi Sakamoto 	    WARN_ON(pcm_channels > AM824_MAX_CHANNELS_FOR_PCM) ||
77df075feeSTakashi Sakamoto 	    WARN_ON(midi_channels > AM824_MAX_CHANNELS_FOR_MIDI))
78df075feeSTakashi Sakamoto 		return -EINVAL;
79df075feeSTakashi Sakamoto 
80df075feeSTakashi Sakamoto 	err = amdtp_stream_set_parameters(s, rate,
81df075feeSTakashi Sakamoto 					  pcm_channels + midi_channels);
8251c29fd2STakashi Sakamoto 	if (err < 0)
8351c29fd2STakashi Sakamoto 		return err;
8451c29fd2STakashi Sakamoto 
85d3d10a4aSTakashi Sakamoto 	s->ctx_data.rx.fdf = AMDTP_FDF_AM824 | s->sfc;
8651c29fd2STakashi Sakamoto 
87df075feeSTakashi Sakamoto 	p->pcm_channels = pcm_channels;
88df075feeSTakashi Sakamoto 	p->midi_ports = midi_ports;
89df075feeSTakashi Sakamoto 
9051c29fd2STakashi Sakamoto 	/*
9151c29fd2STakashi Sakamoto 	 * In IEC 61883-6, one data block represents one event. In ALSA, one
9251c29fd2STakashi Sakamoto 	 * event equals to one PCM frame. But Dice has a quirk at higher
9351c29fd2STakashi Sakamoto 	 * sampling rate to transfer two PCM frames in one data block.
9451c29fd2STakashi Sakamoto 	 */
9551c29fd2STakashi Sakamoto 	if (double_pcm_frames)
96df075feeSTakashi Sakamoto 		p->frame_multiplier = 2;
9751c29fd2STakashi Sakamoto 	else
98df075feeSTakashi Sakamoto 		p->frame_multiplier = 1;
99df075feeSTakashi Sakamoto 
100df075feeSTakashi Sakamoto 	/* init the position map for PCM and MIDI channels */
101df075feeSTakashi Sakamoto 	for (i = 0; i < pcm_channels; i++)
102df075feeSTakashi Sakamoto 		p->pcm_positions[i] = i;
103df075feeSTakashi Sakamoto 	p->midi_position = p->pcm_channels;
104df075feeSTakashi Sakamoto 
105df075feeSTakashi Sakamoto 	/*
106df075feeSTakashi Sakamoto 	 * We do not know the actual MIDI FIFO size of most devices.  Just
107df075feeSTakashi Sakamoto 	 * assume two bytes, i.e., one byte can be received over the bus while
108df075feeSTakashi Sakamoto 	 * the previous one is transmitted over MIDI.
109df075feeSTakashi Sakamoto 	 * (The value here is adjusted for midi_ratelimit_per_packet().)
110df075feeSTakashi Sakamoto 	 */
111df075feeSTakashi Sakamoto 	p->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1;
11251c29fd2STakashi Sakamoto 
11351c29fd2STakashi Sakamoto 	return 0;
11451c29fd2STakashi Sakamoto }
11551c29fd2STakashi Sakamoto EXPORT_SYMBOL_GPL(amdtp_am824_set_parameters);
11651c29fd2STakashi Sakamoto 
1175955815eSTakashi Sakamoto /**
118f65be911STakashi Sakamoto  * amdtp_am824_set_pcm_position - set an index of data channel for a channel
119f65be911STakashi Sakamoto  *				  of PCM frame
120f65be911STakashi Sakamoto  * @s: the AMDTP stream
121f65be911STakashi Sakamoto  * @index: the index of data channel in an data block
122f65be911STakashi Sakamoto  * @position: the channel of PCM frame
123f65be911STakashi Sakamoto  */
124f65be911STakashi Sakamoto void amdtp_am824_set_pcm_position(struct amdtp_stream *s, unsigned int index,
125f65be911STakashi Sakamoto 				 unsigned int position)
126f65be911STakashi Sakamoto {
127df075feeSTakashi Sakamoto 	struct amdtp_am824 *p = s->protocol;
128df075feeSTakashi Sakamoto 
129df075feeSTakashi Sakamoto 	if (index < p->pcm_channels)
130df075feeSTakashi Sakamoto 		p->pcm_positions[index] = position;
131f65be911STakashi Sakamoto }
132f65be911STakashi Sakamoto EXPORT_SYMBOL_GPL(amdtp_am824_set_pcm_position);
133f65be911STakashi Sakamoto 
134f65be911STakashi Sakamoto /**
135f65be911STakashi Sakamoto  * amdtp_am824_set_midi_position - set a index of data channel for MIDI
136f65be911STakashi Sakamoto  *				   conformant data channel
137f65be911STakashi Sakamoto  * @s: the AMDTP stream
138f65be911STakashi Sakamoto  * @position: the index of data channel in an data block
139f65be911STakashi Sakamoto  */
140f65be911STakashi Sakamoto void amdtp_am824_set_midi_position(struct amdtp_stream *s,
141f65be911STakashi Sakamoto 				   unsigned int position)
142f65be911STakashi Sakamoto {
143df075feeSTakashi Sakamoto 	struct amdtp_am824 *p = s->protocol;
144df075feeSTakashi Sakamoto 
145df075feeSTakashi Sakamoto 	p->midi_position = position;
146f65be911STakashi Sakamoto }
147f65be911STakashi Sakamoto EXPORT_SYMBOL_GPL(amdtp_am824_set_midi_position);
148f65be911STakashi Sakamoto 
1499fc90644STakashi Sakamoto static void write_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
1509fc90644STakashi Sakamoto 			  __be32 *buffer, unsigned int frames,
1519fc90644STakashi Sakamoto 			  unsigned int pcm_frames)
152df075feeSTakashi Sakamoto {
153df075feeSTakashi Sakamoto 	struct amdtp_am824 *p = s->protocol;
1549fc90644STakashi Sakamoto 	unsigned int channels = p->pcm_channels;
155df075feeSTakashi Sakamoto 	struct snd_pcm_runtime *runtime = pcm->runtime;
1569fc90644STakashi Sakamoto 	unsigned int pcm_buffer_pointer;
1579fc90644STakashi Sakamoto 	int remaining_frames;
158df075feeSTakashi Sakamoto 	const u32 *src;
1599fc90644STakashi Sakamoto 	int i, c;
160df075feeSTakashi Sakamoto 
1619fc90644STakashi Sakamoto 	pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames;
1629fc90644STakashi Sakamoto 	pcm_buffer_pointer %= runtime->buffer_size;
1639fc90644STakashi Sakamoto 
164df075feeSTakashi Sakamoto 	src = (void *)runtime->dma_area +
1659fc90644STakashi Sakamoto 				frames_to_bytes(runtime, pcm_buffer_pointer);
1669fc90644STakashi Sakamoto 	remaining_frames = runtime->buffer_size - pcm_buffer_pointer;
167df075feeSTakashi Sakamoto 
168df075feeSTakashi Sakamoto 	for (i = 0; i < frames; ++i) {
169df075feeSTakashi Sakamoto 		for (c = 0; c < channels; ++c) {
170df075feeSTakashi Sakamoto 			buffer[p->pcm_positions[c]] =
171df075feeSTakashi Sakamoto 					cpu_to_be32((*src >> 8) | 0x40000000);
172df075feeSTakashi Sakamoto 			src++;
173df075feeSTakashi Sakamoto 		}
174df075feeSTakashi Sakamoto 		buffer += s->data_block_quadlets;
175df075feeSTakashi Sakamoto 		if (--remaining_frames == 0)
176df075feeSTakashi Sakamoto 			src = (void *)runtime->dma_area;
177df075feeSTakashi Sakamoto 	}
178df075feeSTakashi Sakamoto }
179df075feeSTakashi Sakamoto 
1809fc90644STakashi Sakamoto static void read_pcm_s32(struct amdtp_stream *s, struct snd_pcm_substream *pcm,
1819fc90644STakashi Sakamoto 			 __be32 *buffer, unsigned int frames,
1829fc90644STakashi Sakamoto 			 unsigned int pcm_frames)
183df075feeSTakashi Sakamoto {
184df075feeSTakashi Sakamoto 	struct amdtp_am824 *p = s->protocol;
1859fc90644STakashi Sakamoto 	unsigned int channels = p->pcm_channels;
186df075feeSTakashi Sakamoto 	struct snd_pcm_runtime *runtime = pcm->runtime;
1879fc90644STakashi Sakamoto 	unsigned int pcm_buffer_pointer;
1889fc90644STakashi Sakamoto 	int remaining_frames;
189df075feeSTakashi Sakamoto 	u32 *dst;
1909fc90644STakashi Sakamoto 	int i, c;
191df075feeSTakashi Sakamoto 
1929fc90644STakashi Sakamoto 	pcm_buffer_pointer = s->pcm_buffer_pointer + pcm_frames;
1939fc90644STakashi Sakamoto 	pcm_buffer_pointer %= runtime->buffer_size;
1949fc90644STakashi Sakamoto 
195df075feeSTakashi Sakamoto 	dst  = (void *)runtime->dma_area +
1969fc90644STakashi Sakamoto 				frames_to_bytes(runtime, pcm_buffer_pointer);
1979fc90644STakashi Sakamoto 	remaining_frames = runtime->buffer_size - pcm_buffer_pointer;
198df075feeSTakashi Sakamoto 
199df075feeSTakashi Sakamoto 	for (i = 0; i < frames; ++i) {
200df075feeSTakashi Sakamoto 		for (c = 0; c < channels; ++c) {
201df075feeSTakashi Sakamoto 			*dst = be32_to_cpu(buffer[p->pcm_positions[c]]) << 8;
202df075feeSTakashi Sakamoto 			dst++;
203df075feeSTakashi Sakamoto 		}
204df075feeSTakashi Sakamoto 		buffer += s->data_block_quadlets;
205df075feeSTakashi Sakamoto 		if (--remaining_frames == 0)
206df075feeSTakashi Sakamoto 			dst = (void *)runtime->dma_area;
207df075feeSTakashi Sakamoto 	}
208df075feeSTakashi Sakamoto }
209df075feeSTakashi Sakamoto 
210df075feeSTakashi Sakamoto static void write_pcm_silence(struct amdtp_stream *s,
211df075feeSTakashi Sakamoto 			      __be32 *buffer, unsigned int frames)
212df075feeSTakashi Sakamoto {
213df075feeSTakashi Sakamoto 	struct amdtp_am824 *p = s->protocol;
214df075feeSTakashi Sakamoto 	unsigned int i, c, channels = p->pcm_channels;
215df075feeSTakashi Sakamoto 
216df075feeSTakashi Sakamoto 	for (i = 0; i < frames; ++i) {
217df075feeSTakashi Sakamoto 		for (c = 0; c < channels; ++c)
218df075feeSTakashi Sakamoto 			buffer[p->pcm_positions[c]] = cpu_to_be32(0x40000000);
219df075feeSTakashi Sakamoto 		buffer += s->data_block_quadlets;
220df075feeSTakashi Sakamoto 	}
221df075feeSTakashi Sakamoto }
222df075feeSTakashi Sakamoto 
223df075feeSTakashi Sakamoto /**
224bc8500daSTakashi Sakamoto  * amdtp_am824_add_pcm_hw_constraints - add hw constraints for PCM substream
225bc8500daSTakashi Sakamoto  * @s:		the AMDTP stream for AM824 data block, must be initialized.
226bc8500daSTakashi Sakamoto  * @runtime:	the PCM substream runtime
227bc8500daSTakashi Sakamoto  *
228bc8500daSTakashi Sakamoto  */
229bc8500daSTakashi Sakamoto int amdtp_am824_add_pcm_hw_constraints(struct amdtp_stream *s,
230bc8500daSTakashi Sakamoto 				       struct snd_pcm_runtime *runtime)
231bc8500daSTakashi Sakamoto {
232bc8500daSTakashi Sakamoto 	int err;
233bc8500daSTakashi Sakamoto 
234bc8500daSTakashi Sakamoto 	err = amdtp_stream_add_pcm_hw_constraints(s, runtime);
235bc8500daSTakashi Sakamoto 	if (err < 0)
236bc8500daSTakashi Sakamoto 		return err;
237bc8500daSTakashi Sakamoto 
238bc8500daSTakashi Sakamoto 	/* AM824 in IEC 61883-6 can deliver 24bit data. */
239bc8500daSTakashi Sakamoto 	return snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
240bc8500daSTakashi Sakamoto }
241bc8500daSTakashi Sakamoto EXPORT_SYMBOL_GPL(amdtp_am824_add_pcm_hw_constraints);
242bc8500daSTakashi Sakamoto 
243bc8500daSTakashi Sakamoto /**
24403e2a67eSTakashi Sakamoto  * amdtp_am824_midi_trigger - start/stop playback/capture with a MIDI device
24503e2a67eSTakashi Sakamoto  * @s: the AMDTP stream
24603e2a67eSTakashi Sakamoto  * @port: index of MIDI port
24703e2a67eSTakashi Sakamoto  * @midi: the MIDI device to be started, or %NULL to stop the current device
24803e2a67eSTakashi Sakamoto  *
24903e2a67eSTakashi Sakamoto  * Call this function on a running isochronous stream to enable the actual
25003e2a67eSTakashi Sakamoto  * transmission of MIDI data.  This function should be called from the MIDI
25103e2a67eSTakashi Sakamoto  * device's .trigger callback.
25203e2a67eSTakashi Sakamoto  */
25303e2a67eSTakashi Sakamoto void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port,
25403e2a67eSTakashi Sakamoto 			      struct snd_rawmidi_substream *midi)
25503e2a67eSTakashi Sakamoto {
256df075feeSTakashi Sakamoto 	struct amdtp_am824 *p = s->protocol;
257df075feeSTakashi Sakamoto 
258df075feeSTakashi Sakamoto 	if (port < p->midi_ports)
2596aa7de05SMark Rutland 		WRITE_ONCE(p->midi[port], midi);
26003e2a67eSTakashi Sakamoto }
26103e2a67eSTakashi Sakamoto EXPORT_SYMBOL_GPL(amdtp_am824_midi_trigger);
26203e2a67eSTakashi Sakamoto 
263df075feeSTakashi Sakamoto /*
264df075feeSTakashi Sakamoto  * To avoid sending MIDI bytes at too high a rate, assume that the receiving
265df075feeSTakashi Sakamoto  * device has a FIFO, and track how much it is filled.  This values increases
266df075feeSTakashi Sakamoto  * by one whenever we send one byte in a packet, but the FIFO empties at
267df075feeSTakashi Sakamoto  * a constant rate independent of our packet rate.  One packet has syt_interval
268df075feeSTakashi Sakamoto  * samples, so the number of bytes that empty out of the FIFO, per packet(!),
269df075feeSTakashi Sakamoto  * is MIDI_BYTES_PER_SECOND * syt_interval / sample_rate.  To avoid storing
270df075feeSTakashi Sakamoto  * fractional values, the values in midi_fifo_used[] are measured in bytes
271df075feeSTakashi Sakamoto  * multiplied by the sample rate.
272df075feeSTakashi Sakamoto  */
273df075feeSTakashi Sakamoto static bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port)
274df075feeSTakashi Sakamoto {
275df075feeSTakashi Sakamoto 	struct amdtp_am824 *p = s->protocol;
276df075feeSTakashi Sakamoto 	int used;
277df075feeSTakashi Sakamoto 
278df075feeSTakashi Sakamoto 	used = p->midi_fifo_used[port];
279df075feeSTakashi Sakamoto 	if (used == 0) /* common shortcut */
280df075feeSTakashi Sakamoto 		return true;
281df075feeSTakashi Sakamoto 
282df075feeSTakashi Sakamoto 	used -= MIDI_BYTES_PER_SECOND * s->syt_interval;
283df075feeSTakashi Sakamoto 	used = max(used, 0);
284df075feeSTakashi Sakamoto 	p->midi_fifo_used[port] = used;
285df075feeSTakashi Sakamoto 
286df075feeSTakashi Sakamoto 	return used < p->midi_fifo_limit;
287df075feeSTakashi Sakamoto }
288df075feeSTakashi Sakamoto 
289df075feeSTakashi Sakamoto static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port)
290df075feeSTakashi Sakamoto {
291df075feeSTakashi Sakamoto 	struct amdtp_am824 *p = s->protocol;
292df075feeSTakashi Sakamoto 
293df075feeSTakashi Sakamoto 	p->midi_fifo_used[port] += amdtp_rate_table[s->sfc];
294df075feeSTakashi Sakamoto }
295df075feeSTakashi Sakamoto 
296df075feeSTakashi Sakamoto static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer,
297ab754812STakashi Sakamoto 			unsigned int frames, unsigned int data_block_counter)
298df075feeSTakashi Sakamoto {
299df075feeSTakashi Sakamoto 	struct amdtp_am824 *p = s->protocol;
300df075feeSTakashi Sakamoto 	unsigned int f, port;
301df075feeSTakashi Sakamoto 	u8 *b;
302df075feeSTakashi Sakamoto 
303df075feeSTakashi Sakamoto 	for (f = 0; f < frames; f++) {
304df075feeSTakashi Sakamoto 		b = (u8 *)&buffer[p->midi_position];
305df075feeSTakashi Sakamoto 
306ab754812STakashi Sakamoto 		port = (data_block_counter + f) % 8;
307df075feeSTakashi Sakamoto 		if (f < MAX_MIDI_RX_BLOCKS &&
308df075feeSTakashi Sakamoto 		    midi_ratelimit_per_packet(s, port) &&
309df075feeSTakashi Sakamoto 		    p->midi[port] != NULL &&
310df075feeSTakashi Sakamoto 		    snd_rawmidi_transmit(p->midi[port], &b[1], 1) == 1) {
311df075feeSTakashi Sakamoto 			midi_rate_use_one_byte(s, port);
312df075feeSTakashi Sakamoto 			b[0] = 0x81;
313df075feeSTakashi Sakamoto 		} else {
314df075feeSTakashi Sakamoto 			b[0] = 0x80;
315df075feeSTakashi Sakamoto 			b[1] = 0;
316df075feeSTakashi Sakamoto 		}
317df075feeSTakashi Sakamoto 		b[2] = 0;
318df075feeSTakashi Sakamoto 		b[3] = 0;
319df075feeSTakashi Sakamoto 
320df075feeSTakashi Sakamoto 		buffer += s->data_block_quadlets;
321df075feeSTakashi Sakamoto 	}
322df075feeSTakashi Sakamoto }
323df075feeSTakashi Sakamoto 
324ab754812STakashi Sakamoto static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer,
325ab754812STakashi Sakamoto 			unsigned int frames, unsigned int data_block_counter)
326df075feeSTakashi Sakamoto {
327df075feeSTakashi Sakamoto 	struct amdtp_am824 *p = s->protocol;
328df075feeSTakashi Sakamoto 	int len;
329df075feeSTakashi Sakamoto 	u8 *b;
330588f2e2cSTakashi Sakamoto 	int f;
331df075feeSTakashi Sakamoto 
332df075feeSTakashi Sakamoto 	for (f = 0; f < frames; f++) {
333588f2e2cSTakashi Sakamoto 		unsigned int port = f;
334588f2e2cSTakashi Sakamoto 
335588f2e2cSTakashi Sakamoto 		if (!(s->flags & CIP_UNALIGHED_DBC))
336ab754812STakashi Sakamoto 			port += data_block_counter;
337588f2e2cSTakashi Sakamoto 		port %= 8;
338df075feeSTakashi Sakamoto 		b = (u8 *)&buffer[p->midi_position];
339df075feeSTakashi Sakamoto 
340df075feeSTakashi Sakamoto 		len = b[0] - 0x80;
341df075feeSTakashi Sakamoto 		if ((1 <= len) &&  (len <= 3) && (p->midi[port]))
342df075feeSTakashi Sakamoto 			snd_rawmidi_receive(p->midi[port], b + 1, len);
343df075feeSTakashi Sakamoto 
344df075feeSTakashi Sakamoto 		buffer += s->data_block_quadlets;
345df075feeSTakashi Sakamoto 	}
346df075feeSTakashi Sakamoto }
347df075feeSTakashi Sakamoto 
348*9a738ad1STakashi Sakamoto static unsigned int process_it_ctx_payloads(struct amdtp_stream *s,
349*9a738ad1STakashi Sakamoto 					    const struct pkt_desc *descs,
350*9a738ad1STakashi Sakamoto 					    unsigned int packets,
351d2c104a3STakashi Sakamoto 					    struct snd_pcm_substream *pcm)
352df075feeSTakashi Sakamoto {
353df075feeSTakashi Sakamoto 	struct amdtp_am824 *p = s->protocol;
3549fc90644STakashi Sakamoto 	unsigned int pcm_frames = 0;
355*9a738ad1STakashi Sakamoto 	int i;
356*9a738ad1STakashi Sakamoto 
357*9a738ad1STakashi Sakamoto 	for (i = 0; i < packets; ++i) {
358*9a738ad1STakashi Sakamoto 		const struct pkt_desc *desc = descs + i;
359*9a738ad1STakashi Sakamoto 		__be32 *buf = desc->ctx_payload;
360*9a738ad1STakashi Sakamoto 		unsigned int data_blocks = desc->data_blocks;
361df075feeSTakashi Sakamoto 
362df075feeSTakashi Sakamoto 		if (pcm) {
363*9a738ad1STakashi Sakamoto 			write_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
364*9a738ad1STakashi Sakamoto 			pcm_frames += data_blocks * p->frame_multiplier;
365df075feeSTakashi Sakamoto 		} else {
366*9a738ad1STakashi Sakamoto 			write_pcm_silence(s, buf, data_blocks);
367df075feeSTakashi Sakamoto 		}
368df075feeSTakashi Sakamoto 
369d2c104a3STakashi Sakamoto 		if (p->midi_ports) {
370*9a738ad1STakashi Sakamoto 			write_midi_messages(s, buf, data_blocks,
371d2c104a3STakashi Sakamoto 					    desc->data_block_counter);
372d2c104a3STakashi Sakamoto 		}
373*9a738ad1STakashi Sakamoto 	}
374df075feeSTakashi Sakamoto 
375df075feeSTakashi Sakamoto 	return pcm_frames;
376df075feeSTakashi Sakamoto }
377df075feeSTakashi Sakamoto 
378*9a738ad1STakashi Sakamoto static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
379*9a738ad1STakashi Sakamoto 					    const struct pkt_desc *descs,
380*9a738ad1STakashi Sakamoto 					    unsigned int packets,
381d2c104a3STakashi Sakamoto 					    struct snd_pcm_substream *pcm)
382df075feeSTakashi Sakamoto {
383df075feeSTakashi Sakamoto 	struct amdtp_am824 *p = s->protocol;
3849fc90644STakashi Sakamoto 	unsigned int pcm_frames = 0;
385*9a738ad1STakashi Sakamoto 	int i;
386*9a738ad1STakashi Sakamoto 
387*9a738ad1STakashi Sakamoto 	for (i = 0; i < packets; ++i) {
388*9a738ad1STakashi Sakamoto 		const struct pkt_desc *desc = descs + i;
389*9a738ad1STakashi Sakamoto 		__be32 *buf = desc->ctx_payload;
390*9a738ad1STakashi Sakamoto 		unsigned int data_blocks = desc->data_blocks;
391df075feeSTakashi Sakamoto 
392df075feeSTakashi Sakamoto 		if (pcm) {
393*9a738ad1STakashi Sakamoto 			read_pcm_s32(s, pcm, buf, data_blocks, pcm_frames);
394*9a738ad1STakashi Sakamoto 			pcm_frames += data_blocks * p->frame_multiplier;
395df075feeSTakashi Sakamoto 		}
396df075feeSTakashi Sakamoto 
397d2c104a3STakashi Sakamoto 		if (p->midi_ports) {
398*9a738ad1STakashi Sakamoto 			read_midi_messages(s, buf, data_blocks,
399d2c104a3STakashi Sakamoto 					   desc->data_block_counter);
400d2c104a3STakashi Sakamoto 		}
401*9a738ad1STakashi Sakamoto 	}
402df075feeSTakashi Sakamoto 
403df075feeSTakashi Sakamoto 	return pcm_frames;
404df075feeSTakashi Sakamoto }
405df075feeSTakashi Sakamoto 
40603e2a67eSTakashi Sakamoto /**
4075955815eSTakashi Sakamoto  * amdtp_am824_init - initialize an AMDTP stream structure to handle AM824
4085955815eSTakashi Sakamoto  *		      data block
4095955815eSTakashi Sakamoto  * @s: the AMDTP stream to initialize
4105955815eSTakashi Sakamoto  * @unit: the target of the stream
4115955815eSTakashi Sakamoto  * @dir: the direction of stream
4125955815eSTakashi Sakamoto  * @flags: the packet transmission method to use
4135955815eSTakashi Sakamoto  */
4145955815eSTakashi Sakamoto int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit,
4155955815eSTakashi Sakamoto 		     enum amdtp_stream_direction dir, enum cip_flags flags)
4165955815eSTakashi Sakamoto {
417*9a738ad1STakashi Sakamoto 	amdtp_stream_process_ctx_payloads_t process_ctx_payloads;
418df075feeSTakashi Sakamoto 
419df075feeSTakashi Sakamoto 	if (dir == AMDTP_IN_STREAM)
420*9a738ad1STakashi Sakamoto 		process_ctx_payloads = process_ir_ctx_payloads;
421df075feeSTakashi Sakamoto 	else
422*9a738ad1STakashi Sakamoto 		process_ctx_payloads = process_it_ctx_payloads;
423df075feeSTakashi Sakamoto 
424df075feeSTakashi Sakamoto 	return amdtp_stream_init(s, unit, dir, flags, CIP_FMT_AM,
425*9a738ad1STakashi Sakamoto 			process_ctx_payloads, sizeof(struct amdtp_am824));
4265955815eSTakashi Sakamoto }
4275955815eSTakashi Sakamoto EXPORT_SYMBOL_GPL(amdtp_am824_init);
428