1// SPDX-License-Identifier: GPL-2.0-only
2//
3// motu-register-dsp-message-parser.c - a part of driver for MOTU FireWire series
4//
5// Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp>
6
7// Below models allow software to configure their DSP functions by asynchronous transaction
8// to access their internal registers.
9// * 828 mk2
10// * 896hd
11// * Traveler
12// * 8 pre
13// * Ultralite
14// * 4 pre
15// * Audio Express
16//
17// Additionally, isochronous packets from the above models include messages to notify state of
18// DSP. The messages are two set of 3 byte data in 2nd and 3rd quadlet of data block. When user
19// operates hardware components such as dial and switch, corresponding messages are transferred.
20// The messages include Hardware metering and MIDI messages as well.
21
22#include "motu.h"
23
24#define MSG_FLAG_POS                    4
25#define MSG_FLAG_TYPE_MASK              0xf8
26#define MSG_FLAG_MIDI_MASK              0x01
27#define MSG_FLAG_MODEL_SPECIFIC_MASK    0x06
28#define   MSG_FLAG_8PRE                 0x00
29#define   MSG_FLAG_ULTRALITE            0x04
30#define   MSG_FLAG_TRAVELER             0x04
31#define   MSG_FLAG_828MK2               0x04
32#define   MSG_FLAG_896HD                0x04
33#define   MSG_FLAG_4PRE                 0x05 // MIDI mask is in 8th byte.
34#define   MSG_FLAG_AUDIOEXPRESS         0x05 // MIDI mask is in 8th byte.
35#define MSG_FLAG_TYPE_SHIFT             3
36#define MSG_VALUE_POS                   5
37#define MSG_MIDI_BYTE_POS		6
38#define MSG_METER_IDX_POS               7
39
40// In 4 pre and Audio express, meter index is in 6th byte. MIDI flag is in 8th byte and MIDI byte
41// is in 7th byte.
42#define MSG_METER_IDX_POS_4PRE_AE	6
43#define MSG_MIDI_BYTE_POS_4PRE_AE	7
44#define MSG_FLAG_MIDI_POS_4PRE_AE	8
45
46enum register_dsp_msg_type {
47	// Used for messages with no information.
48	INVALID = 0x00,
49	MIXER_SELECT = 0x01,
50	MIXER_SRC_GAIN = 0x02,
51	MIXER_SRC_PAN = 0x03,
52	MIXER_SRC_FLAG = 0x04,
53	MIXER_OUTPUT_PAIRED_VOLUME = 0x05,
54	MIXER_OUTPUT_PAIRED_FLAG = 0x06,
55	MAIN_OUTPUT_PAIRED_VOLUME = 0x07,
56	HP_OUTPUT_PAIRED_VOLUME = 0x08,
57	HP_OUTPUT_PAIRED_ASSIGNMENT = 0x09,
58	// Transferred by all models but the purpose is still unknown.
59	UNKNOWN_0 = 0x0a,
60	// Specific to 828mk2, 896hd, Traveler.
61	UNKNOWN_2 = 0x0c,
62	// Specific to 828mk2, Traveler, and 896hd (not functional).
63	LINE_INPUT_BOOST = 0x0d,
64	// Specific to 828mk2, Traveler, and 896hd (not functional).
65	LINE_INPUT_NOMINAL_LEVEL = 0x0e,
66	// Specific to Ultralite, 4 pre, Audio express, and 8 pre (not functional).
67	INPUT_GAIN_AND_INVERT = 0x15,
68	// Specific to 4 pre, and Audio express.
69	INPUT_FLAG = 0x16,
70	// Specific to 4 pre, and Audio express.
71	MIXER_SRC_PAIRED_BALANCE = 0x17,
72	// Specific to 4 pre, and Audio express.
73	MIXER_SRC_PAIRED_WIDTH = 0x18,
74	// Transferred by all models. This type of message interposes the series of the other
75	// messages. The message delivers signal level up to 96.0 kHz. In 828mk2, 896hd, and
76	// Traveler, one of physical outputs is selected for the message. The selection is done
77	// by LSB one byte in asynchronous write quadlet transaction to 0x'ffff'f000'0b2c.
78	METER = 0x1f,
79};
80
81#define EVENT_QUEUE_SIZE	16
82
83struct msg_parser {
84	spinlock_t lock;
85	struct snd_firewire_motu_register_dsp_meter meter;
86	bool meter_pos_quirk;
87
88	struct snd_firewire_motu_register_dsp_parameter param;
89	u8 prev_mixer_src_type;
90	u8 mixer_ch;
91	u8 mixer_src_ch;
92
93	u8 input_ch;
94	u8 prev_msg_type;
95
96	u32 event_queue[EVENT_QUEUE_SIZE];
97	unsigned int push_pos;
98	unsigned int pull_pos;
99};
100
101int snd_motu_register_dsp_message_parser_new(struct snd_motu *motu)
102{
103	struct msg_parser *parser;
104	parser = devm_kzalloc(&motu->card->card_dev, sizeof(*parser), GFP_KERNEL);
105	if (!parser)
106		return -ENOMEM;
107	spin_lock_init(&parser->lock);
108	if (motu->spec == &snd_motu_spec_4pre || motu->spec == &snd_motu_spec_audio_express)
109		parser->meter_pos_quirk = true;
110	motu->message_parser = parser;
111	return 0;
112}
113
114int snd_motu_register_dsp_message_parser_init(struct snd_motu *motu)
115{
116	struct msg_parser *parser = motu->message_parser;
117
118	parser->prev_mixer_src_type = INVALID;
119	parser->mixer_ch = 0xff;
120	parser->mixer_src_ch = 0xff;
121	parser->prev_msg_type = INVALID;
122
123	return 0;
124}
125
126// Rough implementaion of queue without overrun check.
127static void queue_event(struct snd_motu *motu, u8 msg_type, u8 identifier0, u8 identifier1, u8 val)
128{
129	struct msg_parser *parser = motu->message_parser;
130	unsigned int pos = parser->push_pos;
131	u32 entry;
132
133	if (!motu->hwdep || motu->hwdep->used == 0)
134		return;
135
136	entry = (msg_type << 24) | (identifier0 << 16) | (identifier1 << 8) | val;
137	parser->event_queue[pos] = entry;
138
139	++pos;
140	if (pos >= EVENT_QUEUE_SIZE)
141		pos = 0;
142	parser->push_pos = pos;
143}
144
145void snd_motu_register_dsp_message_parser_parse(const struct amdtp_stream *s,
146						const struct pkt_desc *desc, unsigned int count)
147{
148	struct snd_motu *motu = container_of(s, struct snd_motu, tx_stream);
149	unsigned int data_block_quadlets = s->data_block_quadlets;
150	struct msg_parser *parser = motu->message_parser;
151	bool meter_pos_quirk = parser->meter_pos_quirk;
152	unsigned int pos = parser->push_pos;
153	unsigned long flags;
154	int i;
155
156	spin_lock_irqsave(&parser->lock, flags);
157
158	for (i = 0; i < count; ++i) {
159		__be32 *buffer = desc->ctx_payload;
160		unsigned int data_blocks = desc->data_blocks;
161		int j;
162
163		desc = amdtp_stream_next_packet_desc(s, desc);
164
165		for (j = 0; j < data_blocks; ++j) {
166			u8 *b = (u8 *)buffer;
167			u8 msg_type = (b[MSG_FLAG_POS] & MSG_FLAG_TYPE_MASK) >> MSG_FLAG_TYPE_SHIFT;
168			u8 val = b[MSG_VALUE_POS];
169
170			buffer += data_block_quadlets;
171
172			switch (msg_type) {
173			case MIXER_SELECT:
174			{
175				u8 mixer_ch = val / 0x20;
176				if (mixer_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_COUNT) {
177					parser->mixer_src_ch = 0;
178					parser->mixer_ch = mixer_ch;
179				}
180				break;
181			}
182			case MIXER_SRC_GAIN:
183			case MIXER_SRC_PAN:
184			case MIXER_SRC_FLAG:
185			case MIXER_SRC_PAIRED_BALANCE:
186			case MIXER_SRC_PAIRED_WIDTH:
187			{
188				struct snd_firewire_motu_register_dsp_parameter *param = &parser->param;
189				u8 mixer_ch = parser->mixer_ch;
190				u8 mixer_src_ch = parser->mixer_src_ch;
191
192				if (msg_type != parser->prev_mixer_src_type)
193					mixer_src_ch = 0;
194				else
195					++mixer_src_ch;
196				parser->prev_mixer_src_type = msg_type;
197
198				if (mixer_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_COUNT &&
199				    mixer_src_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_SRC_COUNT) {
200					u8 mixer_ch = parser->mixer_ch;
201
202					switch (msg_type) {
203					case MIXER_SRC_GAIN:
204						if (param->mixer.source[mixer_ch].gain[mixer_src_ch] != val) {
205							queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val);
206							param->mixer.source[mixer_ch].gain[mixer_src_ch] = val;
207						}
208						break;
209					case MIXER_SRC_PAN:
210						if (param->mixer.source[mixer_ch].pan[mixer_src_ch] != val) {
211							queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val);
212							param->mixer.source[mixer_ch].pan[mixer_src_ch] = val;
213						}
214						break;
215					case MIXER_SRC_FLAG:
216						if (param->mixer.source[mixer_ch].flag[mixer_src_ch] != val) {
217							queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val);
218							param->mixer.source[mixer_ch].flag[mixer_src_ch] = val;
219						}
220						break;
221					case MIXER_SRC_PAIRED_BALANCE:
222						if (param->mixer.source[mixer_ch].paired_balance[mixer_src_ch] != val) {
223							queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val);
224							param->mixer.source[mixer_ch].paired_balance[mixer_src_ch] = val;
225						}
226						break;
227					case MIXER_SRC_PAIRED_WIDTH:
228						if (param->mixer.source[mixer_ch].paired_width[mixer_src_ch] != val) {
229							queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val);
230							param->mixer.source[mixer_ch].paired_width[mixer_src_ch] = val;
231						}
232						break;
233					default:
234						break;
235					}
236
237					parser->mixer_src_ch = mixer_src_ch;
238				}
239				break;
240			}
241			case MIXER_OUTPUT_PAIRED_VOLUME:
242			case MIXER_OUTPUT_PAIRED_FLAG:
243			{
244				struct snd_firewire_motu_register_dsp_parameter *param = &parser->param;
245				u8 mixer_ch = parser->mixer_ch;
246
247				if (mixer_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_COUNT) {
248					switch (msg_type) {
249					case MIXER_OUTPUT_PAIRED_VOLUME:
250						if (param->mixer.output.paired_volume[mixer_ch] != val) {
251							queue_event(motu, msg_type, mixer_ch, 0, val);
252							param->mixer.output.paired_volume[mixer_ch] = val;
253						}
254						break;
255					case MIXER_OUTPUT_PAIRED_FLAG:
256						if (param->mixer.output.paired_flag[mixer_ch] != val) {
257							queue_event(motu, msg_type, mixer_ch, 0, val);
258							param->mixer.output.paired_flag[mixer_ch] = val;
259						}
260						break;
261					default:
262						break;
263					}
264				}
265				break;
266			}
267			case MAIN_OUTPUT_PAIRED_VOLUME:
268				if (parser->param.output.main_paired_volume != val) {
269					queue_event(motu, msg_type, 0, 0, val);
270					parser->param.output.main_paired_volume = val;
271				}
272				break;
273			case HP_OUTPUT_PAIRED_VOLUME:
274				if (parser->param.output.hp_paired_volume != val) {
275					queue_event(motu, msg_type, 0, 0, val);
276					parser->param.output.hp_paired_volume = val;
277				}
278				break;
279			case HP_OUTPUT_PAIRED_ASSIGNMENT:
280				if (parser->param.output.hp_paired_assignment != val) {
281					queue_event(motu, msg_type, 0, 0, val);
282					parser->param.output.hp_paired_assignment = val;
283				}
284				break;
285			case LINE_INPUT_BOOST:
286				if (parser->param.line_input.boost_flag != val) {
287					queue_event(motu, msg_type, 0, 0, val);
288					parser->param.line_input.boost_flag = val;
289				}
290				break;
291			case LINE_INPUT_NOMINAL_LEVEL:
292				if (parser->param.line_input.nominal_level_flag != val) {
293					queue_event(motu, msg_type, 0, 0, val);
294					parser->param.line_input.nominal_level_flag = val;
295				}
296				break;
297			case INPUT_GAIN_AND_INVERT:
298			case INPUT_FLAG:
299			{
300				struct snd_firewire_motu_register_dsp_parameter *param = &parser->param;
301				u8 input_ch = parser->input_ch;
302
303				if (parser->prev_msg_type != msg_type)
304					input_ch = 0;
305				else
306					++input_ch;
307
308				if (input_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_INPUT_COUNT) {
309					switch (msg_type) {
310					case INPUT_GAIN_AND_INVERT:
311						if (param->input.gain_and_invert[input_ch] != val) {
312							queue_event(motu, msg_type, input_ch, 0, val);
313							param->input.gain_and_invert[input_ch] = val;
314						}
315						break;
316					case INPUT_FLAG:
317						if (param->input.flag[input_ch] != val) {
318							queue_event(motu, msg_type, input_ch, 0, val);
319							param->input.flag[input_ch] = val;
320						}
321						break;
322					default:
323						break;
324					}
325					parser->input_ch = input_ch;
326				}
327				break;
328			}
329			case UNKNOWN_0:
330			case UNKNOWN_2:
331				break;
332			case METER:
333			{
334				u8 pos;
335
336				if (!meter_pos_quirk)
337					pos = b[MSG_METER_IDX_POS];
338				else
339					pos = b[MSG_METER_IDX_POS_4PRE_AE];
340
341				if (pos < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_INPUT_COUNT) {
342					parser->meter.data[pos] = val;
343				} else if (pos >= 0x80) {
344					pos -= (0x80 - SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_INPUT_COUNT);
345
346					if (pos < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_COUNT)
347						parser->meter.data[pos] = val;
348				}
349
350				// The message for meter is interruptible to the series of other
351				// types of messages. Don't cache it.
352				fallthrough;
353			}
354			case INVALID:
355			default:
356				// Don't cache it.
357				continue;
358			}
359
360			parser->prev_msg_type = msg_type;
361		}
362	}
363
364	if (pos != parser->push_pos)
365		wake_up(&motu->hwdep_wait);
366
367	spin_unlock_irqrestore(&parser->lock, flags);
368}
369
370void snd_motu_register_dsp_message_parser_copy_meter(struct snd_motu *motu,
371						struct snd_firewire_motu_register_dsp_meter *meter)
372{
373	struct msg_parser *parser = motu->message_parser;
374	unsigned long flags;
375
376	spin_lock_irqsave(&parser->lock, flags);
377	memcpy(meter, &parser->meter, sizeof(*meter));
378	spin_unlock_irqrestore(&parser->lock, flags);
379}
380
381void snd_motu_register_dsp_message_parser_copy_parameter(struct snd_motu *motu,
382					struct snd_firewire_motu_register_dsp_parameter *param)
383{
384	struct msg_parser *parser = motu->message_parser;
385	unsigned long flags;
386
387	spin_lock_irqsave(&parser->lock, flags);
388	memcpy(param, &parser->param, sizeof(*param));
389	spin_unlock_irqrestore(&parser->lock, flags);
390}
391
392unsigned int snd_motu_register_dsp_message_parser_count_event(struct snd_motu *motu)
393{
394	struct msg_parser *parser = motu->message_parser;
395
396	if (parser->pull_pos > parser->push_pos)
397		return EVENT_QUEUE_SIZE - parser->pull_pos + parser->push_pos;
398	else
399		return parser->push_pos - parser->pull_pos;
400}
401
402bool snd_motu_register_dsp_message_parser_copy_event(struct snd_motu *motu, u32 *event)
403{
404	struct msg_parser *parser = motu->message_parser;
405	unsigned int pos = parser->pull_pos;
406	unsigned long flags;
407
408	if (pos == parser->push_pos)
409		return false;
410
411	spin_lock_irqsave(&parser->lock, flags);
412
413	*event = parser->event_queue[pos];
414
415	++pos;
416	if (pos >= EVENT_QUEUE_SIZE)
417		pos = 0;
418	parser->pull_pos = pos;
419
420	spin_unlock_irqrestore(&parser->lock, flags);
421
422	return true;
423}
424