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
19 enum msg_parser_state {
20 INITIALIZED,
21 FRAGMENT_DETECTED,
22 AVAILABLE,
23 };
24
25 struct 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
snd_motu_command_dsp_message_parser_new(struct snd_motu * motu)36 int 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
snd_motu_command_dsp_message_parser_init(struct snd_motu * motu,enum cip_sfc sfc)49 int 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
snd_motu_command_dsp_message_parser_parse(struct snd_motu * motu,const struct pkt_desc * descs,unsigned int desc_count,unsigned int data_block_quadlets)83 void snd_motu_command_dsp_message_parser_parse(struct snd_motu *motu, const struct pkt_desc *descs,
84 unsigned int desc_count, unsigned int data_block_quadlets)
85 {
86 struct msg_parser *parser = motu->message_parser;
87 unsigned int interval = parser->interval;
88 unsigned long flags;
89 int i;
90
91 spin_lock_irqsave(&parser->lock, flags);
92
93 for (i = 0; i < desc_count; ++i) {
94 const struct pkt_desc *desc = descs + i;
95 __be32 *buffer = desc->ctx_payload;
96 unsigned int data_blocks = desc->data_blocks;
97 int j;
98
99 for (j = 0; j < data_blocks; ++j) {
100 u8 *b = (u8 *)buffer;
101 buffer += data_block_quadlets;
102
103 switch (parser->state) {
104 case INITIALIZED:
105 {
106 u8 fragment = b[FRAGMENT_POS];
107
108 if (fragment > 0) {
109 parser->value = fragment;
110 parser->message_count = 1;
111 parser->state = FRAGMENT_DETECTED;
112 }
113 break;
114 }
115 case FRAGMENT_DETECTED:
116 {
117 if (parser->message_count % interval == 0) {
118 u8 fragment = b[FRAGMENT_POS];
119
120 parser->value >>= 8;
121 parser->value |= (u64)fragment << 56;
122
123 if (parser->value == VALUES_AT_IMAGE_END) {
124 parser->state = AVAILABLE;
125 parser->fragment_pos = 0;
126 parser->value_index = 0;
127 parser->message_count = 0;
128 }
129 }
130 ++parser->message_count;
131 break;
132 }
133 case AVAILABLE:
134 default:
135 {
136 if (parser->message_count % interval == 0) {
137 u8 fragment = b[FRAGMENT_POS];
138
139 parser->value >>= 8;
140 parser->value |= (u64)fragment << 56;
141 ++parser->fragment_pos;
142
143 if (parser->fragment_pos == 4) {
144 // Skip the last two quadlets since they could be
145 // invalid value (0xffffffff) as floating point
146 // number.
147 if (parser->value_index <
148 SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT - 2) {
149 u32 val = (u32)(parser->value >> 32);
150 parser->meter.data[parser->value_index] = val;
151 }
152 ++parser->value_index;
153 parser->fragment_pos = 0;
154 }
155
156 if (parser->value == VALUES_AT_IMAGE_END) {
157 parser->value_index = 0;
158 parser->fragment_pos = 0;
159 parser->message_count = 0;
160 }
161 }
162 ++parser->message_count;
163 break;
164 }
165 }
166 }
167 }
168
169 spin_unlock_irqrestore(&parser->lock, flags);
170 }
171
snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu * motu,struct snd_firewire_motu_command_dsp_meter * meter)172 void snd_motu_command_dsp_message_parser_copy_meter(struct snd_motu *motu,
173 struct snd_firewire_motu_command_dsp_meter *meter)
174 {
175 struct msg_parser *parser = motu->message_parser;
176 unsigned long flags;
177
178 spin_lock_irqsave(&parser->lock, flags);
179 memcpy(meter, &parser->meter, sizeof(*meter));
180 spin_unlock_irqrestore(&parser->lock, flags);
181 }
182