Merge tag 'linux-watchdog-5.16-rc1' of git://www.linux-watchdog.org/linux-watchdog
[linux-2.6-microblaze.git] / sound / firewire / motu / motu-command-dsp-message-parser.c
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
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
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
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
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 }