Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/firewire/motu/motu-command-dsp-message-parser.c
26424 views
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 <[email protected]>
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(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
175
void 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
186