xref: /openbmc/linux/sound/core/ump.c (revision 9144f784f852f9a125cabe9927b986d909bfa439)
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
process_legacy_output(struct snd_ump_endpoint * ump,u32 * buffer,int count)42  static inline int process_legacy_output(struct snd_ump_endpoint *ump,
43  					u32 *buffer, int count)
44  {
45  	return 0;
46  }
process_legacy_input(struct snd_ump_endpoint * ump,const u32 * src,int words)47  static inline void process_legacy_input(struct snd_ump_endpoint *ump,
48  					const u32 *src, int words)
49  {
50  }
update_legacy_names(struct snd_ump_endpoint * ump)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  
snd_ump_endpoint_free(struct snd_rawmidi * rmidi)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   */
snd_ump_endpoint_new(struct snd_card * card,char * id,int device,int output,int input,struct snd_ump_endpoint ** ump_ret)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)
snd_ump_dev_seq_free(struct snd_seq_device * device)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  
snd_ump_dev_register(struct snd_rawmidi * rmidi)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  
snd_ump_dev_unregister(struct snd_rawmidi * rmidi)203  static int snd_ump_dev_unregister(struct snd_rawmidi *rmidi)
204  {
205  	return 0;
206  }
207  
208  static struct snd_ump_block *
snd_ump_get_block(struct snd_ump_endpoint * ump,unsigned char id)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   */
snd_ump_rawmidi_open(struct snd_rawmidi_substream * substream)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  
snd_ump_rawmidi_close(struct snd_rawmidi_substream * substream)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  
snd_ump_rawmidi_trigger(struct snd_rawmidi_substream * substream,int up)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  
snd_ump_rawmidi_drain(struct snd_rawmidi_substream * substream)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   */
snd_ump_receive_ump_val(struct snd_ump_endpoint * ump,u32 val)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   */
snd_ump_receive(struct snd_ump_endpoint * ump,const u32 * buffer,int count)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   */
snd_ump_transmit(struct snd_ump_endpoint * ump,u32 * buffer,int count)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   */
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)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 < 0 || 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 %d-%d",
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  
snd_ump_ioctl_block(struct snd_ump_endpoint * ump,struct snd_ump_block_info __user * argp)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   */
snd_ump_ioctl(struct snd_rawmidi * rmidi,unsigned int cmd,void __user * argp)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  
ump_direction_string(int dir)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  
ump_ui_hint_string(int dir)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 */
snd_ump_proc_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)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%02x%02x%02x%02x\n",
497  			    ump->info.sw_revision[0],
498  			    ump->info.sw_revision[1],
499  			    ump->info.sw_revision[2],
500  			    ump->info.sw_revision[3]);
501  	}
502  	snd_iprintf(buffer, "Static Blocks: %s\n",
503  		    (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) ? "Yes" : "No");
504  	snd_iprintf(buffer, "Num Blocks: %d\n\n", ump->info.num_blocks);
505  
506  	list_for_each_entry(fb, &ump->block_list, list) {
507  		snd_iprintf(buffer, "Block %d (%s)\n", fb->info.block_id,
508  			    fb->info.name);
509  		snd_iprintf(buffer, "  Direction: %s\n",
510  			    ump_direction_string(fb->info.direction));
511  		snd_iprintf(buffer, "  Active: %s\n",
512  			    fb->info.active ? "Yes" : "No");
513  		snd_iprintf(buffer, "  Groups: %d-%d\n",
514  			    fb->info.first_group + 1,
515  			    fb->info.first_group + fb->info.num_groups);
516  		snd_iprintf(buffer, "  Is MIDI1: %s%s\n",
517  			    (fb->info.flags & SNDRV_UMP_BLOCK_IS_MIDI1) ? "Yes" : "No",
518  			    (fb->info.flags & SNDRV_UMP_BLOCK_IS_LOWSPEED) ? " (Low Speed)" : "");
519  		if (ump->info.version) {
520  			snd_iprintf(buffer, "  MIDI-CI Version: %d\n",
521  				    fb->info.midi_ci_version);
522  			snd_iprintf(buffer, "  Sysex8 Streams: %d\n",
523  				    fb->info.sysex8_streams);
524  			snd_iprintf(buffer, "  UI Hint: %s\n",
525  				    ump_ui_hint_string(fb->info.ui_hint));
526  		}
527  		snd_iprintf(buffer, "\n");
528  	}
529  }
530  
531  /* update dir_bits and active flag for all groups in the client */
snd_ump_update_group_attrs(struct snd_ump_endpoint * ump)532  void snd_ump_update_group_attrs(struct snd_ump_endpoint *ump)
533  {
534  	struct snd_ump_block *fb;
535  	struct snd_ump_group *group;
536  	int i;
537  
538  	for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
539  		group = &ump->groups[i];
540  		*group->name = 0;
541  		group->dir_bits = 0;
542  		group->active = 0;
543  		group->group = i;
544  		group->valid = false;
545  	}
546  
547  	list_for_each_entry(fb, &ump->block_list, list) {
548  		if (fb->info.first_group + fb->info.num_groups > SNDRV_UMP_MAX_GROUPS)
549  			break;
550  		group = &ump->groups[fb->info.first_group];
551  		for (i = 0; i < fb->info.num_groups; i++, group++) {
552  			group->valid = true;
553  			if (fb->info.active)
554  				group->active = 1;
555  			switch (fb->info.direction) {
556  			case SNDRV_UMP_DIR_INPUT:
557  				group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_INPUT);
558  				break;
559  			case SNDRV_UMP_DIR_OUTPUT:
560  				group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_OUTPUT);
561  				break;
562  			case SNDRV_UMP_DIR_BIDIRECTION:
563  				group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_INPUT) |
564  					(1 << SNDRV_RAWMIDI_STREAM_OUTPUT);
565  				break;
566  			}
567  			if (!*fb->info.name)
568  				continue;
569  			if (!*group->name) {
570  				/* store the first matching name */
571  				strscpy(group->name, fb->info.name,
572  					sizeof(group->name));
573  			} else {
574  				/* when overlapping, concat names */
575  				strlcat(group->name, ", ", sizeof(group->name));
576  				strlcat(group->name, fb->info.name,
577  					sizeof(group->name));
578  			}
579  		}
580  	}
581  }
582  EXPORT_SYMBOL_GPL(snd_ump_update_group_attrs);
583  
584  /*
585   * UMP endpoint and function block handling
586   */
587  
588  /* open / close UMP streams for the internal stream msg communication */
ump_request_open(struct snd_ump_endpoint * ump)589  static int ump_request_open(struct snd_ump_endpoint *ump)
590  {
591  	return snd_rawmidi_kernel_open(&ump->core, 0,
592  				       SNDRV_RAWMIDI_LFLG_OUTPUT,
593  				       &ump->stream_rfile);
594  }
595  
ump_request_close(struct snd_ump_endpoint * ump)596  static void ump_request_close(struct snd_ump_endpoint *ump)
597  {
598  	snd_rawmidi_kernel_release(&ump->stream_rfile);
599  }
600  
601  /* request a command and wait for the given response;
602   * @req1 and @req2 are u32 commands
603   * @reply is the expected UMP stream status
604   */
ump_req_msg(struct snd_ump_endpoint * ump,u32 req1,u32 req2,u32 reply)605  static int ump_req_msg(struct snd_ump_endpoint *ump, u32 req1, u32 req2,
606  		       u32 reply)
607  {
608  	u32 buf[4];
609  
610  	ump_dbg(ump, "%s: request %08x %08x, wait-for %08x\n",
611  		__func__, req1, req2, reply);
612  	memset(buf, 0, sizeof(buf));
613  	buf[0] = req1;
614  	buf[1] = req2;
615  	ump->stream_finished = 0;
616  	ump->stream_wait_for = reply;
617  	snd_rawmidi_kernel_write(ump->stream_rfile.output,
618  				 (unsigned char *)&buf, 16);
619  	wait_event_timeout(ump->stream_wait, ump->stream_finished,
620  			   msecs_to_jiffies(500));
621  	if (!READ_ONCE(ump->stream_finished)) {
622  		ump_dbg(ump, "%s: request timed out\n", __func__);
623  		return -ETIMEDOUT;
624  	}
625  	ump->stream_finished = 0;
626  	ump_dbg(ump, "%s: reply: %08x %08x %08x %08x\n",
627  		__func__, buf[0], buf[1], buf[2], buf[3]);
628  	return 0;
629  }
630  
631  /* append the received letters via UMP packet to the given string buffer;
632   * return 1 if the full string is received or 0 to continue
633   */
ump_append_string(struct snd_ump_endpoint * ump,char * dest,int maxsize,const u32 * buf,int offset)634  static int ump_append_string(struct snd_ump_endpoint *ump, char *dest,
635  			     int maxsize, const u32 *buf, int offset)
636  {
637  	unsigned char format;
638  	int c;
639  
640  	format = ump_stream_message_format(buf[0]);
641  	if (format == UMP_STREAM_MSG_FORMAT_SINGLE ||
642  	    format == UMP_STREAM_MSG_FORMAT_START) {
643  		c = 0;
644  	} else {
645  		c = strlen(dest);
646  		if (c >= maxsize - 1)
647  			return 1;
648  	}
649  
650  	for (; offset < 16; offset++) {
651  		dest[c] = buf[offset / 4] >> (3 - (offset % 4)) * 8;
652  		if (!dest[c])
653  			break;
654  		if (++c >= maxsize - 1)
655  			break;
656  	}
657  	dest[c] = 0;
658  	return (format == UMP_STREAM_MSG_FORMAT_SINGLE ||
659  		format == UMP_STREAM_MSG_FORMAT_END);
660  }
661  
662  /* 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)663  static int ump_handle_ep_info_msg(struct snd_ump_endpoint *ump,
664  				  const union snd_ump_stream_msg *buf)
665  {
666  	ump->info.version = (buf->ep_info.ump_version_major << 8) |
667  		buf->ep_info.ump_version_minor;
668  	ump->info.num_blocks = buf->ep_info.num_function_blocks;
669  	if (ump->info.num_blocks > SNDRV_UMP_MAX_BLOCKS) {
670  		ump_info(ump, "Invalid function blocks %d, fallback to 1\n",
671  			 ump->info.num_blocks);
672  		ump->info.num_blocks = 1;
673  	}
674  
675  	if (buf->ep_info.static_function_block)
676  		ump->info.flags |= SNDRV_UMP_EP_INFO_STATIC_BLOCKS;
677  
678  	ump->info.protocol_caps = (buf->ep_info.protocol << 8) |
679  		buf->ep_info.jrts;
680  
681  	ump_dbg(ump, "EP info: version=%x, num_blocks=%x, proto_caps=%x\n",
682  		ump->info.version, ump->info.num_blocks, ump->info.protocol_caps);
683  	return 1; /* finished */
684  }
685  
686  /* 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)687  static int ump_handle_device_info_msg(struct snd_ump_endpoint *ump,
688  				      const union snd_ump_stream_msg *buf)
689  {
690  	ump->info.manufacturer_id = buf->device_info.manufacture_id & 0x7f7f7f;
691  	ump->info.family_id = (buf->device_info.family_msb << 8) |
692  		buf->device_info.family_lsb;
693  	ump->info.model_id = (buf->device_info.model_msb << 8) |
694  		buf->device_info.model_lsb;
695  	ump->info.sw_revision[0] = (buf->device_info.sw_revision >> 24) & 0x7f;
696  	ump->info.sw_revision[1] = (buf->device_info.sw_revision >> 16) & 0x7f;
697  	ump->info.sw_revision[2] = (buf->device_info.sw_revision >> 8) & 0x7f;
698  	ump->info.sw_revision[3] = buf->device_info.sw_revision & 0x7f;
699  	ump_dbg(ump, "EP devinfo: manid=%08x, family=%04x, model=%04x, sw=%02x%02x%02x%02x\n",
700  		ump->info.manufacturer_id,
701  		ump->info.family_id,
702  		ump->info.model_id,
703  		ump->info.sw_revision[0],
704  		ump->info.sw_revision[1],
705  		ump->info.sw_revision[2],
706  		ump->info.sw_revision[3]);
707  	return 1; /* finished */
708  }
709  
710  /* 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)711  static int ump_handle_ep_name_msg(struct snd_ump_endpoint *ump,
712  				  const union snd_ump_stream_msg *buf)
713  {
714  	return ump_append_string(ump, ump->info.name, sizeof(ump->info.name),
715  				 buf->raw, 2);
716  }
717  
718  /* 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)719  static int ump_handle_product_id_msg(struct snd_ump_endpoint *ump,
720  				     const union snd_ump_stream_msg *buf)
721  {
722  	return ump_append_string(ump, ump->info.product_id,
723  				 sizeof(ump->info.product_id),
724  				 buf->raw, 2);
725  }
726  
727  /* notify the protocol change to sequencer */
seq_notify_protocol(struct snd_ump_endpoint * ump)728  static void seq_notify_protocol(struct snd_ump_endpoint *ump)
729  {
730  #if IS_ENABLED(CONFIG_SND_SEQUENCER)
731  	if (ump->seq_ops && ump->seq_ops->switch_protocol)
732  		ump->seq_ops->switch_protocol(ump);
733  #endif /* CONFIG_SND_SEQUENCER */
734  }
735  
736  /**
737   * snd_ump_switch_protocol - switch MIDI protocol
738   * @ump: UMP endpoint
739   * @protocol: protocol to switch to
740   *
741   * Returns 1 if the protocol is actually switched, 0 if unchanged
742   */
snd_ump_switch_protocol(struct snd_ump_endpoint * ump,unsigned int protocol)743  int snd_ump_switch_protocol(struct snd_ump_endpoint *ump, unsigned int protocol)
744  {
745  	unsigned int type;
746  
747  	protocol &= ump->info.protocol_caps;
748  	if (protocol == ump->info.protocol)
749  		return 0;
750  
751  	type = protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK;
752  	if (type != SNDRV_UMP_EP_INFO_PROTO_MIDI1 &&
753  	    type != SNDRV_UMP_EP_INFO_PROTO_MIDI2)
754  		return 0;
755  
756  	ump->info.protocol = protocol;
757  	ump_dbg(ump, "New protocol = %x (caps = %x)\n",
758  		protocol, ump->info.protocol_caps);
759  	seq_notify_protocol(ump);
760  	return 1;
761  }
762  EXPORT_SYMBOL_GPL(snd_ump_switch_protocol);
763  
764  /* 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)765  static int ump_handle_stream_cfg_msg(struct snd_ump_endpoint *ump,
766  				     const union snd_ump_stream_msg *buf)
767  {
768  	unsigned int protocol =
769  		(buf->stream_cfg.protocol << 8) | buf->stream_cfg.jrts;
770  
771  	snd_ump_switch_protocol(ump, protocol);
772  	return 1; /* finished */
773  }
774  
775  /* 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)776  static void fill_fb_info(struct snd_ump_endpoint *ump,
777  			 struct snd_ump_block_info *info,
778  			 const union snd_ump_stream_msg *buf)
779  {
780  	info->direction = buf->fb_info.direction;
781  	info->ui_hint = buf->fb_info.ui_hint;
782  	info->first_group = buf->fb_info.first_group;
783  	info->num_groups = buf->fb_info.num_groups;
784  	if (buf->fb_info.midi_10 < 2)
785  		info->flags = buf->fb_info.midi_10;
786  	else
787  		info->flags = SNDRV_UMP_BLOCK_IS_MIDI1 | SNDRV_UMP_BLOCK_IS_LOWSPEED;
788  	info->active = buf->fb_info.active;
789  	info->midi_ci_version = buf->fb_info.midi_ci_version;
790  	info->sysex8_streams = buf->fb_info.sysex8_streams;
791  
792  	ump_dbg(ump, "FB %d: dir=%d, active=%d, first_gp=%d, num_gp=%d, midici=%d, sysex8=%d, flags=0x%x\n",
793  		info->block_id, info->direction, info->active,
794  		info->first_group, info->num_groups, info->midi_ci_version,
795  		info->sysex8_streams, info->flags);
796  
797  	if ((info->flags & SNDRV_UMP_BLOCK_IS_MIDI1) && info->num_groups != 1) {
798  		info->num_groups = 1;
799  		ump_dbg(ump, "FB %d: corrected groups to 1 for MIDI1\n",
800  			info->block_id);
801  	}
802  }
803  
804  /* 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)805  static bool is_fb_info_updated(struct snd_ump_endpoint *ump,
806  			       struct snd_ump_block *fb,
807  			       const union snd_ump_stream_msg *buf)
808  {
809  	char tmpbuf[offsetof(struct snd_ump_block_info, name)];
810  
811  	if (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) {
812  		ump_info(ump, "Skipping static FB info update (blk#%d)\n",
813  			 fb->info.block_id);
814  		return 0;
815  	}
816  
817  	memcpy(tmpbuf, &fb->info, sizeof(tmpbuf));
818  	fill_fb_info(ump, (struct snd_ump_block_info *)tmpbuf, buf);
819  	return memcmp(&fb->info, tmpbuf, sizeof(tmpbuf)) != 0;
820  }
821  
822  /* notify the FB info/name change to sequencer */
seq_notify_fb_change(struct snd_ump_endpoint * ump,struct snd_ump_block * fb)823  static void seq_notify_fb_change(struct snd_ump_endpoint *ump,
824  				 struct snd_ump_block *fb)
825  {
826  #if IS_ENABLED(CONFIG_SND_SEQUENCER)
827  	if (ump->seq_ops && ump->seq_ops->notify_fb_change)
828  		ump->seq_ops->notify_fb_change(ump, fb);
829  #endif
830  }
831  
832  /* 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)833  static int ump_handle_fb_info_msg(struct snd_ump_endpoint *ump,
834  				  const union snd_ump_stream_msg *buf)
835  {
836  	unsigned char blk;
837  	struct snd_ump_block *fb;
838  
839  	blk = buf->fb_info.function_block_id;
840  	fb = snd_ump_get_block(ump, blk);
841  
842  	/* complain only if updated after parsing */
843  	if (!fb && ump->parsed) {
844  		ump_info(ump, "Function Block Info Update for non-existing block %d\n",
845  			 blk);
846  		return -ENODEV;
847  	}
848  
849  	/* When updated after the initial parse, check the FB info update */
850  	if (ump->parsed && !is_fb_info_updated(ump, fb, buf))
851  		return 1; /* no content change */
852  
853  	if (fb) {
854  		fill_fb_info(ump, &fb->info, buf);
855  		if (ump->parsed) {
856  			snd_ump_update_group_attrs(ump);
857  			update_legacy_names(ump);
858  			seq_notify_fb_change(ump, fb);
859  		}
860  	}
861  
862  	return 1; /* finished */
863  }
864  
865  /* 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)866  static int ump_handle_fb_name_msg(struct snd_ump_endpoint *ump,
867  				  const union snd_ump_stream_msg *buf)
868  {
869  	unsigned char blk;
870  	struct snd_ump_block *fb;
871  	int ret;
872  
873  	blk = buf->fb_name.function_block_id;
874  	fb = snd_ump_get_block(ump, blk);
875  	if (!fb)
876  		return -ENODEV;
877  
878  	if (ump->parsed &&
879  	    (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS)) {
880  		ump_dbg(ump, "Skipping static FB name update (blk#%d)\n",
881  			fb->info.block_id);
882  		return 0;
883  	}
884  
885  	ret = ump_append_string(ump, fb->info.name, sizeof(fb->info.name),
886  				buf->raw, 3);
887  	/* notify the FB name update to sequencer, too */
888  	if (ret > 0 && ump->parsed) {
889  		snd_ump_update_group_attrs(ump);
890  		update_legacy_names(ump);
891  		seq_notify_fb_change(ump, fb);
892  	}
893  	return ret;
894  }
895  
create_block_from_fb_info(struct snd_ump_endpoint * ump,int blk)896  static int create_block_from_fb_info(struct snd_ump_endpoint *ump, int blk)
897  {
898  	struct snd_ump_block *fb;
899  	unsigned char direction, first_group, num_groups;
900  	const union snd_ump_stream_msg *buf =
901  		(const union snd_ump_stream_msg *)ump->input_buf;
902  	u32 msg;
903  	int err;
904  
905  	/* query the FB info once */
906  	msg = ump_stream_compose(UMP_STREAM_MSG_STATUS_FB_DISCOVERY, 0) |
907  		(blk << 8) | UMP_STREAM_MSG_REQUEST_FB_INFO;
908  	err = ump_req_msg(ump, msg, 0, UMP_STREAM_MSG_STATUS_FB_INFO);
909  	if (err < 0) {
910  		ump_dbg(ump, "Unable to get FB info for block %d\n", blk);
911  		return err;
912  	}
913  
914  	/* the last input must be the FB info */
915  	if (buf->fb_info.status != UMP_STREAM_MSG_STATUS_FB_INFO) {
916  		ump_dbg(ump, "Inconsistent input: 0x%x\n", *buf->raw);
917  		return -EINVAL;
918  	}
919  
920  	direction = buf->fb_info.direction;
921  	first_group = buf->fb_info.first_group;
922  	num_groups = buf->fb_info.num_groups;
923  
924  	err = snd_ump_block_new(ump, blk, direction, first_group, num_groups,
925  				&fb);
926  	if (err < 0)
927  		return err;
928  
929  	fill_fb_info(ump, &fb->info, buf);
930  
931  	msg = ump_stream_compose(UMP_STREAM_MSG_STATUS_FB_DISCOVERY, 0) |
932  		(blk << 8) | UMP_STREAM_MSG_REQUEST_FB_NAME;
933  	err = ump_req_msg(ump, msg, 0, UMP_STREAM_MSG_STATUS_FB_NAME);
934  	if (err)
935  		ump_dbg(ump, "Unable to get UMP FB name string #%d\n", blk);
936  
937  	return 0;
938  }
939  
940  /* handle stream messages, called from snd_ump_receive() */
ump_handle_stream_msg(struct snd_ump_endpoint * ump,const u32 * buf,int size)941  static void ump_handle_stream_msg(struct snd_ump_endpoint *ump,
942  				  const u32 *buf, int size)
943  {
944  	const union snd_ump_stream_msg *msg;
945  	unsigned int status;
946  	int ret;
947  
948  	/* UMP stream message suppressed (for gadget UMP)? */
949  	if (ump->no_process_stream)
950  		return;
951  
952  	BUILD_BUG_ON(sizeof(*msg) != 16);
953  	ump_dbg(ump, "Stream msg: %08x %08x %08x %08x\n",
954  		buf[0], buf[1], buf[2], buf[3]);
955  
956  	if (size != 4 || ump_message_type(*buf) != UMP_MSG_TYPE_STREAM)
957  		return;
958  
959  	msg = (const union snd_ump_stream_msg *)buf;
960  	status = ump_stream_message_status(*buf);
961  	switch (status) {
962  	case UMP_STREAM_MSG_STATUS_EP_INFO:
963  		ret = ump_handle_ep_info_msg(ump, msg);
964  		break;
965  	case UMP_STREAM_MSG_STATUS_DEVICE_INFO:
966  		ret = ump_handle_device_info_msg(ump, msg);
967  		break;
968  	case UMP_STREAM_MSG_STATUS_EP_NAME:
969  		ret = ump_handle_ep_name_msg(ump, msg);
970  		break;
971  	case UMP_STREAM_MSG_STATUS_PRODUCT_ID:
972  		ret = ump_handle_product_id_msg(ump, msg);
973  		break;
974  	case UMP_STREAM_MSG_STATUS_STREAM_CFG:
975  		ret = ump_handle_stream_cfg_msg(ump, msg);
976  		break;
977  	case UMP_STREAM_MSG_STATUS_FB_INFO:
978  		ret = ump_handle_fb_info_msg(ump, msg);
979  		break;
980  	case UMP_STREAM_MSG_STATUS_FB_NAME:
981  		ret = ump_handle_fb_name_msg(ump, msg);
982  		break;
983  	default:
984  		return;
985  	}
986  
987  	/* when the message has been processed fully, wake up */
988  	if (ret > 0 && ump->stream_wait_for == status) {
989  		WRITE_ONCE(ump->stream_finished, 1);
990  		wake_up(&ump->stream_wait);
991  	}
992  }
993  
994  /**
995   * snd_ump_parse_endpoint - parse endpoint and create function blocks
996   * @ump: UMP object
997   *
998   * Returns 0 for successful parse, -ENODEV if device doesn't respond
999   * (or the query is unsupported), or other error code for serious errors.
1000   */
snd_ump_parse_endpoint(struct snd_ump_endpoint * ump)1001  int snd_ump_parse_endpoint(struct snd_ump_endpoint *ump)
1002  {
1003  	int blk, err;
1004  	u32 msg;
1005  
1006  	if (!(ump->core.info_flags & SNDRV_RAWMIDI_INFO_DUPLEX))
1007  		return -ENODEV;
1008  
1009  	err = ump_request_open(ump);
1010  	if (err < 0) {
1011  		ump_dbg(ump, "Unable to open rawmidi device: %d\n", err);
1012  		return err;
1013  	}
1014  
1015  	/* Check Endpoint Information */
1016  	msg = ump_stream_compose(UMP_STREAM_MSG_STATUS_EP_DISCOVERY, 0) |
1017  		0x0101; /* UMP version 1.1 */
1018  	err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_EP_INFO,
1019  			  UMP_STREAM_MSG_STATUS_EP_INFO);
1020  	if (err < 0) {
1021  		ump_dbg(ump, "Unable to get UMP EP info\n");
1022  		goto error;
1023  	}
1024  
1025  	/* Request Endpoint Device Info */
1026  	err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_DEVICE_INFO,
1027  			  UMP_STREAM_MSG_STATUS_DEVICE_INFO);
1028  	if (err < 0)
1029  		ump_dbg(ump, "Unable to get UMP EP device info\n");
1030  
1031  	/* Request Endpoint Name */
1032  	err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_EP_NAME,
1033  			  UMP_STREAM_MSG_STATUS_EP_NAME);
1034  	if (err < 0)
1035  		ump_dbg(ump, "Unable to get UMP EP name string\n");
1036  
1037  	/* Request Endpoint Product ID */
1038  	err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_PRODUCT_ID,
1039  			  UMP_STREAM_MSG_STATUS_PRODUCT_ID);
1040  	if (err < 0)
1041  		ump_dbg(ump, "Unable to get UMP EP product ID string\n");
1042  
1043  	/* Get the current stream configuration */
1044  	err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_STREAM_CFG,
1045  			  UMP_STREAM_MSG_STATUS_STREAM_CFG);
1046  	if (err < 0)
1047  		ump_dbg(ump, "Unable to get UMP EP stream config\n");
1048  
1049  	/* If no protocol is set by some reason, assume the valid one */
1050  	if (!(ump->info.protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK)) {
1051  		if (ump->info.protocol_caps & SNDRV_UMP_EP_INFO_PROTO_MIDI2)
1052  			ump->info.protocol |= SNDRV_UMP_EP_INFO_PROTO_MIDI2;
1053  		else if (ump->info.protocol_caps & SNDRV_UMP_EP_INFO_PROTO_MIDI1)
1054  			ump->info.protocol |= SNDRV_UMP_EP_INFO_PROTO_MIDI1;
1055  	}
1056  
1057  	/* Query and create blocks from Function Blocks */
1058  	for (blk = 0; blk < ump->info.num_blocks; blk++) {
1059  		err = create_block_from_fb_info(ump, blk);
1060  		if (err < 0)
1061  			continue;
1062  	}
1063  
1064  	/* initialize group attributions */
1065  	snd_ump_update_group_attrs(ump);
1066  
1067   error:
1068  	ump->parsed = true;
1069  	ump_request_close(ump);
1070  	if (err == -ETIMEDOUT)
1071  		err = -ENODEV;
1072  	return err;
1073  }
1074  EXPORT_SYMBOL_GPL(snd_ump_parse_endpoint);
1075  
1076  #if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
1077  /*
1078   * Legacy rawmidi support
1079   */
snd_ump_legacy_open(struct snd_rawmidi_substream * substream)1080  static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream)
1081  {
1082  	struct snd_ump_endpoint *ump = substream->rmidi->private_data;
1083  	int dir = substream->stream;
1084  	int group = ump->legacy_mapping[substream->number];
1085  	int err;
1086  
1087  	guard(mutex)(&ump->open_mutex);
1088  	if (ump->legacy_substreams[dir][group])
1089  		return -EBUSY;
1090  	if (!ump->groups[group].active)
1091  		return -ENODEV;
1092  	if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) {
1093  		if (!ump->legacy_out_opens) {
1094  			err = snd_rawmidi_kernel_open(&ump->core, 0,
1095  						      SNDRV_RAWMIDI_LFLG_OUTPUT |
1096  						      SNDRV_RAWMIDI_LFLG_APPEND,
1097  						      &ump->legacy_out_rfile);
1098  			if (err < 0)
1099  				return err;
1100  		}
1101  		ump->legacy_out_opens++;
1102  		snd_ump_convert_reset(&ump->out_cvts[group]);
1103  	}
1104  	guard(spinlock_irq)(&ump->legacy_locks[dir]);
1105  	ump->legacy_substreams[dir][group] = substream;
1106  	return 0;
1107  }
1108  
snd_ump_legacy_close(struct snd_rawmidi_substream * substream)1109  static int snd_ump_legacy_close(struct snd_rawmidi_substream *substream)
1110  {
1111  	struct snd_ump_endpoint *ump = substream->rmidi->private_data;
1112  	int dir = substream->stream;
1113  	int group = ump->legacy_mapping[substream->number];
1114  
1115  	guard(mutex)(&ump->open_mutex);
1116  	scoped_guard(spinlock_irq, &ump->legacy_locks[dir])
1117  		ump->legacy_substreams[dir][group] = NULL;
1118  	if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) {
1119  		if (!--ump->legacy_out_opens)
1120  			snd_rawmidi_kernel_release(&ump->legacy_out_rfile);
1121  	}
1122  	return 0;
1123  }
1124  
snd_ump_legacy_trigger(struct snd_rawmidi_substream * substream,int up)1125  static void snd_ump_legacy_trigger(struct snd_rawmidi_substream *substream,
1126  				   int up)
1127  {
1128  	struct snd_ump_endpoint *ump = substream->rmidi->private_data;
1129  	int dir = substream->stream;
1130  
1131  	ump->ops->trigger(ump, dir, up);
1132  }
1133  
snd_ump_legacy_drain(struct snd_rawmidi_substream * substream)1134  static void snd_ump_legacy_drain(struct snd_rawmidi_substream *substream)
1135  {
1136  	struct snd_ump_endpoint *ump = substream->rmidi->private_data;
1137  
1138  	if (ump->ops->drain)
1139  		ump->ops->drain(ump, SNDRV_RAWMIDI_STREAM_OUTPUT);
1140  }
1141  
snd_ump_legacy_dev_register(struct snd_rawmidi * rmidi)1142  static int snd_ump_legacy_dev_register(struct snd_rawmidi *rmidi)
1143  {
1144  	/* dummy, just for avoiding create superfluous seq clients */
1145  	return 0;
1146  }
1147  
1148  static const struct snd_rawmidi_ops snd_ump_legacy_input_ops = {
1149  	.open = snd_ump_legacy_open,
1150  	.close = snd_ump_legacy_close,
1151  	.trigger = snd_ump_legacy_trigger,
1152  };
1153  
1154  static const struct snd_rawmidi_ops snd_ump_legacy_output_ops = {
1155  	.open = snd_ump_legacy_open,
1156  	.close = snd_ump_legacy_close,
1157  	.trigger = snd_ump_legacy_trigger,
1158  	.drain = snd_ump_legacy_drain,
1159  };
1160  
1161  static const struct snd_rawmidi_global_ops snd_ump_legacy_ops = {
1162  	.dev_register = snd_ump_legacy_dev_register,
1163  };
1164  
process_legacy_output(struct snd_ump_endpoint * ump,u32 * buffer,int count)1165  static int process_legacy_output(struct snd_ump_endpoint *ump,
1166  				 u32 *buffer, int count)
1167  {
1168  	struct snd_rawmidi_substream *substream;
1169  	struct ump_cvt_to_ump *ctx;
1170  	const int dir = SNDRV_RAWMIDI_STREAM_OUTPUT;
1171  	unsigned char c;
1172  	int group, size = 0;
1173  
1174  	if (!ump->out_cvts || !ump->legacy_out_opens)
1175  		return 0;
1176  
1177  	guard(spinlock_irqsave)(&ump->legacy_locks[dir]);
1178  	for (group = 0; group < SNDRV_UMP_MAX_GROUPS; group++) {
1179  		substream = ump->legacy_substreams[dir][group];
1180  		if (!substream)
1181  			continue;
1182  		ctx = &ump->out_cvts[group];
1183  		while (!ctx->ump_bytes &&
1184  		       snd_rawmidi_transmit(substream, &c, 1) > 0)
1185  			snd_ump_convert_to_ump(ctx, group, ump->info.protocol, c);
1186  		if (ctx->ump_bytes && ctx->ump_bytes <= count) {
1187  			size = ctx->ump_bytes;
1188  			memcpy(buffer, ctx->ump, size);
1189  			ctx->ump_bytes = 0;
1190  			break;
1191  		}
1192  	}
1193  	return size;
1194  }
1195  
process_legacy_input(struct snd_ump_endpoint * ump,const u32 * src,int words)1196  static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src,
1197  				 int words)
1198  {
1199  	struct snd_rawmidi_substream *substream;
1200  	unsigned char buf[16];
1201  	unsigned char group;
1202  	const int dir = SNDRV_RAWMIDI_STREAM_INPUT;
1203  	int size;
1204  
1205  	size = snd_ump_convert_from_ump(src, buf, &group);
1206  	if (size <= 0)
1207  		return;
1208  	guard(spinlock_irqsave)(&ump->legacy_locks[dir]);
1209  	substream = ump->legacy_substreams[dir][group];
1210  	if (substream)
1211  		snd_rawmidi_receive(substream, buf, size);
1212  }
1213  
1214  /* Fill ump->legacy_mapping[] for groups to be used for legacy rawmidi */
fill_legacy_mapping(struct snd_ump_endpoint * ump)1215  static int fill_legacy_mapping(struct snd_ump_endpoint *ump)
1216  {
1217  	struct snd_ump_block *fb;
1218  	unsigned int group_maps = 0;
1219  	int i, num;
1220  
1221  	if (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) {
1222  		list_for_each_entry(fb, &ump->block_list, list) {
1223  			for (i = 0; i < fb->info.num_groups; i++)
1224  				group_maps |= 1U << (fb->info.first_group + i);
1225  		}
1226  		if (!group_maps)
1227  			ump_info(ump, "No UMP Group is found in FB\n");
1228  	}
1229  
1230  	/* use all groups for non-static case */
1231  	if (!group_maps)
1232  		group_maps = (1U << SNDRV_UMP_MAX_GROUPS) - 1;
1233  
1234  	num = 0;
1235  	for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++)
1236  		if (group_maps & (1U << i))
1237  			ump->legacy_mapping[num++] = i;
1238  
1239  	return num;
1240  }
1241  
fill_substream_names(struct snd_ump_endpoint * ump,struct snd_rawmidi * rmidi,int dir)1242  static void fill_substream_names(struct snd_ump_endpoint *ump,
1243  				 struct snd_rawmidi *rmidi, int dir)
1244  {
1245  	struct snd_rawmidi_substream *s;
1246  	const char *name;
1247  	int idx;
1248  
1249  	list_for_each_entry(s, &rmidi->streams[dir].substreams, list) {
1250  		idx = ump->legacy_mapping[s->number];
1251  		name = ump->groups[idx].name;
1252  		if (!*name)
1253  			name = ump->info.name;
1254  		scnprintf(s->name, sizeof(s->name), "Group %d (%.16s)%s",
1255  			  idx + 1, name,
1256  			  ump->groups[idx].active ? "" : " [Inactive]");
1257  	}
1258  }
1259  
update_legacy_names(struct snd_ump_endpoint * ump)1260  static void update_legacy_names(struct snd_ump_endpoint *ump)
1261  {
1262  	struct snd_rawmidi *rmidi = ump->legacy_rmidi;
1263  
1264  	fill_substream_names(ump, rmidi, SNDRV_RAWMIDI_STREAM_INPUT);
1265  	fill_substream_names(ump, rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT);
1266  }
1267  
snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint * ump,char * id,int device)1268  int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump,
1269  				  char *id, int device)
1270  {
1271  	struct snd_rawmidi *rmidi;
1272  	bool input, output;
1273  	int err, num;
1274  
1275  	ump->out_cvts = kcalloc(SNDRV_UMP_MAX_GROUPS,
1276  				sizeof(*ump->out_cvts), GFP_KERNEL);
1277  	if (!ump->out_cvts)
1278  		return -ENOMEM;
1279  
1280  	num = fill_legacy_mapping(ump);
1281  
1282  	input = ump->core.info_flags & SNDRV_RAWMIDI_INFO_INPUT;
1283  	output = ump->core.info_flags & SNDRV_RAWMIDI_INFO_OUTPUT;
1284  	err = snd_rawmidi_new(ump->core.card, id, device,
1285  			      output ? num : 0, input ? num : 0,
1286  			      &rmidi);
1287  	if (err < 0) {
1288  		kfree(ump->out_cvts);
1289  		return err;
1290  	}
1291  
1292  	if (input)
1293  		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
1294  				    &snd_ump_legacy_input_ops);
1295  	if (output)
1296  		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
1297  				    &snd_ump_legacy_output_ops);
1298  	snprintf(rmidi->name, sizeof(rmidi->name), "%.68s (MIDI 1.0)",
1299  		 ump->info.name);
1300  	rmidi->info_flags = ump->core.info_flags & ~SNDRV_RAWMIDI_INFO_UMP;
1301  	rmidi->ops = &snd_ump_legacy_ops;
1302  	rmidi->private_data = ump;
1303  	ump->legacy_rmidi = rmidi;
1304  	update_legacy_names(ump);
1305  
1306  	ump_dbg(ump, "Created a legacy rawmidi #%d (%s)\n", device, id);
1307  	return 0;
1308  }
1309  EXPORT_SYMBOL_GPL(snd_ump_attach_legacy_rawmidi);
1310  #endif /* CONFIG_SND_UMP_LEGACY_RAWMIDI */
1311  
1312  MODULE_DESCRIPTION("Universal MIDI Packet (UMP) Core Driver");
1313  MODULE_LICENSE("GPL");
1314