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
29266 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
int i;
91
92
guard(spinlock_irqsave)(&parser->lock);
93
94
for (i = 0; i < count; ++i) {
95
__be32 *buffer = desc->ctx_payload;
96
unsigned int data_blocks = desc->data_blocks;
97
int j;
98
99
desc = amdtp_stream_next_packet_desc(s, desc);
100
101
for (j = 0; j < data_blocks; ++j) {
102
u8 *b = (u8 *)buffer;
103
buffer += data_block_quadlets;
104
105
switch (parser->state) {
106
case INITIALIZED:
107
{
108
u8 fragment = b[FRAGMENT_POS];
109
110
if (fragment > 0) {
111
parser->value = fragment;
112
parser->message_count = 1;
113
parser->state = FRAGMENT_DETECTED;
114
}
115
break;
116
}
117
case FRAGMENT_DETECTED:
118
{
119
if (parser->message_count % interval == 0) {
120
u8 fragment = b[FRAGMENT_POS];
121
122
parser->value >>= 8;
123
parser->value |= (u64)fragment << 56;
124
125
if (parser->value == VALUES_AT_IMAGE_END) {
126
parser->state = AVAILABLE;
127
parser->fragment_pos = 0;
128
parser->value_index = 0;
129
parser->message_count = 0;
130
}
131
}
132
++parser->message_count;
133
break;
134
}
135
case AVAILABLE:
136
default:
137
{
138
if (parser->message_count % interval == 0) {
139
u8 fragment = b[FRAGMENT_POS];
140
141
parser->value >>= 8;
142
parser->value |= (u64)fragment << 56;
143
++parser->fragment_pos;
144
145
if (parser->fragment_pos == 4) {
146
// Skip the last two quadlets since they could be
147
// invalid value (0xffffffff) as floating point
148
// number.
149
if (parser->value_index <
150
SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT - 2) {
151
u32 val = (u32)(parser->value >> 32);
152
parser->meter.data[parser->value_index] = val;
153
}
154
++parser->value_index;
155
parser->fragment_pos = 0;
156
}
157
158
if (parser->value == VALUES_AT_IMAGE_END) {
159
parser->value_index = 0;
160
parser->fragment_pos = 0;
161
parser->message_count = 0;
162
}
163
}
164
++parser->message_count;
165
break;
166
}
167
}
168
}
169
}
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
177
guard(spinlock_irqsave)(&parser->lock);
178
memcpy(meter, &parser->meter, sizeof(*meter));
179
}
180
181