162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// motu-register-dsp-message-parser.c - a part of driver for MOTU FireWire series
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci// Below models allow software to configure their DSP functions by asynchronous transaction
862306a36Sopenharmony_ci// to access their internal registers.
962306a36Sopenharmony_ci// * 828 mk2
1062306a36Sopenharmony_ci// * 896hd
1162306a36Sopenharmony_ci// * Traveler
1262306a36Sopenharmony_ci// * 8 pre
1362306a36Sopenharmony_ci// * Ultralite
1462306a36Sopenharmony_ci// * 4 pre
1562306a36Sopenharmony_ci// * Audio Express
1662306a36Sopenharmony_ci//
1762306a36Sopenharmony_ci// Additionally, isochronous packets from the above models include messages to notify state of
1862306a36Sopenharmony_ci// DSP. The messages are two set of 3 byte data in 2nd and 3rd quadlet of data block. When user
1962306a36Sopenharmony_ci// operates hardware components such as dial and switch, corresponding messages are transferred.
2062306a36Sopenharmony_ci// The messages include Hardware metering and MIDI messages as well.
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "motu.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define MSG_FLAG_POS                    4
2562306a36Sopenharmony_ci#define MSG_FLAG_TYPE_MASK              0xf8
2662306a36Sopenharmony_ci#define MSG_FLAG_MIDI_MASK              0x01
2762306a36Sopenharmony_ci#define MSG_FLAG_MODEL_SPECIFIC_MASK    0x06
2862306a36Sopenharmony_ci#define   MSG_FLAG_8PRE                 0x00
2962306a36Sopenharmony_ci#define   MSG_FLAG_ULTRALITE            0x04
3062306a36Sopenharmony_ci#define   MSG_FLAG_TRAVELER             0x04
3162306a36Sopenharmony_ci#define   MSG_FLAG_828MK2               0x04
3262306a36Sopenharmony_ci#define   MSG_FLAG_896HD                0x04
3362306a36Sopenharmony_ci#define   MSG_FLAG_4PRE                 0x05 // MIDI mask is in 8th byte.
3462306a36Sopenharmony_ci#define   MSG_FLAG_AUDIOEXPRESS         0x05 // MIDI mask is in 8th byte.
3562306a36Sopenharmony_ci#define MSG_FLAG_TYPE_SHIFT             3
3662306a36Sopenharmony_ci#define MSG_VALUE_POS                   5
3762306a36Sopenharmony_ci#define MSG_MIDI_BYTE_POS		6
3862306a36Sopenharmony_ci#define MSG_METER_IDX_POS               7
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci// In 4 pre and Audio express, meter index is in 6th byte. MIDI flag is in 8th byte and MIDI byte
4162306a36Sopenharmony_ci// is in 7th byte.
4262306a36Sopenharmony_ci#define MSG_METER_IDX_POS_4PRE_AE	6
4362306a36Sopenharmony_ci#define MSG_MIDI_BYTE_POS_4PRE_AE	7
4462306a36Sopenharmony_ci#define MSG_FLAG_MIDI_POS_4PRE_AE	8
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cienum register_dsp_msg_type {
4762306a36Sopenharmony_ci	// Used for messages with no information.
4862306a36Sopenharmony_ci	INVALID = 0x00,
4962306a36Sopenharmony_ci	MIXER_SELECT = 0x01,
5062306a36Sopenharmony_ci	MIXER_SRC_GAIN = 0x02,
5162306a36Sopenharmony_ci	MIXER_SRC_PAN = 0x03,
5262306a36Sopenharmony_ci	MIXER_SRC_FLAG = 0x04,
5362306a36Sopenharmony_ci	MIXER_OUTPUT_PAIRED_VOLUME = 0x05,
5462306a36Sopenharmony_ci	MIXER_OUTPUT_PAIRED_FLAG = 0x06,
5562306a36Sopenharmony_ci	MAIN_OUTPUT_PAIRED_VOLUME = 0x07,
5662306a36Sopenharmony_ci	HP_OUTPUT_PAIRED_VOLUME = 0x08,
5762306a36Sopenharmony_ci	HP_OUTPUT_PAIRED_ASSIGNMENT = 0x09,
5862306a36Sopenharmony_ci	// Transferred by all models but the purpose is still unknown.
5962306a36Sopenharmony_ci	UNKNOWN_0 = 0x0a,
6062306a36Sopenharmony_ci	// Specific to 828mk2, 896hd, Traveler.
6162306a36Sopenharmony_ci	UNKNOWN_2 = 0x0c,
6262306a36Sopenharmony_ci	// Specific to 828mk2, Traveler, and 896hd (not functional).
6362306a36Sopenharmony_ci	LINE_INPUT_BOOST = 0x0d,
6462306a36Sopenharmony_ci	// Specific to 828mk2, Traveler, and 896hd (not functional).
6562306a36Sopenharmony_ci	LINE_INPUT_NOMINAL_LEVEL = 0x0e,
6662306a36Sopenharmony_ci	// Specific to Ultralite, 4 pre, Audio express, and 8 pre (not functional).
6762306a36Sopenharmony_ci	INPUT_GAIN_AND_INVERT = 0x15,
6862306a36Sopenharmony_ci	// Specific to 4 pre, and Audio express.
6962306a36Sopenharmony_ci	INPUT_FLAG = 0x16,
7062306a36Sopenharmony_ci	// Specific to 4 pre, and Audio express.
7162306a36Sopenharmony_ci	MIXER_SRC_PAIRED_BALANCE = 0x17,
7262306a36Sopenharmony_ci	// Specific to 4 pre, and Audio express.
7362306a36Sopenharmony_ci	MIXER_SRC_PAIRED_WIDTH = 0x18,
7462306a36Sopenharmony_ci	// Transferred by all models. This type of message interposes the series of the other
7562306a36Sopenharmony_ci	// messages. The message delivers signal level up to 96.0 kHz. In 828mk2, 896hd, and
7662306a36Sopenharmony_ci	// Traveler, one of physical outputs is selected for the message. The selection is done
7762306a36Sopenharmony_ci	// by LSB one byte in asynchronous write quadlet transaction to 0x'ffff'f000'0b2c.
7862306a36Sopenharmony_ci	METER = 0x1f,
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define EVENT_QUEUE_SIZE	16
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistruct msg_parser {
8462306a36Sopenharmony_ci	spinlock_t lock;
8562306a36Sopenharmony_ci	struct snd_firewire_motu_register_dsp_meter meter;
8662306a36Sopenharmony_ci	bool meter_pos_quirk;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	struct snd_firewire_motu_register_dsp_parameter param;
8962306a36Sopenharmony_ci	u8 prev_mixer_src_type;
9062306a36Sopenharmony_ci	u8 mixer_ch;
9162306a36Sopenharmony_ci	u8 mixer_src_ch;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	u8 input_ch;
9462306a36Sopenharmony_ci	u8 prev_msg_type;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	u32 event_queue[EVENT_QUEUE_SIZE];
9762306a36Sopenharmony_ci	unsigned int push_pos;
9862306a36Sopenharmony_ci	unsigned int pull_pos;
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ciint snd_motu_register_dsp_message_parser_new(struct snd_motu *motu)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	struct msg_parser *parser;
10462306a36Sopenharmony_ci	parser = devm_kzalloc(&motu->card->card_dev, sizeof(*parser), GFP_KERNEL);
10562306a36Sopenharmony_ci	if (!parser)
10662306a36Sopenharmony_ci		return -ENOMEM;
10762306a36Sopenharmony_ci	spin_lock_init(&parser->lock);
10862306a36Sopenharmony_ci	if (motu->spec == &snd_motu_spec_4pre || motu->spec == &snd_motu_spec_audio_express)
10962306a36Sopenharmony_ci		parser->meter_pos_quirk = true;
11062306a36Sopenharmony_ci	motu->message_parser = parser;
11162306a36Sopenharmony_ci	return 0;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ciint snd_motu_register_dsp_message_parser_init(struct snd_motu *motu)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct msg_parser *parser = motu->message_parser;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	parser->prev_mixer_src_type = INVALID;
11962306a36Sopenharmony_ci	parser->mixer_ch = 0xff;
12062306a36Sopenharmony_ci	parser->mixer_src_ch = 0xff;
12162306a36Sopenharmony_ci	parser->prev_msg_type = INVALID;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	return 0;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci// Rough implementaion of queue without overrun check.
12762306a36Sopenharmony_cistatic void queue_event(struct snd_motu *motu, u8 msg_type, u8 identifier0, u8 identifier1, u8 val)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct msg_parser *parser = motu->message_parser;
13062306a36Sopenharmony_ci	unsigned int pos = parser->push_pos;
13162306a36Sopenharmony_ci	u32 entry;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (!motu->hwdep || motu->hwdep->used == 0)
13462306a36Sopenharmony_ci		return;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	entry = (msg_type << 24) | (identifier0 << 16) | (identifier1 << 8) | val;
13762306a36Sopenharmony_ci	parser->event_queue[pos] = entry;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	++pos;
14062306a36Sopenharmony_ci	if (pos >= EVENT_QUEUE_SIZE)
14162306a36Sopenharmony_ci		pos = 0;
14262306a36Sopenharmony_ci	parser->push_pos = pos;
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_civoid snd_motu_register_dsp_message_parser_parse(const struct amdtp_stream *s,
14662306a36Sopenharmony_ci						const struct pkt_desc *desc, unsigned int count)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct snd_motu *motu = container_of(s, struct snd_motu, tx_stream);
14962306a36Sopenharmony_ci	unsigned int data_block_quadlets = s->data_block_quadlets;
15062306a36Sopenharmony_ci	struct msg_parser *parser = motu->message_parser;
15162306a36Sopenharmony_ci	bool meter_pos_quirk = parser->meter_pos_quirk;
15262306a36Sopenharmony_ci	unsigned int pos = parser->push_pos;
15362306a36Sopenharmony_ci	unsigned long flags;
15462306a36Sopenharmony_ci	int i;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	spin_lock_irqsave(&parser->lock, flags);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	for (i = 0; i < count; ++i) {
15962306a36Sopenharmony_ci		__be32 *buffer = desc->ctx_payload;
16062306a36Sopenharmony_ci		unsigned int data_blocks = desc->data_blocks;
16162306a36Sopenharmony_ci		int j;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci		desc = amdtp_stream_next_packet_desc(s, desc);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci		for (j = 0; j < data_blocks; ++j) {
16662306a36Sopenharmony_ci			u8 *b = (u8 *)buffer;
16762306a36Sopenharmony_ci			u8 msg_type = (b[MSG_FLAG_POS] & MSG_FLAG_TYPE_MASK) >> MSG_FLAG_TYPE_SHIFT;
16862306a36Sopenharmony_ci			u8 val = b[MSG_VALUE_POS];
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci			buffer += data_block_quadlets;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci			switch (msg_type) {
17362306a36Sopenharmony_ci			case MIXER_SELECT:
17462306a36Sopenharmony_ci			{
17562306a36Sopenharmony_ci				u8 mixer_ch = val / 0x20;
17662306a36Sopenharmony_ci				if (mixer_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_COUNT) {
17762306a36Sopenharmony_ci					parser->mixer_src_ch = 0;
17862306a36Sopenharmony_ci					parser->mixer_ch = mixer_ch;
17962306a36Sopenharmony_ci				}
18062306a36Sopenharmony_ci				break;
18162306a36Sopenharmony_ci			}
18262306a36Sopenharmony_ci			case MIXER_SRC_GAIN:
18362306a36Sopenharmony_ci			case MIXER_SRC_PAN:
18462306a36Sopenharmony_ci			case MIXER_SRC_FLAG:
18562306a36Sopenharmony_ci			case MIXER_SRC_PAIRED_BALANCE:
18662306a36Sopenharmony_ci			case MIXER_SRC_PAIRED_WIDTH:
18762306a36Sopenharmony_ci			{
18862306a36Sopenharmony_ci				struct snd_firewire_motu_register_dsp_parameter *param = &parser->param;
18962306a36Sopenharmony_ci				u8 mixer_ch = parser->mixer_ch;
19062306a36Sopenharmony_ci				u8 mixer_src_ch = parser->mixer_src_ch;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci				if (msg_type != parser->prev_mixer_src_type)
19362306a36Sopenharmony_ci					mixer_src_ch = 0;
19462306a36Sopenharmony_ci				else
19562306a36Sopenharmony_ci					++mixer_src_ch;
19662306a36Sopenharmony_ci				parser->prev_mixer_src_type = msg_type;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci				if (mixer_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_COUNT &&
19962306a36Sopenharmony_ci				    mixer_src_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_SRC_COUNT) {
20062306a36Sopenharmony_ci					u8 mixer_ch = parser->mixer_ch;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci					switch (msg_type) {
20362306a36Sopenharmony_ci					case MIXER_SRC_GAIN:
20462306a36Sopenharmony_ci						if (param->mixer.source[mixer_ch].gain[mixer_src_ch] != val) {
20562306a36Sopenharmony_ci							queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val);
20662306a36Sopenharmony_ci							param->mixer.source[mixer_ch].gain[mixer_src_ch] = val;
20762306a36Sopenharmony_ci						}
20862306a36Sopenharmony_ci						break;
20962306a36Sopenharmony_ci					case MIXER_SRC_PAN:
21062306a36Sopenharmony_ci						if (param->mixer.source[mixer_ch].pan[mixer_src_ch] != val) {
21162306a36Sopenharmony_ci							queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val);
21262306a36Sopenharmony_ci							param->mixer.source[mixer_ch].pan[mixer_src_ch] = val;
21362306a36Sopenharmony_ci						}
21462306a36Sopenharmony_ci						break;
21562306a36Sopenharmony_ci					case MIXER_SRC_FLAG:
21662306a36Sopenharmony_ci						if (param->mixer.source[mixer_ch].flag[mixer_src_ch] != val) {
21762306a36Sopenharmony_ci							queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val);
21862306a36Sopenharmony_ci							param->mixer.source[mixer_ch].flag[mixer_src_ch] = val;
21962306a36Sopenharmony_ci						}
22062306a36Sopenharmony_ci						break;
22162306a36Sopenharmony_ci					case MIXER_SRC_PAIRED_BALANCE:
22262306a36Sopenharmony_ci						if (param->mixer.source[mixer_ch].paired_balance[mixer_src_ch] != val) {
22362306a36Sopenharmony_ci							queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val);
22462306a36Sopenharmony_ci							param->mixer.source[mixer_ch].paired_balance[mixer_src_ch] = val;
22562306a36Sopenharmony_ci						}
22662306a36Sopenharmony_ci						break;
22762306a36Sopenharmony_ci					case MIXER_SRC_PAIRED_WIDTH:
22862306a36Sopenharmony_ci						if (param->mixer.source[mixer_ch].paired_width[mixer_src_ch] != val) {
22962306a36Sopenharmony_ci							queue_event(motu, msg_type, mixer_ch, mixer_src_ch, val);
23062306a36Sopenharmony_ci							param->mixer.source[mixer_ch].paired_width[mixer_src_ch] = val;
23162306a36Sopenharmony_ci						}
23262306a36Sopenharmony_ci						break;
23362306a36Sopenharmony_ci					default:
23462306a36Sopenharmony_ci						break;
23562306a36Sopenharmony_ci					}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci					parser->mixer_src_ch = mixer_src_ch;
23862306a36Sopenharmony_ci				}
23962306a36Sopenharmony_ci				break;
24062306a36Sopenharmony_ci			}
24162306a36Sopenharmony_ci			case MIXER_OUTPUT_PAIRED_VOLUME:
24262306a36Sopenharmony_ci			case MIXER_OUTPUT_PAIRED_FLAG:
24362306a36Sopenharmony_ci			{
24462306a36Sopenharmony_ci				struct snd_firewire_motu_register_dsp_parameter *param = &parser->param;
24562306a36Sopenharmony_ci				u8 mixer_ch = parser->mixer_ch;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci				if (mixer_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_MIXER_COUNT) {
24862306a36Sopenharmony_ci					switch (msg_type) {
24962306a36Sopenharmony_ci					case MIXER_OUTPUT_PAIRED_VOLUME:
25062306a36Sopenharmony_ci						if (param->mixer.output.paired_volume[mixer_ch] != val) {
25162306a36Sopenharmony_ci							queue_event(motu, msg_type, mixer_ch, 0, val);
25262306a36Sopenharmony_ci							param->mixer.output.paired_volume[mixer_ch] = val;
25362306a36Sopenharmony_ci						}
25462306a36Sopenharmony_ci						break;
25562306a36Sopenharmony_ci					case MIXER_OUTPUT_PAIRED_FLAG:
25662306a36Sopenharmony_ci						if (param->mixer.output.paired_flag[mixer_ch] != val) {
25762306a36Sopenharmony_ci							queue_event(motu, msg_type, mixer_ch, 0, val);
25862306a36Sopenharmony_ci							param->mixer.output.paired_flag[mixer_ch] = val;
25962306a36Sopenharmony_ci						}
26062306a36Sopenharmony_ci						break;
26162306a36Sopenharmony_ci					default:
26262306a36Sopenharmony_ci						break;
26362306a36Sopenharmony_ci					}
26462306a36Sopenharmony_ci				}
26562306a36Sopenharmony_ci				break;
26662306a36Sopenharmony_ci			}
26762306a36Sopenharmony_ci			case MAIN_OUTPUT_PAIRED_VOLUME:
26862306a36Sopenharmony_ci				if (parser->param.output.main_paired_volume != val) {
26962306a36Sopenharmony_ci					queue_event(motu, msg_type, 0, 0, val);
27062306a36Sopenharmony_ci					parser->param.output.main_paired_volume = val;
27162306a36Sopenharmony_ci				}
27262306a36Sopenharmony_ci				break;
27362306a36Sopenharmony_ci			case HP_OUTPUT_PAIRED_VOLUME:
27462306a36Sopenharmony_ci				if (parser->param.output.hp_paired_volume != val) {
27562306a36Sopenharmony_ci					queue_event(motu, msg_type, 0, 0, val);
27662306a36Sopenharmony_ci					parser->param.output.hp_paired_volume = val;
27762306a36Sopenharmony_ci				}
27862306a36Sopenharmony_ci				break;
27962306a36Sopenharmony_ci			case HP_OUTPUT_PAIRED_ASSIGNMENT:
28062306a36Sopenharmony_ci				if (parser->param.output.hp_paired_assignment != val) {
28162306a36Sopenharmony_ci					queue_event(motu, msg_type, 0, 0, val);
28262306a36Sopenharmony_ci					parser->param.output.hp_paired_assignment = val;
28362306a36Sopenharmony_ci				}
28462306a36Sopenharmony_ci				break;
28562306a36Sopenharmony_ci			case LINE_INPUT_BOOST:
28662306a36Sopenharmony_ci				if (parser->param.line_input.boost_flag != val) {
28762306a36Sopenharmony_ci					queue_event(motu, msg_type, 0, 0, val);
28862306a36Sopenharmony_ci					parser->param.line_input.boost_flag = val;
28962306a36Sopenharmony_ci				}
29062306a36Sopenharmony_ci				break;
29162306a36Sopenharmony_ci			case LINE_INPUT_NOMINAL_LEVEL:
29262306a36Sopenharmony_ci				if (parser->param.line_input.nominal_level_flag != val) {
29362306a36Sopenharmony_ci					queue_event(motu, msg_type, 0, 0, val);
29462306a36Sopenharmony_ci					parser->param.line_input.nominal_level_flag = val;
29562306a36Sopenharmony_ci				}
29662306a36Sopenharmony_ci				break;
29762306a36Sopenharmony_ci			case INPUT_GAIN_AND_INVERT:
29862306a36Sopenharmony_ci			case INPUT_FLAG:
29962306a36Sopenharmony_ci			{
30062306a36Sopenharmony_ci				struct snd_firewire_motu_register_dsp_parameter *param = &parser->param;
30162306a36Sopenharmony_ci				u8 input_ch = parser->input_ch;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci				if (parser->prev_msg_type != msg_type)
30462306a36Sopenharmony_ci					input_ch = 0;
30562306a36Sopenharmony_ci				else
30662306a36Sopenharmony_ci					++input_ch;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci				if (input_ch < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_INPUT_COUNT) {
30962306a36Sopenharmony_ci					switch (msg_type) {
31062306a36Sopenharmony_ci					case INPUT_GAIN_AND_INVERT:
31162306a36Sopenharmony_ci						if (param->input.gain_and_invert[input_ch] != val) {
31262306a36Sopenharmony_ci							queue_event(motu, msg_type, input_ch, 0, val);
31362306a36Sopenharmony_ci							param->input.gain_and_invert[input_ch] = val;
31462306a36Sopenharmony_ci						}
31562306a36Sopenharmony_ci						break;
31662306a36Sopenharmony_ci					case INPUT_FLAG:
31762306a36Sopenharmony_ci						if (param->input.flag[input_ch] != val) {
31862306a36Sopenharmony_ci							queue_event(motu, msg_type, input_ch, 0, val);
31962306a36Sopenharmony_ci							param->input.flag[input_ch] = val;
32062306a36Sopenharmony_ci						}
32162306a36Sopenharmony_ci						break;
32262306a36Sopenharmony_ci					default:
32362306a36Sopenharmony_ci						break;
32462306a36Sopenharmony_ci					}
32562306a36Sopenharmony_ci					parser->input_ch = input_ch;
32662306a36Sopenharmony_ci				}
32762306a36Sopenharmony_ci				break;
32862306a36Sopenharmony_ci			}
32962306a36Sopenharmony_ci			case UNKNOWN_0:
33062306a36Sopenharmony_ci			case UNKNOWN_2:
33162306a36Sopenharmony_ci				break;
33262306a36Sopenharmony_ci			case METER:
33362306a36Sopenharmony_ci			{
33462306a36Sopenharmony_ci				u8 pos;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci				if (!meter_pos_quirk)
33762306a36Sopenharmony_ci					pos = b[MSG_METER_IDX_POS];
33862306a36Sopenharmony_ci				else
33962306a36Sopenharmony_ci					pos = b[MSG_METER_IDX_POS_4PRE_AE];
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci				if (pos < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_INPUT_COUNT) {
34262306a36Sopenharmony_ci					parser->meter.data[pos] = val;
34362306a36Sopenharmony_ci				} else if (pos >= 0x80) {
34462306a36Sopenharmony_ci					pos -= (0x80 - SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_INPUT_COUNT);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci					if (pos < SNDRV_FIREWIRE_MOTU_REGISTER_DSP_METER_COUNT)
34762306a36Sopenharmony_ci						parser->meter.data[pos] = val;
34862306a36Sopenharmony_ci				}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci				// The message for meter is interruptible to the series of other
35162306a36Sopenharmony_ci				// types of messages. Don't cache it.
35262306a36Sopenharmony_ci				fallthrough;
35362306a36Sopenharmony_ci			}
35462306a36Sopenharmony_ci			case INVALID:
35562306a36Sopenharmony_ci			default:
35662306a36Sopenharmony_ci				// Don't cache it.
35762306a36Sopenharmony_ci				continue;
35862306a36Sopenharmony_ci			}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci			parser->prev_msg_type = msg_type;
36162306a36Sopenharmony_ci		}
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (pos != parser->push_pos)
36562306a36Sopenharmony_ci		wake_up(&motu->hwdep_wait);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	spin_unlock_irqrestore(&parser->lock, flags);
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_civoid snd_motu_register_dsp_message_parser_copy_meter(struct snd_motu *motu,
37162306a36Sopenharmony_ci						struct snd_firewire_motu_register_dsp_meter *meter)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	struct msg_parser *parser = motu->message_parser;
37462306a36Sopenharmony_ci	unsigned long flags;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	spin_lock_irqsave(&parser->lock, flags);
37762306a36Sopenharmony_ci	memcpy(meter, &parser->meter, sizeof(*meter));
37862306a36Sopenharmony_ci	spin_unlock_irqrestore(&parser->lock, flags);
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_civoid snd_motu_register_dsp_message_parser_copy_parameter(struct snd_motu *motu,
38262306a36Sopenharmony_ci					struct snd_firewire_motu_register_dsp_parameter *param)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	struct msg_parser *parser = motu->message_parser;
38562306a36Sopenharmony_ci	unsigned long flags;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	spin_lock_irqsave(&parser->lock, flags);
38862306a36Sopenharmony_ci	memcpy(param, &parser->param, sizeof(*param));
38962306a36Sopenharmony_ci	spin_unlock_irqrestore(&parser->lock, flags);
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ciunsigned int snd_motu_register_dsp_message_parser_count_event(struct snd_motu *motu)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	struct msg_parser *parser = motu->message_parser;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (parser->pull_pos > parser->push_pos)
39762306a36Sopenharmony_ci		return EVENT_QUEUE_SIZE - parser->pull_pos + parser->push_pos;
39862306a36Sopenharmony_ci	else
39962306a36Sopenharmony_ci		return parser->push_pos - parser->pull_pos;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cibool snd_motu_register_dsp_message_parser_copy_event(struct snd_motu *motu, u32 *event)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct msg_parser *parser = motu->message_parser;
40562306a36Sopenharmony_ci	unsigned int pos = parser->pull_pos;
40662306a36Sopenharmony_ci	unsigned long flags;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (pos == parser->push_pos)
40962306a36Sopenharmony_ci		return false;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	spin_lock_irqsave(&parser->lock, flags);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	*event = parser->event_queue[pos];
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	++pos;
41662306a36Sopenharmony_ci	if (pos >= EVENT_QUEUE_SIZE)
41762306a36Sopenharmony_ci		pos = 0;
41862306a36Sopenharmony_ci	parser->pull_pos = pos;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	spin_unlock_irqrestore(&parser->lock, flags);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	return true;
42362306a36Sopenharmony_ci}
424