1// SPDX-License-Identifier: GPL-2.0-only
2//
3// motu-command-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 function by command transferred in
8// asynchronous transaction:
9//  * 828 mk3 (FireWire only and Hybrid)
10//  * 896 mk3 (FireWire only and Hybrid)
11//  * Ultralite mk3 (FireWire only and Hybrid)
12//  * Traveler mk3
13//  * Track 16
14//
15// Isochronous packets from the above models includes messages to report state of hardware meter.
16
17#include "motu.h"
18
19enum msg_parser_state {
20	INITIALIZED,
21	FRAGMENT_DETECTED,
22	AVAILABLE,
23};
24
25struct msg_parser {
26	spinlock_t lock;
27	enum msg_parser_state state;
28	unsigned int interval;
29	unsigned int message_count;
30	unsigned int fragment_pos;
31	unsigned int value_index;
32	u64 value;
33	struct snd_firewire_motu_command_dsp_meter meter;
34};
35
36int snd_motu_command_dsp_message_parser_new(struct snd_motu *motu)
37{
38	struct msg_parser *parser;
39
40	parser = devm_kzalloc(&motu->card->card_dev, sizeof(*parser), GFP_KERNEL);
41	if (!parser)
42		return -ENOMEM;
43	spin_lock_init(&parser->lock);
44	motu->message_parser = parser;
45
46	return 0;
47}
48
49int snd_motu_command_dsp_message_parser_init(struct snd_motu *motu, enum cip_sfc sfc)
50{
51	struct msg_parser *parser = motu->message_parser;
52
53	parser->state = INITIALIZED;
54
55	// All of data blocks don't have messages with meaningful information.
56	switch (sfc) {
57	case CIP_SFC_176400:
58	case CIP_SFC_192000:
59		parser->interval = 4;
60		break;
61	case CIP_SFC_88200:
62	case CIP_SFC_96000:
63		parser->interval = 2;
64		break;
65	case CIP_SFC_32000:
66	case CIP_SFC_44100:
67	case CIP_SFC_48000:
68	default:
69		parser->interval = 1;
70		break;
71	}
72
73	return 0;
74}
75
76#define FRAGMENT_POS			6
77#define MIDI_BYTE_POS			7
78#define MIDI_FLAG_POS			8
79// One value of hardware meter consists of 4 messages.
80#define FRAGMENTS_PER_VALUE		4
81#define VALUES_AT_IMAGE_END		0xffffffffffffffff
82
83void snd_motu_command_dsp_message_parser_parse(const struct amdtp_stream *s,
84					const struct pkt_desc *desc, unsigned int count)
85{
86	struct snd_motu *motu = container_of(s, struct snd_motu, tx_stream);
87	unsigned int data_block_quadlets = s->data_block_quadlets;
88	struct msg_parser *parser = motu->message_parser;
89	unsigned int interval = parser->interval;
90	unsigned long flags;
91	int i;
92
93	spin_lock_irqsave(&parser->lock, flags);
94
95	for (i = 0; i < count; ++i) {
96		__be32 *buffer = desc->ctx_payload;
97		unsigned int data_blocks = desc->data_blocks;
98		int j;
99
100		desc = amdtp_stream_next_packet_desc(s, desc);
101
102		for (j = 0; j < data_blocks; ++j) {
103			u8 *b = (u8 *)buffer;
104			buffer += data_block_quadlets;
105
106			switch (parser->state) {
107			case INITIALIZED:
108			{
109				u8 fragment = b[FRAGMENT_POS];
110
111				if (fragment > 0) {
112					parser->value = fragment;
113					parser->message_count = 1;
114					parser->state = FRAGMENT_DETECTED;
115				}
116				break;
117			}
118			case FRAGMENT_DETECTED:
119			{
120				if (parser->message_count % interval == 0) {
121					u8 fragment = b[FRAGMENT_POS];
122
123					parser->value >>= 8;
124					parser->value |= (u64)fragment << 56;
125
126					if (parser->value == VALUES_AT_IMAGE_END) {
127						parser->state = AVAILABLE;
128						parser->fragment_pos = 0;
129						parser->value_index = 0;
130						parser->message_count = 0;
131					}
132				}
133				++parser->message_count;
134				break;
135			}
136			case AVAILABLE:
137			default:
138			{
139				if (parser->message_count % interval == 0) {
140					u8 fragment = b[FRAGMENT_POS];
141
142					parser->value >>= 8;
143					parser->value |= (u64)fragment << 56;
144					++parser->fragment_pos;
145
146					if (parser->fragment_pos == 4) {
147						// Skip the last two quadlets since they could be
148						// invalid value (0xffffffff) as floating point
149						// number.
150						if (parser->value_index <
151						    SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT - 2) {
152							u32 val = (u32)(parser->value >> 32);
153							parser->meter.data[parser->value_index] = val;
154						}
155						++parser->value_index;
156						parser->fragment_pos = 0;
157					}
158
159					if (parser->value == VALUES_AT_IMAGE_END) {
160						parser->value_index = 0;
161						parser->fragment_pos = 0;
162						parser->message_count = 0;
163					}
164				}
165				++parser->message_count;
166				break;
167			}
168			}
169		}
170	}
171
172	spin_unlock_irqrestore(&parser->lock, flags);
173}
174
175void snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu *motu,
176					struct snd_firewire_motu_command_dsp_meter *meter)
177{
178	struct msg_parser *parser = motu->message_parser;
179	unsigned long flags;
180
181	spin_lock_irqsave(&parser->lock, flags);
182	memcpy(meter, &parser->meter, sizeof(*meter));
183	spin_unlock_irqrestore(&parser->lock, flags);
184}
185