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