190b28f3bSTakashi Sakamoto // SPDX-License-Identifier: GPL-2.0-only
290b28f3bSTakashi Sakamoto //
390b28f3bSTakashi Sakamoto // motu-command-dsp-message-parser.c - a part of driver for MOTU FireWire series
490b28f3bSTakashi Sakamoto //
590b28f3bSTakashi Sakamoto // Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp>
690b28f3bSTakashi Sakamoto 
790b28f3bSTakashi Sakamoto // Below models allow software to configure their DSP function by command transferred in
890b28f3bSTakashi Sakamoto // asynchronous transaction:
990b28f3bSTakashi Sakamoto //  * 828 mk3 (FireWire only and Hybrid)
1090b28f3bSTakashi Sakamoto //  * 896 mk3 (FireWire only and Hybrid)
1190b28f3bSTakashi Sakamoto //  * Ultralite mk3 (FireWire only and Hybrid)
1290b28f3bSTakashi Sakamoto //  * Traveler mk3
1390b28f3bSTakashi Sakamoto //  * Track 16
1490b28f3bSTakashi Sakamoto //
1590b28f3bSTakashi Sakamoto // Isochronous packets from the above models includes messages to report state of hardware meter.
1690b28f3bSTakashi Sakamoto 
1790b28f3bSTakashi Sakamoto #include "motu.h"
1890b28f3bSTakashi Sakamoto 
1990b28f3bSTakashi Sakamoto enum msg_parser_state {
2090b28f3bSTakashi Sakamoto 	INITIALIZED,
2190b28f3bSTakashi Sakamoto 	FRAGMENT_DETECTED,
2290b28f3bSTakashi Sakamoto 	AVAILABLE,
2390b28f3bSTakashi Sakamoto };
2490b28f3bSTakashi Sakamoto 
2590b28f3bSTakashi Sakamoto struct msg_parser {
2658b62ab7STakashi Sakamoto 	spinlock_t lock;
2790b28f3bSTakashi Sakamoto 	enum msg_parser_state state;
2890b28f3bSTakashi Sakamoto 	unsigned int interval;
2990b28f3bSTakashi Sakamoto 	unsigned int message_count;
3090b28f3bSTakashi Sakamoto 	unsigned int fragment_pos;
3190b28f3bSTakashi Sakamoto 	unsigned int value_index;
3290b28f3bSTakashi Sakamoto 	u64 value;
3390b28f3bSTakashi Sakamoto 	struct snd_firewire_motu_command_dsp_meter meter;
3490b28f3bSTakashi Sakamoto };
3590b28f3bSTakashi Sakamoto 
snd_motu_command_dsp_message_parser_new(struct snd_motu * motu)3690b28f3bSTakashi Sakamoto int snd_motu_command_dsp_message_parser_new(struct snd_motu *motu)
3790b28f3bSTakashi Sakamoto {
3890b28f3bSTakashi Sakamoto 	struct msg_parser *parser;
3990b28f3bSTakashi Sakamoto 
4090b28f3bSTakashi Sakamoto 	parser = devm_kzalloc(&motu->card->card_dev, sizeof(*parser), GFP_KERNEL);
4190b28f3bSTakashi Sakamoto 	if (!parser)
4290b28f3bSTakashi Sakamoto 		return -ENOMEM;
4358b62ab7STakashi Sakamoto 	spin_lock_init(&parser->lock);
4490b28f3bSTakashi Sakamoto 	motu->message_parser = parser;
4590b28f3bSTakashi Sakamoto 
4690b28f3bSTakashi Sakamoto 	return 0;
4790b28f3bSTakashi Sakamoto }
4890b28f3bSTakashi Sakamoto 
snd_motu_command_dsp_message_parser_init(struct snd_motu * motu,enum cip_sfc sfc)4990b28f3bSTakashi Sakamoto int snd_motu_command_dsp_message_parser_init(struct snd_motu *motu, enum cip_sfc sfc)
5090b28f3bSTakashi Sakamoto {
5190b28f3bSTakashi Sakamoto 	struct msg_parser *parser = motu->message_parser;
5290b28f3bSTakashi Sakamoto 
5390b28f3bSTakashi Sakamoto 	parser->state = INITIALIZED;
5490b28f3bSTakashi Sakamoto 
5590b28f3bSTakashi Sakamoto 	// All of data blocks don't have messages with meaningful information.
5690b28f3bSTakashi Sakamoto 	switch (sfc) {
5790b28f3bSTakashi Sakamoto 	case CIP_SFC_176400:
5890b28f3bSTakashi Sakamoto 	case CIP_SFC_192000:
5990b28f3bSTakashi Sakamoto 		parser->interval = 4;
6090b28f3bSTakashi Sakamoto 		break;
6190b28f3bSTakashi Sakamoto 	case CIP_SFC_88200:
6290b28f3bSTakashi Sakamoto 	case CIP_SFC_96000:
6390b28f3bSTakashi Sakamoto 		parser->interval = 2;
6490b28f3bSTakashi Sakamoto 		break;
6590b28f3bSTakashi Sakamoto 	case CIP_SFC_32000:
6690b28f3bSTakashi Sakamoto 	case CIP_SFC_44100:
6790b28f3bSTakashi Sakamoto 	case CIP_SFC_48000:
6890b28f3bSTakashi Sakamoto 	default:
6990b28f3bSTakashi Sakamoto 		parser->interval = 1;
7090b28f3bSTakashi Sakamoto 		break;
7190b28f3bSTakashi Sakamoto 	}
7290b28f3bSTakashi Sakamoto 
7390b28f3bSTakashi Sakamoto 	return 0;
7490b28f3bSTakashi Sakamoto }
7590b28f3bSTakashi Sakamoto 
7690b28f3bSTakashi Sakamoto #define FRAGMENT_POS			6
7790b28f3bSTakashi Sakamoto #define MIDI_BYTE_POS			7
7890b28f3bSTakashi Sakamoto #define MIDI_FLAG_POS			8
7990b28f3bSTakashi Sakamoto // One value of hardware meter consists of 4 messages.
8090b28f3bSTakashi Sakamoto #define FRAGMENTS_PER_VALUE		4
8190b28f3bSTakashi Sakamoto #define VALUES_AT_IMAGE_END		0xffffffffffffffff
8290b28f3bSTakashi Sakamoto 
snd_motu_command_dsp_message_parser_parse(const struct amdtp_stream * s,const struct pkt_desc * desc,unsigned int count)83*0cac60c7STakashi Sakamoto void snd_motu_command_dsp_message_parser_parse(const struct amdtp_stream *s,
84*0cac60c7STakashi Sakamoto 					const struct pkt_desc *desc, unsigned int count)
8590b28f3bSTakashi Sakamoto {
86*0cac60c7STakashi Sakamoto 	struct snd_motu *motu = container_of(s, struct snd_motu, tx_stream);
87*0cac60c7STakashi Sakamoto 	unsigned int data_block_quadlets = s->data_block_quadlets;
8890b28f3bSTakashi Sakamoto 	struct msg_parser *parser = motu->message_parser;
8990b28f3bSTakashi Sakamoto 	unsigned int interval = parser->interval;
9058b62ab7STakashi Sakamoto 	unsigned long flags;
9190b28f3bSTakashi Sakamoto 	int i;
9290b28f3bSTakashi Sakamoto 
9358b62ab7STakashi Sakamoto 	spin_lock_irqsave(&parser->lock, flags);
9458b62ab7STakashi Sakamoto 
95*0cac60c7STakashi Sakamoto 	for (i = 0; i < count; ++i) {
9690b28f3bSTakashi Sakamoto 		__be32 *buffer = desc->ctx_payload;
9790b28f3bSTakashi Sakamoto 		unsigned int data_blocks = desc->data_blocks;
9890b28f3bSTakashi Sakamoto 		int j;
9990b28f3bSTakashi Sakamoto 
100*0cac60c7STakashi Sakamoto 		desc = amdtp_stream_next_packet_desc(s, desc);
101*0cac60c7STakashi Sakamoto 
10290b28f3bSTakashi Sakamoto 		for (j = 0; j < data_blocks; ++j) {
10390b28f3bSTakashi Sakamoto 			u8 *b = (u8 *)buffer;
10490b28f3bSTakashi Sakamoto 			buffer += data_block_quadlets;
10590b28f3bSTakashi Sakamoto 
10690b28f3bSTakashi Sakamoto 			switch (parser->state) {
10790b28f3bSTakashi Sakamoto 			case INITIALIZED:
10890b28f3bSTakashi Sakamoto 			{
10990b28f3bSTakashi Sakamoto 				u8 fragment = b[FRAGMENT_POS];
11090b28f3bSTakashi Sakamoto 
11190b28f3bSTakashi Sakamoto 				if (fragment > 0) {
11290b28f3bSTakashi Sakamoto 					parser->value = fragment;
11390b28f3bSTakashi Sakamoto 					parser->message_count = 1;
11490b28f3bSTakashi Sakamoto 					parser->state = FRAGMENT_DETECTED;
11590b28f3bSTakashi Sakamoto 				}
11690b28f3bSTakashi Sakamoto 				break;
11790b28f3bSTakashi Sakamoto 			}
11890b28f3bSTakashi Sakamoto 			case FRAGMENT_DETECTED:
11990b28f3bSTakashi Sakamoto 			{
12090b28f3bSTakashi Sakamoto 				if (parser->message_count % interval == 0) {
12190b28f3bSTakashi Sakamoto 					u8 fragment = b[FRAGMENT_POS];
12290b28f3bSTakashi Sakamoto 
12390b28f3bSTakashi Sakamoto 					parser->value >>= 8;
12490b28f3bSTakashi Sakamoto 					parser->value |= (u64)fragment << 56;
12590b28f3bSTakashi Sakamoto 
12690b28f3bSTakashi Sakamoto 					if (parser->value == VALUES_AT_IMAGE_END) {
12790b28f3bSTakashi Sakamoto 						parser->state = AVAILABLE;
12890b28f3bSTakashi Sakamoto 						parser->fragment_pos = 0;
12990b28f3bSTakashi Sakamoto 						parser->value_index = 0;
13090b28f3bSTakashi Sakamoto 						parser->message_count = 0;
13190b28f3bSTakashi Sakamoto 					}
13290b28f3bSTakashi Sakamoto 				}
13390b28f3bSTakashi Sakamoto 				++parser->message_count;
13490b28f3bSTakashi Sakamoto 				break;
13590b28f3bSTakashi Sakamoto 			}
13690b28f3bSTakashi Sakamoto 			case AVAILABLE:
13790b28f3bSTakashi Sakamoto 			default:
13890b28f3bSTakashi Sakamoto 			{
13990b28f3bSTakashi Sakamoto 				if (parser->message_count % interval == 0) {
14090b28f3bSTakashi Sakamoto 					u8 fragment = b[FRAGMENT_POS];
14190b28f3bSTakashi Sakamoto 
14290b28f3bSTakashi Sakamoto 					parser->value >>= 8;
14390b28f3bSTakashi Sakamoto 					parser->value |= (u64)fragment << 56;
14490b28f3bSTakashi Sakamoto 					++parser->fragment_pos;
14590b28f3bSTakashi Sakamoto 
14690b28f3bSTakashi Sakamoto 					if (parser->fragment_pos == 4) {
147407359d4STakashi Sakamoto 						// Skip the last two quadlets since they could be
148407359d4STakashi Sakamoto 						// invalid value (0xffffffff) as floating point
149407359d4STakashi Sakamoto 						// number.
15090b28f3bSTakashi Sakamoto 						if (parser->value_index <
151407359d4STakashi Sakamoto 						    SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT - 2) {
15290b28f3bSTakashi Sakamoto 							u32 val = (u32)(parser->value >> 32);
15390b28f3bSTakashi Sakamoto 							parser->meter.data[parser->value_index] = val;
15490b28f3bSTakashi Sakamoto 						}
155407359d4STakashi Sakamoto 						++parser->value_index;
15690b28f3bSTakashi Sakamoto 						parser->fragment_pos = 0;
15790b28f3bSTakashi Sakamoto 					}
15890b28f3bSTakashi Sakamoto 
15990b28f3bSTakashi Sakamoto 					if (parser->value == VALUES_AT_IMAGE_END) {
16090b28f3bSTakashi Sakamoto 						parser->value_index = 0;
16190b28f3bSTakashi Sakamoto 						parser->fragment_pos = 0;
16290b28f3bSTakashi Sakamoto 						parser->message_count = 0;
16390b28f3bSTakashi Sakamoto 					}
16490b28f3bSTakashi Sakamoto 				}
16590b28f3bSTakashi Sakamoto 				++parser->message_count;
16690b28f3bSTakashi Sakamoto 				break;
16790b28f3bSTakashi Sakamoto 			}
16890b28f3bSTakashi Sakamoto 			}
16990b28f3bSTakashi Sakamoto 		}
17090b28f3bSTakashi Sakamoto 	}
17158b62ab7STakashi Sakamoto 
17258b62ab7STakashi Sakamoto 	spin_unlock_irqrestore(&parser->lock, flags);
17358b62ab7STakashi Sakamoto }
17458b62ab7STakashi Sakamoto 
snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu * motu,struct snd_firewire_motu_command_dsp_meter * meter)17558b62ab7STakashi Sakamoto void snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu *motu,
17658b62ab7STakashi Sakamoto 					struct snd_firewire_motu_command_dsp_meter *meter)
17758b62ab7STakashi Sakamoto {
17858b62ab7STakashi Sakamoto 	struct msg_parser *parser = motu->message_parser;
17958b62ab7STakashi Sakamoto 	unsigned long flags;
18058b62ab7STakashi Sakamoto 
18158b62ab7STakashi Sakamoto 	spin_lock_irqsave(&parser->lock, flags);
18258b62ab7STakashi Sakamoto 	memcpy(meter, &parser->meter, sizeof(*meter));
18358b62ab7STakashi Sakamoto 	spin_unlock_irqrestore(&parser->lock, flags);
18490b28f3bSTakashi Sakamoto }
185