1
2
3
4
5
6
7
8
9#include "ff.h"
10
11static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port,
12 int rcode)
13{
14 struct snd_rawmidi_substream *substream =
15 READ_ONCE(ff->rx_midi_substreams[port]);
16
17 if (rcode_is_permanent_error(rcode)) {
18 ff->rx_midi_error[port] = true;
19 return;
20 }
21
22 if (rcode != RCODE_COMPLETE) {
23
24 ff->next_ktime[port] = 0;
25 schedule_work(&ff->rx_midi_work[port]);
26 return;
27 }
28
29 snd_rawmidi_transmit_ack(substream, ff->rx_bytes[port]);
30 ff->rx_bytes[port] = 0;
31
32 if (!snd_rawmidi_transmit_empty(substream))
33 schedule_work(&ff->rx_midi_work[port]);
34}
35
36static void finish_transmit_midi0_msg(struct fw_card *card, int rcode,
37 void *data, size_t length,
38 void *callback_data)
39{
40 struct snd_ff *ff =
41 container_of(callback_data, struct snd_ff, transactions[0]);
42 finish_transmit_midi_msg(ff, 0, rcode);
43}
44
45static void finish_transmit_midi1_msg(struct fw_card *card, int rcode,
46 void *data, size_t length,
47 void *callback_data)
48{
49 struct snd_ff *ff =
50 container_of(callback_data, struct snd_ff, transactions[1]);
51 finish_transmit_midi_msg(ff, 1, rcode);
52}
53
54static inline void fill_midi_buf(struct snd_ff *ff, unsigned int port,
55 unsigned int index, u8 byte)
56{
57 ff->msg_buf[port][index] = cpu_to_le32(byte);
58}
59
60static void transmit_midi_msg(struct snd_ff *ff, unsigned int port)
61{
62 struct snd_rawmidi_substream *substream =
63 READ_ONCE(ff->rx_midi_substreams[port]);
64 u8 *buf = (u8 *)ff->msg_buf[port];
65 int i, len;
66
67 struct fw_device *fw_dev = fw_parent_device(ff->unit);
68 unsigned long long addr;
69 int generation;
70 fw_transaction_callback_t callback;
71
72 if (substream == NULL || snd_rawmidi_transmit_empty(substream))
73 return;
74
75 if (ff->rx_bytes[port] > 0 || ff->rx_midi_error[port])
76 return;
77
78
79 if (ktime_after(ff->next_ktime[port], ktime_get())) {
80 schedule_work(&ff->rx_midi_work[port]);
81 return;
82 }
83
84 len = snd_rawmidi_transmit_peek(substream, buf,
85 SND_FF_MAXIMIM_MIDI_QUADS);
86 if (len <= 0)
87 return;
88
89 for (i = len - 1; i >= 0; i--)
90 fill_midi_buf(ff, port, i, buf[i]);
91
92 if (port == 0) {
93 addr = ff->spec->protocol->midi_rx_port_0_reg;
94 callback = finish_transmit_midi0_msg;
95 } else {
96 addr = ff->spec->protocol->midi_rx_port_1_reg;
97 callback = finish_transmit_midi1_msg;
98 }
99
100
101 ff->next_ktime[port] = ktime_add_ns(ktime_get(),
102 len * 8 * NSEC_PER_SEC / 31250);
103 ff->rx_bytes[port] = len;
104
105
106
107
108
109
110
111
112
113 generation = fw_dev->generation;
114 smp_rmb();
115 fw_send_request(fw_dev->card, &ff->transactions[port],
116 TCODE_WRITE_BLOCK_REQUEST,
117 fw_dev->node_id, generation, fw_dev->max_speed,
118 addr, &ff->msg_buf[port], len * 4,
119 callback, &ff->transactions[port]);
120}
121
122static void transmit_midi0_msg(struct work_struct *work)
123{
124 struct snd_ff *ff = container_of(work, struct snd_ff, rx_midi_work[0]);
125
126 transmit_midi_msg(ff, 0);
127}
128
129static void transmit_midi1_msg(struct work_struct *work)
130{
131 struct snd_ff *ff = container_of(work, struct snd_ff, rx_midi_work[1]);
132
133 transmit_midi_msg(ff, 1);
134}
135
136static void handle_midi_msg(struct fw_card *card, struct fw_request *request,
137 int tcode, int destination, int source,
138 int generation, unsigned long long offset,
139 void *data, size_t length, void *callback_data)
140{
141 struct snd_ff *ff = callback_data;
142 __le32 *buf = data;
143 u32 quad;
144 u8 byte;
145 unsigned int index;
146 struct snd_rawmidi_substream *substream;
147 int i;
148
149 fw_send_response(card, request, RCODE_COMPLETE);
150
151 for (i = 0; i < length / 4; i++) {
152 quad = le32_to_cpu(buf[i]);
153
154
155
156
157
158
159
160 index = (quad >> 8) & 0xff;
161 if (index > 0) {
162 substream = READ_ONCE(ff->tx_midi_substreams[0]);
163 if (substream != NULL) {
164 byte = quad & 0xff;
165 snd_rawmidi_receive(substream, &byte, 1);
166 }
167 }
168
169
170 index = (quad >> 24) & 0xff;
171 if (index > 0) {
172 substream = READ_ONCE(ff->tx_midi_substreams[1]);
173 if (substream != NULL) {
174 byte = (quad >> 16) & 0xff;
175 snd_rawmidi_receive(substream, &byte, 1);
176 }
177 }
178 }
179}
180
181static int allocate_own_address(struct snd_ff *ff, int i)
182{
183 struct fw_address_region midi_msg_region;
184 int err;
185
186 ff->async_handler.length = SND_FF_MAXIMIM_MIDI_QUADS * 4;
187 ff->async_handler.address_callback = handle_midi_msg;
188 ff->async_handler.callback_data = ff;
189
190 midi_msg_region.start = 0x000100000000ull * i;
191 midi_msg_region.end = midi_msg_region.start + ff->async_handler.length;
192
193 err = fw_core_add_address_handler(&ff->async_handler, &midi_msg_region);
194 if (err >= 0) {
195
196 if (ff->async_handler.offset & 0x0000ffffffff) {
197 fw_core_remove_address_handler(&ff->async_handler);
198 err = -EAGAIN;
199 }
200 }
201
202 return err;
203}
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237int snd_ff_transaction_reregister(struct snd_ff *ff)
238{
239 struct fw_card *fw_card = fw_parent_device(ff->unit)->card;
240 u32 addr;
241 __le32 reg;
242
243
244
245
246
247 addr = (fw_card->node_id << 16) | (ff->async_handler.offset >> 32);
248 reg = cpu_to_le32(addr);
249 return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
250 ff->spec->protocol->midi_high_addr_reg,
251 ®, sizeof(reg), 0);
252}
253
254int snd_ff_transaction_register(struct snd_ff *ff)
255{
256 int i, err;
257
258
259
260
261
262 for (i = 0; i < 0xffff; i++) {
263 err = allocate_own_address(ff, i);
264 if (err != -EBUSY && err != -EAGAIN)
265 break;
266 }
267 if (err < 0)
268 return err;
269
270 err = snd_ff_transaction_reregister(ff);
271 if (err < 0)
272 return err;
273
274 INIT_WORK(&ff->rx_midi_work[0], transmit_midi0_msg);
275 INIT_WORK(&ff->rx_midi_work[1], transmit_midi1_msg);
276
277 return 0;
278}
279
280void snd_ff_transaction_unregister(struct snd_ff *ff)
281{
282 __le32 reg;
283
284 if (ff->async_handler.callback_data == NULL)
285 return;
286 ff->async_handler.callback_data = NULL;
287
288
289 reg = cpu_to_le32(0x00000000);
290 snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
291 ff->spec->protocol->midi_high_addr_reg,
292 ®, sizeof(reg), 0);
293
294 fw_core_remove_address_handler(&ff->async_handler);
295}
296