xref: /linux/sound/core/ump.c (revision 2c1ed907520c50326b8f604907a8478b27881a2e)
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