1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Universal MIDI Packet (UMP) support
4 */
5
6 #include <linux/list.h>
7 #include <linux/slab.h>
8 #include <linux/module.h>
9 #include <linux/export.h>
10 #include <linux/mm.h>
11 #include <sound/core.h>
12 #include <sound/rawmidi.h>
13 #include <sound/ump.h>
14 #include <sound/ump_convert.h>
15
16 #define ump_err(ump, fmt, args...) dev_err((ump)->core.dev, fmt, ##args)
17 #define ump_warn(ump, fmt, args...) dev_warn((ump)->core.dev, fmt, ##args)
18 #define ump_info(ump, fmt, args...) dev_info((ump)->core.dev, fmt, ##args)
19 #define ump_dbg(ump, fmt, args...) dev_dbg((ump)->core.dev, fmt, ##args)
20
21 static int snd_ump_dev_register(struct snd_rawmidi *rmidi);
22 static int snd_ump_dev_unregister(struct snd_rawmidi *rmidi);
23 static long snd_ump_ioctl(struct snd_rawmidi *rmidi, unsigned int cmd,
24 void __user *argp);
25 static void snd_ump_proc_read(struct snd_info_entry *entry,
26 struct snd_info_buffer *buffer);
27 static int snd_ump_rawmidi_open(struct snd_rawmidi_substream *substream);
28 static int snd_ump_rawmidi_close(struct snd_rawmidi_substream *substream);
29 static void snd_ump_rawmidi_trigger(struct snd_rawmidi_substream *substream,
30 int up);
31 static void snd_ump_rawmidi_drain(struct snd_rawmidi_substream *substream);
32
33 static void ump_handle_stream_msg(struct snd_ump_endpoint *ump,
34 const u32 *buf, int size);
35 #if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
36 static int process_legacy_output(struct snd_ump_endpoint *ump,
37 u32 *buffer, int count);
38 static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src,
39 int words);
40 static void ump_legacy_set_rawmidi_name(struct snd_ump_endpoint *ump);
41 static void update_legacy_names(struct snd_ump_endpoint *ump);
42 #else
process_legacy_output(struct snd_ump_endpoint * ump,u32 * buffer,int count)43 static inline int process_legacy_output(struct snd_ump_endpoint *ump,
44 u32 *buffer, int count)
45 {
46 return 0;
47 }
process_legacy_input(struct snd_ump_endpoint * ump,const u32 * src,int words)48 static inline void process_legacy_input(struct snd_ump_endpoint *ump,
49 const u32 *src, int words)
50 {
51 }
ump_legacy_set_rawmidi_name(struct snd_ump_endpoint * ump)52 static inline void ump_legacy_set_rawmidi_name(struct snd_ump_endpoint *ump)
53 {
54 }
update_legacy_names(struct snd_ump_endpoint * ump)55 static inline void update_legacy_names(struct snd_ump_endpoint *ump)
56 {
57 }
58 #endif
59
60 /* copy a string safely with stripping non-printable letters */
safe_copy_string(void * dst,size_t max_dst_size,const void * src,size_t max_src_size)61 static void safe_copy_string(void *dst, size_t max_dst_size,
62 const void *src, size_t max_src_size)
63 {
64 const unsigned char *s = src;
65 unsigned char *d = dst;
66
67 if (!max_dst_size--)
68 return;
69 for (s = src; max_dst_size && *s && max_src_size--; s++) {
70 if (!isascii(*s) || !isprint(*s))
71 continue;
72 *d++ = *s;
73 max_dst_size--;
74 }
75 *d = 0;
76 }
77
78 /* append a string safely with stripping non-printable letters */
safe_append_string(void * dst,size_t max_dst_size,const void * src,size_t max_src_size)79 static void safe_append_string(void *dst, size_t max_dst_size,
80 const void *src, size_t max_src_size)
81 {
82 unsigned char *d = dst;
83 size_t len = strlen(d);
84
85 safe_copy_string(d + len, max_dst_size - len, src, max_src_size);
86 }
87
88 static const struct snd_rawmidi_global_ops snd_ump_rawmidi_ops = {
89 .dev_register = snd_ump_dev_register,
90 .dev_unregister = snd_ump_dev_unregister,
91 .ioctl = snd_ump_ioctl,
92 .proc_read = snd_ump_proc_read,
93 };
94
95 static const struct snd_rawmidi_ops snd_ump_rawmidi_input_ops = {
96 .open = snd_ump_rawmidi_open,
97 .close = snd_ump_rawmidi_close,
98 .trigger = snd_ump_rawmidi_trigger,
99 };
100
101 static const struct snd_rawmidi_ops snd_ump_rawmidi_output_ops = {
102 .open = snd_ump_rawmidi_open,
103 .close = snd_ump_rawmidi_close,
104 .trigger = snd_ump_rawmidi_trigger,
105 .drain = snd_ump_rawmidi_drain,
106 };
107
snd_ump_endpoint_free(struct snd_rawmidi * rmidi)108 static void snd_ump_endpoint_free(struct snd_rawmidi *rmidi)
109 {
110 struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi);
111 struct snd_ump_block *fb;
112
113 while (!list_empty(&ump->block_list)) {
114 fb = list_first_entry(&ump->block_list, struct snd_ump_block,
115 list);
116 list_del(&fb->list);
117 if (fb->private_free)
118 fb->private_free(fb);
119 kfree(fb);
120 }
121
122 if (ump->private_free)
123 ump->private_free(ump);
124
125 #if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
126 kfree(ump->out_cvts);
127 #endif
128 }
129
130 /**
131 * snd_ump_endpoint_new - create a UMP Endpoint object
132 * @card: the card instance
133 * @id: the id string for rawmidi
134 * @device: the device index for rawmidi
135 * @output: 1 for enabling output
136 * @input: 1 for enabling input
137 * @ump_ret: the pointer to store the new UMP instance
138 *
139 * Creates a new UMP Endpoint object. A UMP Endpoint is tied with one rawmidi
140 * instance with one input and/or one output rawmidi stream (either uni-
141 * or bi-directional). A UMP Endpoint may contain one or multiple UMP Blocks
142 * that consist of one or multiple UMP Groups.
143 *
144 * Use snd_rawmidi_set_ops() to set the operators to the new instance.
145 * Unlike snd_rawmidi_new(), this function sets up the info_flags by itself
146 * depending on the given @output and @input.
147 *
148 * The device has SNDRV_RAWMIDI_INFO_UMP flag set and a different device
149 * file ("umpCxDx") than a standard MIDI 1.x device ("midiCxDx") is
150 * created.
151 *
152 * Return: Zero if successful, or a negative error code on failure.
153 */
snd_ump_endpoint_new(struct snd_card * card,char * id,int device,int output,int input,struct snd_ump_endpoint ** ump_ret)154 int snd_ump_endpoint_new(struct snd_card *card, char *id, int device,
155 int output, int input,
156 struct snd_ump_endpoint **ump_ret)
157 {
158 unsigned int info_flags = SNDRV_RAWMIDI_INFO_UMP;
159 struct snd_ump_endpoint *ump;
160 int err;
161
162 if (input)
163 info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
164 if (output)
165 info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
166 if (input && output)
167 info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
168
169 ump = kzalloc(sizeof(*ump), GFP_KERNEL);
170 if (!ump)
171 return -ENOMEM;
172 INIT_LIST_HEAD(&ump->block_list);
173 mutex_init(&ump->open_mutex);
174 init_waitqueue_head(&ump->stream_wait);
175 #if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
176 spin_lock_init(&ump->legacy_locks[0]);
177 spin_lock_init(&ump->legacy_locks[1]);
178 #endif
179 err = snd_rawmidi_init(&ump->core, card, id, device,
180 output, input, info_flags);
181 if (err < 0) {
182 snd_rawmidi_free(&ump->core);
183 return err;
184 }
185
186 ump->info.card = card->number;
187 ump->info.device = device;
188
189 ump->core.private_free = snd_ump_endpoint_free;
190 ump->core.ops = &snd_ump_rawmidi_ops;
191 if (input)
192 snd_rawmidi_set_ops(&ump->core, SNDRV_RAWMIDI_STREAM_INPUT,
193 &snd_ump_rawmidi_input_ops);
194 if (output)
195 snd_rawmidi_set_ops(&ump->core, SNDRV_RAWMIDI_STREAM_OUTPUT,
196 &snd_ump_rawmidi_output_ops);
197
198 ump_dbg(ump, "Created a UMP EP #%d (%s)\n", device, id);
199 *ump_ret = ump;
200 return 0;
201 }
202 EXPORT_SYMBOL_GPL(snd_ump_endpoint_new);
203
204 /*
205 * Device register / unregister hooks;
206 * do nothing, placeholders for avoiding the default rawmidi handling
207 */
208
209 #if IS_ENABLED(CONFIG_SND_SEQUENCER)
snd_ump_dev_seq_free(struct snd_seq_device * device)210 static void snd_ump_dev_seq_free(struct snd_seq_device *device)
211 {
212 struct snd_ump_endpoint *ump = device->private_data;
213
214 ump->seq_dev = NULL;
215 }
216 #endif
217
snd_ump_dev_register(struct snd_rawmidi * rmidi)218 static int snd_ump_dev_register(struct snd_rawmidi *rmidi)
219 {
220 #if IS_ENABLED(CONFIG_SND_SEQUENCER)
221 struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi);
222 int err;
223
224 err = snd_seq_device_new(ump->core.card, ump->core.device,
225 SNDRV_SEQ_DEV_ID_UMP, 0, &ump->seq_dev);
226 if (err < 0)
227 return err;
228 ump->seq_dev->private_data = ump;
229 ump->seq_dev->private_free = snd_ump_dev_seq_free;
230 snd_device_register(ump->core.card, ump->seq_dev);
231 #endif
232 return 0;
233 }
234
snd_ump_dev_unregister(struct snd_rawmidi * rmidi)235 static int snd_ump_dev_unregister(struct snd_rawmidi *rmidi)
236 {
237 return 0;
238 }
239
240 static struct snd_ump_block *
snd_ump_get_block(struct snd_ump_endpoint * ump,unsigned char id)241 snd_ump_get_block(struct snd_ump_endpoint *ump, unsigned char id)
242 {
243 struct snd_ump_block *fb;
244
245 list_for_each_entry(fb, &ump->block_list, list) {
246 if (fb->info.block_id == id)
247 return fb;
248 }
249 return NULL;
250 }
251
252 /*
253 * rawmidi ops for UMP endpoint
254 */
snd_ump_rawmidi_open(struct snd_rawmidi_substream * substream)255 static int snd_ump_rawmidi_open(struct snd_rawmidi_substream *substream)
256 {
257 struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi);
258 int dir = substream->stream;
259 int err;
260
261 if (ump->substreams[dir])
262 return -EBUSY;
263 err = ump->ops->open(ump, dir);
264 if (err < 0)
265 return err;
266 ump->substreams[dir] = substream;
267 return 0;
268 }
269
snd_ump_rawmidi_close(struct snd_rawmidi_substream * substream)270 static int snd_ump_rawmidi_close(struct snd_rawmidi_substream *substream)
271 {
272 struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi);
273 int dir = substream->stream;
274
275 ump->substreams[dir] = NULL;
276 ump->ops->close(ump, dir);
277 return 0;
278 }
279
snd_ump_rawmidi_trigger(struct snd_rawmidi_substream * substream,int up)280 static void snd_ump_rawmidi_trigger(struct snd_rawmidi_substream *substream,
281 int up)
282 {
283 struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi);
284 int dir = substream->stream;
285
286 ump->ops->trigger(ump, dir, up);
287 }
288
snd_ump_rawmidi_drain(struct snd_rawmidi_substream * substream)289 static void snd_ump_rawmidi_drain(struct snd_rawmidi_substream *substream)
290 {
291 struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi);
292
293 if (ump->ops->drain)
294 ump->ops->drain(ump, SNDRV_RAWMIDI_STREAM_OUTPUT);
295 }
296
297 /* number of 32bit words per message type */
298 static unsigned char ump_packet_words[0x10] = {
299 1, 1, 1, 2, 2, 4, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4
300 };
301
302 /**
303 * snd_ump_receive_ump_val - parse the UMP packet data
304 * @ump: UMP endpoint
305 * @val: UMP packet data
306 *
307 * The data is copied onto ump->input_buf[].
308 * When a full packet is completed, returns the number of words (from 1 to 4).
309 * OTOH, if the packet is incomplete, returns 0.
310 */
snd_ump_receive_ump_val(struct snd_ump_endpoint * ump,u32 val)311 int snd_ump_receive_ump_val(struct snd_ump_endpoint *ump, u32 val)
312 {
313 int words;
314
315 if (!ump->input_pending)
316 ump->input_pending = ump_packet_words[ump_message_type(val)];
317
318 ump->input_buf[ump->input_buf_head++] = val;
319 ump->input_pending--;
320 if (!ump->input_pending) {
321 words = ump->input_buf_head;
322 ump->input_buf_head = 0;
323 return words;
324 }
325 return 0;
326 }
327 EXPORT_SYMBOL_GPL(snd_ump_receive_ump_val);
328
329 /**
330 * snd_ump_receive - transfer UMP packets from the device
331 * @ump: the UMP endpoint
332 * @buffer: the buffer pointer to transfer
333 * @count: byte size to transfer
334 *
335 * Called from the driver to submit the received UMP packets from the device
336 * to user-space. It's essentially a wrapper of rawmidi_receive().
337 * The data to receive is in CPU-native endianness.
338 */
snd_ump_receive(struct snd_ump_endpoint * ump,const u32 * buffer,int count)339 int snd_ump_receive(struct snd_ump_endpoint *ump, const u32 *buffer, int count)
340 {
341 struct snd_rawmidi_substream *substream;
342 const u32 *p = buffer;
343 int n, words = count >> 2;
344
345 while (words--) {
346 n = snd_ump_receive_ump_val(ump, *p++);
347 if (!n)
348 continue;
349 ump_handle_stream_msg(ump, ump->input_buf, n);
350 #if IS_ENABLED(CONFIG_SND_SEQUENCER)
351 if (ump->seq_ops)
352 ump->seq_ops->input_receive(ump, ump->input_buf, n);
353 #endif
354 process_legacy_input(ump, ump->input_buf, n);
355 }
356
357 substream = ump->substreams[SNDRV_RAWMIDI_STREAM_INPUT];
358 if (!substream)
359 return 0;
360 return snd_rawmidi_receive(substream, (const char *)buffer, count);
361 }
362 EXPORT_SYMBOL_GPL(snd_ump_receive);
363
364 /**
365 * snd_ump_transmit - transmit UMP packets
366 * @ump: the UMP endpoint
367 * @buffer: the buffer pointer to transfer
368 * @count: byte size to transfer
369 *
370 * Called from the driver to obtain the UMP packets from user-space to the
371 * device. It's essentially a wrapper of rawmidi_transmit().
372 * The data to transmit is in CPU-native endianness.
373 */
snd_ump_transmit(struct snd_ump_endpoint * ump,u32 * buffer,int count)374 int snd_ump_transmit(struct snd_ump_endpoint *ump, u32 *buffer, int count)
375 {
376 struct snd_rawmidi_substream *substream =
377 ump->substreams[SNDRV_RAWMIDI_STREAM_OUTPUT];
378 int err;
379
380 if (!substream)
381 return -ENODEV;
382 err = snd_rawmidi_transmit(substream, (char *)buffer, count);
383 /* received either data or an error? */
384 if (err)
385 return err;
386 return process_legacy_output(ump, buffer, count);
387 }
388 EXPORT_SYMBOL_GPL(snd_ump_transmit);
389
390 /**
391 * snd_ump_block_new - Create a UMP block
392 * @ump: UMP object
393 * @blk: block ID number to create
394 * @direction: direction (in/out/bidirection)
395 * @first_group: the first group ID (0-based)
396 * @num_groups: the number of groups in this block
397 * @blk_ret: the pointer to store the resultant block object
398 */
snd_ump_block_new(struct snd_ump_endpoint * ump,unsigned int blk,unsigned int direction,unsigned int first_group,unsigned int num_groups,struct snd_ump_block ** blk_ret)399 int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk,
400 unsigned int direction, unsigned int first_group,
401 unsigned int num_groups, struct snd_ump_block **blk_ret)
402 {
403 struct snd_ump_block *fb, *p;
404
405 if (blk >= SNDRV_UMP_MAX_BLOCKS)
406 return -EINVAL;
407
408 if (snd_ump_get_block(ump, blk))
409 return -EBUSY;
410
411 fb = kzalloc(sizeof(*fb), GFP_KERNEL);
412 if (!fb)
413 return -ENOMEM;
414
415 fb->ump = ump;
416 fb->info.card = ump->info.card;
417 fb->info.device = ump->info.device;
418 fb->info.block_id = blk;
419 if (blk >= ump->info.num_blocks)
420 ump->info.num_blocks = blk + 1;
421 fb->info.direction = direction;
422 fb->info.active = 1;
423 fb->info.first_group = first_group;
424 fb->info.num_groups = num_groups;
425 /* fill the default name, may be overwritten to a better name */
426 snprintf(fb->info.name, sizeof(fb->info.name), "Group %u-%u",
427 first_group + 1, first_group + num_groups);
428
429 /* put the entry in the ordered list */
430 list_for_each_entry(p, &ump->block_list, list) {
431 if (p->info.block_id > blk) {
432 list_add_tail(&fb->list, &p->list);
433 goto added;
434 }
435 }
436 list_add_tail(&fb->list, &ump->block_list);
437
438 added:
439 ump_dbg(ump, "Created a UMP Block #%d (%s)\n", blk, fb->info.name);
440 *blk_ret = fb;
441 return 0;
442 }
443 EXPORT_SYMBOL_GPL(snd_ump_block_new);
444
snd_ump_ioctl_block(struct snd_ump_endpoint * ump,struct snd_ump_block_info __user * argp)445 static int snd_ump_ioctl_block(struct snd_ump_endpoint *ump,
446 struct snd_ump_block_info __user *argp)
447 {
448 struct snd_ump_block *fb;
449 unsigned char id;
450
451 if (get_user(id, &argp->block_id))
452 return -EFAULT;
453 fb = snd_ump_get_block(ump, id);
454 if (!fb)
455 return -ENOENT;
456 if (copy_to_user(argp, &fb->info, sizeof(fb->info)))
457 return -EFAULT;
458 return 0;
459 }
460
461 /*
462 * Handle UMP-specific ioctls; called from snd_rawmidi_ioctl()
463 */
snd_ump_ioctl(struct snd_rawmidi * rmidi,unsigned int cmd,void __user * argp)464 static long snd_ump_ioctl(struct snd_rawmidi *rmidi, unsigned int cmd,
465 void __user *argp)
466 {
467 struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi);
468
469 switch (cmd) {
470 case SNDRV_UMP_IOCTL_ENDPOINT_INFO:
471 if (copy_to_user(argp, &ump->info, sizeof(ump->info)))
472 return -EFAULT;
473 return 0;
474 case SNDRV_UMP_IOCTL_BLOCK_INFO:
475 return snd_ump_ioctl_block(ump, argp);
476 default:
477 ump_dbg(ump, "rawmidi: unknown command = 0x%x\n", cmd);
478 return -ENOTTY;
479 }
480 }
481
ump_direction_string(int dir)482 static const char *ump_direction_string(int dir)
483 {
484 switch (dir) {
485 case SNDRV_UMP_DIR_INPUT:
486 return "input";
487 case SNDRV_UMP_DIR_OUTPUT:
488 return "output";
489 case SNDRV_UMP_DIR_BIDIRECTION:
490 return "bidirection";
491 default:
492 return "unknown";
493 }
494 }
495
ump_ui_hint_string(int dir)496 static const char *ump_ui_hint_string(int dir)
497 {
498 switch (dir) {
499 case SNDRV_UMP_BLOCK_UI_HINT_RECEIVER:
500 return "receiver";
501 case SNDRV_UMP_BLOCK_UI_HINT_SENDER:
502 return "sender";
503 case SNDRV_UMP_BLOCK_UI_HINT_BOTH:
504 return "both";
505 default:
506 return "unknown";
507 }
508 }
509
510 /* Additional proc file output */
snd_ump_proc_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)511 static void snd_ump_proc_read(struct snd_info_entry *entry,
512 struct snd_info_buffer *buffer)
513 {
514 struct snd_rawmidi *rmidi = entry->private_data;
515 struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi);
516 struct snd_ump_block *fb;
517
518 snd_iprintf(buffer, "EP Name: %s\n", ump->info.name);
519 snd_iprintf(buffer, "EP Product ID: %s\n", ump->info.product_id);
520 snd_iprintf(buffer, "UMP Version: 0x%04x\n", ump->info.version);
521 snd_iprintf(buffer, "Protocol Caps: 0x%08x\n", ump->info.protocol_caps);
522 snd_iprintf(buffer, "Protocol: 0x%08x\n", ump->info.protocol);
523 if (ump->info.version) {
524 snd_iprintf(buffer, "Manufacturer ID: 0x%08x\n",
525 ump->info.manufacturer_id);
526 snd_iprintf(buffer, "Family ID: 0x%04x\n", ump->info.family_id);
527 snd_iprintf(buffer, "Model ID: 0x%04x\n", ump->info.model_id);
528 snd_iprintf(buffer, "SW Revision: 0x%4phN\n", ump->info.sw_revision);
529 }
530 snd_iprintf(buffer, "Static Blocks: %s\n",
531 (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) ? "Yes" : "No");
532 snd_iprintf(buffer, "Num Blocks: %d\n\n", ump->info.num_blocks);
533
534 list_for_each_entry(fb, &ump->block_list, list) {
535 snd_iprintf(buffer, "Block %d (%s)\n", fb->info.block_id,
536 fb->info.name);
537 snd_iprintf(buffer, " Direction: %s\n",
538 ump_direction_string(fb->info.direction));
539 snd_iprintf(buffer, " Active: %s\n",
540 fb->info.active ? "Yes" : "No");
541 snd_iprintf(buffer, " Groups: %d-%d\n",
542 fb->info.first_group + 1,
543 fb->info.first_group + fb->info.num_groups);
544 snd_iprintf(buffer, " Is MIDI1: %s%s\n",
545 (fb->info.flags & SNDRV_UMP_BLOCK_IS_MIDI1) ? "Yes" : "No",
546 (fb->info.flags & SNDRV_UMP_BLOCK_IS_LOWSPEED) ? " (Low Speed)" : "");
547 if (ump->info.version) {
548 snd_iprintf(buffer, " MIDI-CI Version: %d\n",
549 fb->info.midi_ci_version);
550 snd_iprintf(buffer, " Sysex8 Streams: %d\n",
551 fb->info.sysex8_streams);
552 snd_iprintf(buffer, " UI Hint: %s\n",
553 ump_ui_hint_string(fb->info.ui_hint));
554 }
555 snd_iprintf(buffer, "\n");
556 }
557 }
558
559 /* update dir_bits and active flag for all groups in the client */
snd_ump_update_group_attrs(struct snd_ump_endpoint * ump)560 void snd_ump_update_group_attrs(struct snd_ump_endpoint *ump)
561 {
562 struct snd_ump_block *fb;
563 struct snd_ump_group *group;
564 int i;
565
566 for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
567 group = &ump->groups[i];
568 *group->name = 0;
569 group->dir_bits = 0;
570 group->active = 0;
571 group->group = i;
572 group->valid = false;
573 group->is_midi1 = false;
574 }
575
576 list_for_each_entry(fb, &ump->block_list, list) {
577 if (fb->info.first_group + fb->info.num_groups > SNDRV_UMP_MAX_GROUPS)
578 break;
579 group = &ump->groups[fb->info.first_group];
580 for (i = 0; i < fb->info.num_groups; i++, group++) {
581 group->valid = true;
582 if (fb->info.active)
583 group->active = 1;
584 if (fb->info.flags & SNDRV_UMP_BLOCK_IS_MIDI1)
585 group->is_midi1 = true;
586 switch (fb->info.direction) {
587 case SNDRV_UMP_DIR_INPUT:
588 group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_INPUT);
589 break;
590 case SNDRV_UMP_DIR_OUTPUT:
591 group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_OUTPUT);
592 break;
593 case SNDRV_UMP_DIR_BIDIRECTION:
594 group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_INPUT) |
595 (1 << SNDRV_RAWMIDI_STREAM_OUTPUT);
596 break;
597 }
598 if (!*fb->info.name)
599 continue;
600 if (*group->name)
601 strlcat(group->name, ", ", sizeof(group->name));
602 safe_append_string(group->name, sizeof(group->name),
603 fb->info.name, sizeof(fb->info.name));
604 }
605 }
606 }
607 EXPORT_SYMBOL_GPL(snd_ump_update_group_attrs);
608
609 /*
610 * UMP endpoint and function block handling
611 */
612
613 /* open / close UMP streams for the internal stream msg communication */
ump_request_open(struct snd_ump_endpoint * ump)614 static int ump_request_open(struct snd_ump_endpoint *ump)
615 {
616 return snd_rawmidi_kernel_open(&ump->core, 0,
617 SNDRV_RAWMIDI_LFLG_OUTPUT,
618 &ump->stream_rfile);
619 }
620
ump_request_close(struct snd_ump_endpoint * ump)621 static void ump_request_close(struct snd_ump_endpoint *ump)
622 {
623 snd_rawmidi_kernel_release(&ump->stream_rfile);
624 }
625
626 /* request a command and wait for the given response;
627 * @req1 and @req2 are u32 commands
628 * @reply is the expected UMP stream status
629 */
ump_req_msg(struct snd_ump_endpoint * ump,u32 req1,u32 req2,u32 reply)630 static int ump_req_msg(struct snd_ump_endpoint *ump, u32 req1, u32 req2,
631 u32 reply)
632 {
633 u32 buf[4];
634
635 ump_dbg(ump, "%s: request %08x %08x, wait-for %08x\n",
636 __func__, req1, req2, reply);
637 memset(buf, 0, sizeof(buf));
638 buf[0] = req1;
639 buf[1] = req2;
640 ump->stream_finished = 0;
641 ump->stream_wait_for = reply;
642 snd_rawmidi_kernel_write(ump->stream_rfile.output,
643 (unsigned char *)&buf, 16);
644 wait_event_timeout(ump->stream_wait, ump->stream_finished,
645 msecs_to_jiffies(500));
646 if (!READ_ONCE(ump->stream_finished)) {
647 ump_dbg(ump, "%s: request timed out\n", __func__);
648 return -ETIMEDOUT;
649 }
650 ump->stream_finished = 0;
651 ump_dbg(ump, "%s: reply: %08x %08x %08x %08x\n",
652 __func__, buf[0], buf[1], buf[2], buf[3]);
653 return 0;
654 }
655
656 /* append the received letters via UMP packet to the given string buffer;
657 * return 1 if the full string is received or 0 to continue
658 */
ump_append_string(struct snd_ump_endpoint * ump,char * dest,int maxsize,const u32 * buf,int offset)659 static int ump_append_string(struct snd_ump_endpoint *ump, char *dest,
660 int maxsize, const u32 *buf, int offset)
661 {
662 unsigned char format;
663 int c;
664
665 format = ump_stream_message_format(buf[0]);
666 if (format == UMP_STREAM_MSG_FORMAT_SINGLE ||
667 format == UMP_STREAM_MSG_FORMAT_START) {
668 c = 0;
669 } else {
670 c = strlen(dest);
671 if (c >= maxsize - 1)
672 return 1;
673 }
674
675 for (; offset < 16; offset++) {
676 dest[c] = buf[offset / 4] >> (3 - (offset % 4)) * 8;
677 if (!dest[c])
678 break;
679 if (++c >= maxsize - 1)
680 break;
681 }
682 dest[c] = 0;
683 return (format == UMP_STREAM_MSG_FORMAT_SINGLE ||
684 format == UMP_STREAM_MSG_FORMAT_END);
685 }
686
687 /* Choose the default protocol */
choose_default_protocol(struct snd_ump_endpoint * ump)688 static void choose_default_protocol(struct snd_ump_endpoint *ump)
689 {
690 if (ump->info.protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK)
691 return;
692 if (ump->info.protocol_caps & SNDRV_UMP_EP_INFO_PROTO_MIDI2)
693 ump->info.protocol |= SNDRV_UMP_EP_INFO_PROTO_MIDI2;
694 else
695 ump->info.protocol |= SNDRV_UMP_EP_INFO_PROTO_MIDI1;
696 }
697
698 /* notify the EP info/name change to sequencer */
seq_notify_ep_change(struct snd_ump_endpoint * ump)699 static void seq_notify_ep_change(struct snd_ump_endpoint *ump)
700 {
701 #if IS_ENABLED(CONFIG_SND_SEQUENCER)
702 if (ump->parsed && ump->seq_ops && ump->seq_ops->notify_ep_change)
703 ump->seq_ops->notify_ep_change(ump);
704 #endif
705 }
706
707 /* handle EP info stream message; update the UMP attributes */
ump_handle_ep_info_msg(struct snd_ump_endpoint * ump,const union snd_ump_stream_msg * buf)708 static int ump_handle_ep_info_msg(struct snd_ump_endpoint *ump,
709 const union snd_ump_stream_msg *buf)
710 {
711 ump->info.version = (buf->ep_info.ump_version_major << 8) |
712 buf->ep_info.ump_version_minor;
713 ump->info.num_blocks = buf->ep_info.num_function_blocks;
714 if (ump->info.num_blocks > SNDRV_UMP_MAX_BLOCKS) {
715 ump_info(ump, "Invalid function blocks %d, fallback to 1\n",
716 ump->info.num_blocks);
717 ump->info.num_blocks = 1;
718 }
719
720 if (buf->ep_info.static_function_block)
721 ump->info.flags |= SNDRV_UMP_EP_INFO_STATIC_BLOCKS;
722
723 ump->info.protocol_caps = (buf->ep_info.protocol << 8) |
724 buf->ep_info.jrts;
725
726 ump_dbg(ump, "EP info: version=%x, num_blocks=%x, proto_caps=%x\n",
727 ump->info.version, ump->info.num_blocks, ump->info.protocol_caps);
728
729 ump->info.protocol &= ump->info.protocol_caps;
730 choose_default_protocol(ump);
731 seq_notify_ep_change(ump);
732
733 return 1; /* finished */
734 }
735
736 /* handle EP device info stream message; update the UMP attributes */
ump_handle_device_info_msg(struct snd_ump_endpoint * ump,const union snd_ump_stream_msg * buf)737 static int ump_handle_device_info_msg(struct snd_ump_endpoint *ump,
738 const union snd_ump_stream_msg *buf)
739 {
740 ump->info.manufacturer_id = buf->device_info.manufacture_id & 0x7f7f7f;
741 ump->info.family_id = (buf->device_info.family_msb << 8) |
742 buf->device_info.family_lsb;
743 ump->info.model_id = (buf->device_info.model_msb << 8) |
744 buf->device_info.model_lsb;
745 ump->info.sw_revision[0] = (buf->device_info.sw_revision >> 24) & 0x7f;
746 ump->info.sw_revision[1] = (buf->device_info.sw_revision >> 16) & 0x7f;
747 ump->info.sw_revision[2] = (buf->device_info.sw_revision >> 8) & 0x7f;
748 ump->info.sw_revision[3] = buf->device_info.sw_revision & 0x7f;
749 ump_dbg(ump, "EP devinfo: manid=%08x, family=%04x, model=%04x, sw=%4phN\n",
750 ump->info.manufacturer_id,
751 ump->info.family_id,
752 ump->info.model_id,
753 ump->info.sw_revision);
754 seq_notify_ep_change(ump);
755 return 1; /* finished */
756 }
757
758 /* set up the core rawmidi name from UMP EP name string */
ump_set_rawmidi_name(struct snd_ump_endpoint * ump)759 static void ump_set_rawmidi_name(struct snd_ump_endpoint *ump)
760 {
761 safe_copy_string(ump->core.name, sizeof(ump->core.name),
762 ump->info.name, sizeof(ump->info.name));
763 }
764
765 /* handle EP name stream message; update the UMP name string */
ump_handle_ep_name_msg(struct snd_ump_endpoint * ump,const union snd_ump_stream_msg * buf)766 static int ump_handle_ep_name_msg(struct snd_ump_endpoint *ump,
767 const union snd_ump_stream_msg *buf)
768 {
769 int ret;
770
771 ret = ump_append_string(ump, ump->info.name, sizeof(ump->info.name),
772 buf->raw, 2);
773 if (ret && ump->parsed) {
774 ump_set_rawmidi_name(ump);
775 ump_legacy_set_rawmidi_name(ump);
776 seq_notify_ep_change(ump);
777 }
778
779 return ret;
780 }
781
782 /* handle EP product id stream message; update the UMP product_id string */
ump_handle_product_id_msg(struct snd_ump_endpoint * ump,const union snd_ump_stream_msg * buf)783 static int ump_handle_product_id_msg(struct snd_ump_endpoint *ump,
784 const union snd_ump_stream_msg *buf)
785 {
786 int ret;
787
788 ret = ump_append_string(ump, ump->info.product_id,
789 sizeof(ump->info.product_id),
790 buf->raw, 2);
791 if (ret)
792 seq_notify_ep_change(ump);
793 return ret;
794 }
795
796 /* notify the protocol change to sequencer */
seq_notify_protocol(struct snd_ump_endpoint * ump)797 static void seq_notify_protocol(struct snd_ump_endpoint *ump)
798 {
799 #if IS_ENABLED(CONFIG_SND_SEQUENCER)
800 if (ump->seq_ops && ump->seq_ops->switch_protocol)
801 ump->seq_ops->switch_protocol(ump);
802 #endif /* CONFIG_SND_SEQUENCER */
803 }
804
805 /**
806 * snd_ump_switch_protocol - switch MIDI protocol
807 * @ump: UMP endpoint
808 * @protocol: protocol to switch to
809 *
810 * Returns 1 if the protocol is actually switched, 0 if unchanged
811 */
snd_ump_switch_protocol(struct snd_ump_endpoint * ump,unsigned int protocol)812 int snd_ump_switch_protocol(struct snd_ump_endpoint *ump, unsigned int protocol)
813 {
814 unsigned int type;
815
816 protocol &= ump->info.protocol_caps;
817 if (protocol == ump->info.protocol)
818 return 0;
819
820 type = protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK;
821 if (type != SNDRV_UMP_EP_INFO_PROTO_MIDI1 &&
822 type != SNDRV_UMP_EP_INFO_PROTO_MIDI2)
823 return 0;
824
825 ump->info.protocol = protocol;
826 ump_dbg(ump, "New protocol = %x (caps = %x)\n",
827 protocol, ump->info.protocol_caps);
828 seq_notify_protocol(ump);
829 return 1;
830 }
831 EXPORT_SYMBOL_GPL(snd_ump_switch_protocol);
832
833 /* handle EP stream config message; update the UMP protocol */
ump_handle_stream_cfg_msg(struct snd_ump_endpoint * ump,const union snd_ump_stream_msg * buf)834 static int ump_handle_stream_cfg_msg(struct snd_ump_endpoint *ump,
835 const union snd_ump_stream_msg *buf)
836 {
837 unsigned int protocol =
838 (buf->stream_cfg.protocol << 8) | buf->stream_cfg.jrts;
839
840 snd_ump_switch_protocol(ump, protocol);
841 return 1; /* finished */
842 }
843
844 /* Extract Function Block info from UMP packet */
fill_fb_info(struct snd_ump_endpoint * ump,struct snd_ump_block_info * info,const union snd_ump_stream_msg * buf)845 static void fill_fb_info(struct snd_ump_endpoint *ump,
846 struct snd_ump_block_info *info,
847 const union snd_ump_stream_msg *buf)
848 {
849 info->direction = buf->fb_info.direction;
850 info->ui_hint = buf->fb_info.ui_hint;
851 info->first_group = buf->fb_info.first_group;
852 info->num_groups = buf->fb_info.num_groups;
853 if (buf->fb_info.midi_10 < 2)
854 info->flags = buf->fb_info.midi_10;
855 else
856 info->flags = SNDRV_UMP_BLOCK_IS_MIDI1 | SNDRV_UMP_BLOCK_IS_LOWSPEED;
857 info->active = buf->fb_info.active;
858 info->midi_ci_version = buf->fb_info.midi_ci_version;
859 info->sysex8_streams = buf->fb_info.sysex8_streams;
860
861 ump_dbg(ump, "FB %d: dir=%d, active=%d, first_gp=%d, num_gp=%d, midici=%d, sysex8=%d, flags=0x%x\n",
862 info->block_id, info->direction, info->active,
863 info->first_group, info->num_groups, info->midi_ci_version,
864 info->sysex8_streams, info->flags);
865
866 if ((info->flags & SNDRV_UMP_BLOCK_IS_MIDI1) && info->num_groups != 1) {
867 info->num_groups = 1;
868 ump_dbg(ump, "FB %d: corrected groups to 1 for MIDI1\n",
869 info->block_id);
870 }
871 }
872
873 /* check whether the FB info gets updated by the current message */
is_fb_info_updated(struct snd_ump_endpoint * ump,struct snd_ump_block * fb,const union snd_ump_stream_msg * buf)874 static bool is_fb_info_updated(struct snd_ump_endpoint *ump,
875 struct snd_ump_block *fb,
876 const union snd_ump_stream_msg *buf)
877 {
878 char tmpbuf[offsetof(struct snd_ump_block_info, name)];
879
880 if (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) {
881 ump_info(ump, "Skipping static FB info update (blk#%d)\n",
882 fb->info.block_id);
883 return 0;
884 }
885
886 memcpy(tmpbuf, &fb->info, sizeof(tmpbuf));
887 fill_fb_info(ump, (struct snd_ump_block_info *)tmpbuf, buf);
888 return memcmp(&fb->info, tmpbuf, sizeof(tmpbuf)) != 0;
889 }
890
891 /* notify the FB info/name change to sequencer */
seq_notify_fb_change(struct snd_ump_endpoint * ump,struct snd_ump_block * fb)892 static void seq_notify_fb_change(struct snd_ump_endpoint *ump,
893 struct snd_ump_block *fb)
894 {
895 #if IS_ENABLED(CONFIG_SND_SEQUENCER)
896 if (ump->seq_ops && ump->seq_ops->notify_fb_change)
897 ump->seq_ops->notify_fb_change(ump, fb);
898 #endif
899 }
900
901 /* handle FB info message; update FB info if the block is present */
ump_handle_fb_info_msg(struct snd_ump_endpoint * ump,const union snd_ump_stream_msg * buf)902 static int ump_handle_fb_info_msg(struct snd_ump_endpoint *ump,
903 const union snd_ump_stream_msg *buf)
904 {
905 unsigned char blk;
906 struct snd_ump_block *fb;
907
908 blk = buf->fb_info.function_block_id;
909 fb = snd_ump_get_block(ump, blk);
910
911 /* complain only if updated after parsing */
912 if (!fb && ump->parsed) {
913 ump_info(ump, "Function Block Info Update for non-existing block %d\n",
914 blk);
915 return -ENODEV;
916 }
917
918 /* When updated after the initial parse, check the FB info update */
919 if (ump->parsed && !is_fb_info_updated(ump, fb, buf))
920 return 1; /* no content change */
921
922 if (fb) {
923 fill_fb_info(ump, &fb->info, buf);
924 if (ump->parsed) {
925 snd_ump_update_group_attrs(ump);
926 update_legacy_names(ump);
927 seq_notify_fb_change(ump, fb);
928 }
929 }
930
931 return 1; /* finished */
932 }
933
934 /* handle FB name message; update the FB name string */
ump_handle_fb_name_msg(struct snd_ump_endpoint * ump,const union snd_ump_stream_msg * buf)935 static int ump_handle_fb_name_msg(struct snd_ump_endpoint *ump,
936 const union snd_ump_stream_msg *buf)
937 {
938 unsigned char blk;
939 struct snd_ump_block *fb;
940 int ret;
941
942 blk = buf->fb_name.function_block_id;
943 fb = snd_ump_get_block(ump, blk);
944 if (!fb)
945 return -ENODEV;
946
947 if (ump->parsed &&
948 (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS)) {
949 ump_dbg(ump, "Skipping static FB name update (blk#%d)\n",
950 fb->info.block_id);
951 return 0;
952 }
953
954 ret = ump_append_string(ump, fb->info.name, sizeof(fb->info.name),
955 buf->raw, 3);
956 /* notify the FB name update to sequencer, too */
957 if (ret > 0 && ump->parsed) {
958 snd_ump_update_group_attrs(ump);
959 update_legacy_names(ump);
960 seq_notify_fb_change(ump, fb);
961 }
962 return ret;
963 }
964
create_block_from_fb_info(struct snd_ump_endpoint * ump,int blk)965 static int create_block_from_fb_info(struct snd_ump_endpoint *ump, int blk)
966 {
967 struct snd_ump_block *fb;
968 unsigned char direction, first_group, num_groups;
969 const union snd_ump_stream_msg *buf =
970 (const union snd_ump_stream_msg *)ump->input_buf;
971 u32 msg;
972 int err;
973
974 /* query the FB info once */
975 msg = ump_stream_compose(UMP_STREAM_MSG_STATUS_FB_DISCOVERY, 0) |
976 (blk << 8) | UMP_STREAM_MSG_REQUEST_FB_INFO;
977 err = ump_req_msg(ump, msg, 0, UMP_STREAM_MSG_STATUS_FB_INFO);
978 if (err < 0) {
979 ump_dbg(ump, "Unable to get FB info for block %d\n", blk);
980 return err;
981 }
982
983 /* the last input must be the FB info */
984 if (buf->fb_info.status != UMP_STREAM_MSG_STATUS_FB_INFO) {
985 ump_dbg(ump, "Inconsistent input: 0x%x\n", *buf->raw);
986 return -EINVAL;
987 }
988
989 direction = buf->fb_info.direction;
990 first_group = buf->fb_info.first_group;
991 num_groups = buf->fb_info.num_groups;
992
993 err = snd_ump_block_new(ump, blk, direction, first_group, num_groups,
994 &fb);
995 if (err < 0)
996 return err;
997
998 fill_fb_info(ump, &fb->info, buf);
999
1000 msg = ump_stream_compose(UMP_STREAM_MSG_STATUS_FB_DISCOVERY, 0) |
1001 (blk << 8) | UMP_STREAM_MSG_REQUEST_FB_NAME;
1002 err = ump_req_msg(ump, msg, 0, UMP_STREAM_MSG_STATUS_FB_NAME);
1003 if (err)
1004 ump_dbg(ump, "Unable to get UMP FB name string #%d\n", blk);
1005
1006 return 0;
1007 }
1008
1009 /* handle stream messages, called from snd_ump_receive() */
ump_handle_stream_msg(struct snd_ump_endpoint * ump,const u32 * buf,int size)1010 static void ump_handle_stream_msg(struct snd_ump_endpoint *ump,
1011 const u32 *buf, int size)
1012 {
1013 const union snd_ump_stream_msg *msg;
1014 unsigned int status;
1015 int ret;
1016
1017 /* UMP stream message suppressed (for gadget UMP)? */
1018 if (ump->no_process_stream)
1019 return;
1020
1021 BUILD_BUG_ON(sizeof(*msg) != 16);
1022 ump_dbg(ump, "Stream msg: %08x %08x %08x %08x\n",
1023 buf[0], buf[1], buf[2], buf[3]);
1024
1025 if (size != 4 || ump_message_type(*buf) != UMP_MSG_TYPE_STREAM)
1026 return;
1027
1028 msg = (const union snd_ump_stream_msg *)buf;
1029 status = ump_stream_message_status(*buf);
1030 switch (status) {
1031 case UMP_STREAM_MSG_STATUS_EP_INFO:
1032 ret = ump_handle_ep_info_msg(ump, msg);
1033 break;
1034 case UMP_STREAM_MSG_STATUS_DEVICE_INFO:
1035 ret = ump_handle_device_info_msg(ump, msg);
1036 break;
1037 case UMP_STREAM_MSG_STATUS_EP_NAME:
1038 ret = ump_handle_ep_name_msg(ump, msg);
1039 break;
1040 case UMP_STREAM_MSG_STATUS_PRODUCT_ID:
1041 ret = ump_handle_product_id_msg(ump, msg);
1042 break;
1043 case UMP_STREAM_MSG_STATUS_STREAM_CFG:
1044 ret = ump_handle_stream_cfg_msg(ump, msg);
1045 break;
1046 case UMP_STREAM_MSG_STATUS_FB_INFO:
1047 ret = ump_handle_fb_info_msg(ump, msg);
1048 break;
1049 case UMP_STREAM_MSG_STATUS_FB_NAME:
1050 ret = ump_handle_fb_name_msg(ump, msg);
1051 break;
1052 default:
1053 return;
1054 }
1055
1056 /* when the message has been processed fully, wake up */
1057 if (ret > 0 && ump->stream_wait_for == status) {
1058 WRITE_ONCE(ump->stream_finished, 1);
1059 wake_up(&ump->stream_wait);
1060 }
1061 }
1062
1063 /**
1064 * snd_ump_parse_endpoint - parse endpoint and create function blocks
1065 * @ump: UMP object
1066 *
1067 * Returns 0 for successful parse, -ENODEV if device doesn't respond
1068 * (or the query is unsupported), or other error code for serious errors.
1069 */
snd_ump_parse_endpoint(struct snd_ump_endpoint * ump)1070 int snd_ump_parse_endpoint(struct snd_ump_endpoint *ump)
1071 {
1072 int blk, err;
1073 u32 msg;
1074
1075 if (!(ump->core.info_flags & SNDRV_RAWMIDI_INFO_DUPLEX))
1076 return -ENODEV;
1077
1078 err = ump_request_open(ump);
1079 if (err < 0) {
1080 ump_dbg(ump, "Unable to open rawmidi device: %d\n", err);
1081 return err;
1082 }
1083
1084 /* Check Endpoint Information */
1085 msg = ump_stream_compose(UMP_STREAM_MSG_STATUS_EP_DISCOVERY, 0) |
1086 0x0101; /* UMP version 1.1 */
1087 err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_EP_INFO,
1088 UMP_STREAM_MSG_STATUS_EP_INFO);
1089 if (err < 0) {
1090 ump_dbg(ump, "Unable to get UMP EP info\n");
1091 goto error;
1092 }
1093
1094 /* Request Endpoint Device Info */
1095 err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_DEVICE_INFO,
1096 UMP_STREAM_MSG_STATUS_DEVICE_INFO);
1097 if (err < 0)
1098 ump_dbg(ump, "Unable to get UMP EP device info\n");
1099
1100 /* Request Endpoint Name */
1101 err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_EP_NAME,
1102 UMP_STREAM_MSG_STATUS_EP_NAME);
1103 if (err < 0)
1104 ump_dbg(ump, "Unable to get UMP EP name string\n");
1105
1106 ump_set_rawmidi_name(ump);
1107
1108 /* Request Endpoint Product ID */
1109 err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_PRODUCT_ID,
1110 UMP_STREAM_MSG_STATUS_PRODUCT_ID);
1111 if (err < 0)
1112 ump_dbg(ump, "Unable to get UMP EP product ID string\n");
1113
1114 /* Get the current stream configuration */
1115 err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_STREAM_CFG,
1116 UMP_STREAM_MSG_STATUS_STREAM_CFG);
1117 if (err < 0)
1118 ump_dbg(ump, "Unable to get UMP EP stream config\n");
1119
1120 /* If no protocol is set by some reason, assume the valid one */
1121 choose_default_protocol(ump);
1122
1123 /* Query and create blocks from Function Blocks */
1124 for (blk = 0; blk < ump->info.num_blocks; blk++) {
1125 err = create_block_from_fb_info(ump, blk);
1126 if (err < 0)
1127 continue;
1128 }
1129
1130 /* initialize group attributions */
1131 snd_ump_update_group_attrs(ump);
1132
1133 error:
1134 ump->parsed = true;
1135 ump_request_close(ump);
1136 if (err == -ETIMEDOUT)
1137 err = -ENODEV;
1138 return err;
1139 }
1140 EXPORT_SYMBOL_GPL(snd_ump_parse_endpoint);
1141
1142 #if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
1143 /*
1144 * Legacy rawmidi support
1145 */
snd_ump_legacy_open(struct snd_rawmidi_substream * substream)1146 static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream)
1147 {
1148 struct snd_ump_endpoint *ump = substream->rmidi->private_data;
1149 int dir = substream->stream;
1150 int group = ump->legacy_mapping[substream->number];
1151 int err;
1152
1153 guard(mutex)(&ump->open_mutex);
1154 if (ump->legacy_substreams[dir][group])
1155 return -EBUSY;
1156 if (!ump->groups[group].active)
1157 return -ENODEV;
1158 if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) {
1159 if (!ump->legacy_out_opens) {
1160 err = snd_rawmidi_kernel_open(&ump->core, 0,
1161 SNDRV_RAWMIDI_LFLG_OUTPUT |
1162 SNDRV_RAWMIDI_LFLG_APPEND,
1163 &ump->legacy_out_rfile);
1164 if (err < 0)
1165 return err;
1166 }
1167 ump->legacy_out_opens++;
1168 snd_ump_convert_reset(&ump->out_cvts[group]);
1169 }
1170 guard(spinlock_irq)(&ump->legacy_locks[dir]);
1171 ump->legacy_substreams[dir][group] = substream;
1172 return 0;
1173 }
1174
snd_ump_legacy_close(struct snd_rawmidi_substream * substream)1175 static int snd_ump_legacy_close(struct snd_rawmidi_substream *substream)
1176 {
1177 struct snd_ump_endpoint *ump = substream->rmidi->private_data;
1178 int dir = substream->stream;
1179 int group = ump->legacy_mapping[substream->number];
1180
1181 guard(mutex)(&ump->open_mutex);
1182 scoped_guard(spinlock_irq, &ump->legacy_locks[dir])
1183 ump->legacy_substreams[dir][group] = NULL;
1184 if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) {
1185 if (!--ump->legacy_out_opens)
1186 snd_rawmidi_kernel_release(&ump->legacy_out_rfile);
1187 }
1188 return 0;
1189 }
1190
snd_ump_legacy_trigger(struct snd_rawmidi_substream * substream,int up)1191 static void snd_ump_legacy_trigger(struct snd_rawmidi_substream *substream,
1192 int up)
1193 {
1194 struct snd_ump_endpoint *ump = substream->rmidi->private_data;
1195 int dir = substream->stream;
1196
1197 ump->ops->trigger(ump, dir, up);
1198 }
1199
snd_ump_legacy_drain(struct snd_rawmidi_substream * substream)1200 static void snd_ump_legacy_drain(struct snd_rawmidi_substream *substream)
1201 {
1202 struct snd_ump_endpoint *ump = substream->rmidi->private_data;
1203
1204 if (ump->ops->drain)
1205 ump->ops->drain(ump, SNDRV_RAWMIDI_STREAM_OUTPUT);
1206 }
1207
snd_ump_legacy_dev_register(struct snd_rawmidi * rmidi)1208 static int snd_ump_legacy_dev_register(struct snd_rawmidi *rmidi)
1209 {
1210 /* dummy, just for avoiding create superfluous seq clients */
1211 return 0;
1212 }
1213
1214 static const struct snd_rawmidi_ops snd_ump_legacy_input_ops = {
1215 .open = snd_ump_legacy_open,
1216 .close = snd_ump_legacy_close,
1217 .trigger = snd_ump_legacy_trigger,
1218 };
1219
1220 static const struct snd_rawmidi_ops snd_ump_legacy_output_ops = {
1221 .open = snd_ump_legacy_open,
1222 .close = snd_ump_legacy_close,
1223 .trigger = snd_ump_legacy_trigger,
1224 .drain = snd_ump_legacy_drain,
1225 };
1226
1227 static const struct snd_rawmidi_global_ops snd_ump_legacy_ops = {
1228 .dev_register = snd_ump_legacy_dev_register,
1229 };
1230
process_legacy_output(struct snd_ump_endpoint * ump,u32 * buffer,int count)1231 static int process_legacy_output(struct snd_ump_endpoint *ump,
1232 u32 *buffer, int count)
1233 {
1234 struct snd_rawmidi_substream *substream;
1235 struct ump_cvt_to_ump *ctx;
1236 const int dir = SNDRV_RAWMIDI_STREAM_OUTPUT;
1237 unsigned int protocol;
1238 unsigned char c;
1239 int group, size = 0;
1240
1241 if (!ump->out_cvts || !ump->legacy_out_opens)
1242 return 0;
1243
1244 guard(spinlock_irqsave)(&ump->legacy_locks[dir]);
1245 for (group = 0; group < SNDRV_UMP_MAX_GROUPS; group++) {
1246 substream = ump->legacy_substreams[dir][group];
1247 if (!substream)
1248 continue;
1249 ctx = &ump->out_cvts[group];
1250 protocol = ump->info.protocol;
1251 if ((protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI2) &&
1252 ump->groups[group].is_midi1)
1253 protocol = SNDRV_UMP_EP_INFO_PROTO_MIDI1;
1254 while (!ctx->ump_bytes &&
1255 snd_rawmidi_transmit(substream, &c, 1) > 0)
1256 snd_ump_convert_to_ump(ctx, group, protocol, c);
1257 if (ctx->ump_bytes && ctx->ump_bytes <= count) {
1258 size = ctx->ump_bytes;
1259 memcpy(buffer, ctx->ump, size);
1260 ctx->ump_bytes = 0;
1261 break;
1262 }
1263 }
1264 return size;
1265 }
1266
process_legacy_input(struct snd_ump_endpoint * ump,const u32 * src,int words)1267 static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src,
1268 int words)
1269 {
1270 struct snd_rawmidi_substream *substream;
1271 unsigned char buf[16];
1272 unsigned char group;
1273 const int dir = SNDRV_RAWMIDI_STREAM_INPUT;
1274 int size;
1275
1276 size = snd_ump_convert_from_ump(src, buf, &group);
1277 if (size <= 0)
1278 return;
1279 guard(spinlock_irqsave)(&ump->legacy_locks[dir]);
1280 substream = ump->legacy_substreams[dir][group];
1281 if (substream)
1282 snd_rawmidi_receive(substream, buf, size);
1283 }
1284
1285 /* Fill ump->legacy_mapping[] for groups to be used for legacy rawmidi */
fill_legacy_mapping(struct snd_ump_endpoint * ump)1286 static int fill_legacy_mapping(struct snd_ump_endpoint *ump)
1287 {
1288 struct snd_ump_block *fb;
1289 unsigned int group_maps = 0;
1290 int i, num;
1291
1292 if (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) {
1293 list_for_each_entry(fb, &ump->block_list, list) {
1294 for (i = 0; i < fb->info.num_groups; i++)
1295 group_maps |= 1U << (fb->info.first_group + i);
1296 }
1297 if (!group_maps)
1298 ump_info(ump, "No UMP Group is found in FB\n");
1299 }
1300
1301 /* use all groups for non-static case */
1302 if (!group_maps)
1303 group_maps = (1U << SNDRV_UMP_MAX_GROUPS) - 1;
1304
1305 num = 0;
1306 for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++)
1307 if (group_maps & (1U << i))
1308 ump->legacy_mapping[num++] = i;
1309
1310 return num;
1311 }
1312
update_legacy_substreams(struct snd_ump_endpoint * ump,struct snd_rawmidi * rmidi,int dir)1313 static void update_legacy_substreams(struct snd_ump_endpoint *ump,
1314 struct snd_rawmidi *rmidi, int dir)
1315 {
1316 struct snd_rawmidi_substream *s;
1317 const char *name;
1318 int idx;
1319
1320 list_for_each_entry(s, &rmidi->streams[dir].substreams, list) {
1321 idx = ump->legacy_mapping[s->number];
1322 name = ump->groups[idx].name;
1323 if (!*name)
1324 name = ump->core.name;
1325 scnprintf(s->name, sizeof(s->name), "Group %d (%.16s)%s",
1326 idx + 1, name,
1327 ump->groups[idx].active ? "" : " [Inactive]");
1328 s->inactive = !ump->groups[idx].active;
1329 }
1330 }
1331
update_legacy_names(struct snd_ump_endpoint * ump)1332 static void update_legacy_names(struct snd_ump_endpoint *ump)
1333 {
1334 struct snd_rawmidi *rmidi = ump->legacy_rmidi;
1335
1336 update_legacy_substreams(ump, rmidi, SNDRV_RAWMIDI_STREAM_INPUT);
1337 update_legacy_substreams(ump, rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT);
1338 }
1339
ump_legacy_set_rawmidi_name(struct snd_ump_endpoint * ump)1340 static void ump_legacy_set_rawmidi_name(struct snd_ump_endpoint *ump)
1341 {
1342 struct snd_rawmidi *rmidi = ump->legacy_rmidi;
1343
1344 snprintf(rmidi->name, sizeof(rmidi->name), "%.68s (MIDI 1.0)",
1345 ump->core.name);
1346 }
1347
snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint * ump,char * id,int device)1348 int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump,
1349 char *id, int device)
1350 {
1351 struct snd_rawmidi *rmidi;
1352 bool input, output;
1353 int err, num;
1354
1355 ump->out_cvts = kcalloc(SNDRV_UMP_MAX_GROUPS,
1356 sizeof(*ump->out_cvts), GFP_KERNEL);
1357 if (!ump->out_cvts)
1358 return -ENOMEM;
1359
1360 num = fill_legacy_mapping(ump);
1361
1362 input = ump->core.info_flags & SNDRV_RAWMIDI_INFO_INPUT;
1363 output = ump->core.info_flags & SNDRV_RAWMIDI_INFO_OUTPUT;
1364 err = snd_rawmidi_new(ump->core.card, id, device,
1365 output ? num : 0, input ? num : 0,
1366 &rmidi);
1367 if (err < 0) {
1368 kfree(ump->out_cvts);
1369 return err;
1370 }
1371
1372 if (input)
1373 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
1374 &snd_ump_legacy_input_ops);
1375 if (output)
1376 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
1377 &snd_ump_legacy_output_ops);
1378 rmidi->info_flags = ump->core.info_flags & ~SNDRV_RAWMIDI_INFO_UMP;
1379 rmidi->ops = &snd_ump_legacy_ops;
1380 rmidi->private_data = ump;
1381 ump->legacy_rmidi = rmidi;
1382 ump_legacy_set_rawmidi_name(ump);
1383 update_legacy_names(ump);
1384
1385 snd_rawmidi_tie_devices(rmidi, &ump->core);
1386
1387 ump_dbg(ump, "Created a legacy rawmidi #%d (%s)\n", device, id);
1388 return 0;
1389 }
1390 EXPORT_SYMBOL_GPL(snd_ump_attach_legacy_rawmidi);
1391 #endif /* CONFIG_SND_UMP_LEGACY_RAWMIDI */
1392
1393 MODULE_DESCRIPTION("Universal MIDI Packet (UMP) Core Driver");
1394 MODULE_LICENSE("GPL");
1395