1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * ALSA sequencer event conversion between UMP and legacy clients
4 */
5
6#include <linux/init.h>
7#include <linux/errno.h>
8#include <linux/string.h>
9#include <sound/core.h>
10#include <sound/ump.h>
11#include <sound/ump_msg.h>
12#include "seq_ump_convert.h"
13
14/*
15 * Upgrade / downgrade value bits
16 */
17static u8 downscale_32_to_7bit(u32 src)
18{
19	return src >> 25;
20}
21
22static u16 downscale_32_to_14bit(u32 src)
23{
24	return src >> 18;
25}
26
27static u8 downscale_16_to_7bit(u16 src)
28{
29	return src >> 9;
30}
31
32static u16 upscale_7_to_16bit(u8 src)
33{
34	u16 val, repeat;
35
36	val = (u16)src << 9;
37	if (src <= 0x40)
38		return val;
39	repeat = src & 0x3f;
40	return val | (repeat << 3) | (repeat >> 3);
41}
42
43static u32 upscale_7_to_32bit(u8 src)
44{
45	u32 val, repeat;
46
47	val = src << 25;
48	if (src <= 0x40)
49		return val;
50	repeat = src & 0x3f;
51	return val | (repeat << 19) | (repeat << 13) |
52		(repeat << 7) | (repeat << 1) | (repeat >> 5);
53}
54
55static u32 upscale_14_to_32bit(u16 src)
56{
57	u32 val, repeat;
58
59	val = src << 18;
60	if (src <= 0x2000)
61		return val;
62	repeat = src & 0x1fff;
63	return val | (repeat << 5) | (repeat >> 8);
64}
65
66static unsigned char get_ump_group(struct snd_seq_client_port *port)
67{
68	return port->ump_group ? (port->ump_group - 1) : 0;
69}
70
71/* create a UMP header */
72#define make_raw_ump(port, type) \
73	ump_compose(type, get_ump_group(port), 0, 0)
74
75/*
76 * UMP -> MIDI1 sequencer event
77 */
78
79/* MIDI 1.0 CVM */
80
81/* encode note event */
82static void ump_midi1_to_note_ev(const union snd_ump_midi1_msg *val,
83				 struct snd_seq_event *ev)
84{
85	ev->data.note.channel = val->note.channel;
86	ev->data.note.note = val->note.note;
87	ev->data.note.velocity = val->note.velocity;
88}
89
90/* encode one parameter controls */
91static void ump_midi1_to_ctrl_ev(const union snd_ump_midi1_msg *val,
92				 struct snd_seq_event *ev)
93{
94	ev->data.control.channel = val->caf.channel;
95	ev->data.control.value = val->caf.data;
96}
97
98/* encode pitch wheel change */
99static void ump_midi1_to_pitchbend_ev(const union snd_ump_midi1_msg *val,
100				      struct snd_seq_event *ev)
101{
102	ev->data.control.channel = val->pb.channel;
103	ev->data.control.value = (val->pb.data_msb << 7) | val->pb.data_lsb;
104	ev->data.control.value -= 8192;
105}
106
107/* encode midi control change */
108static void ump_midi1_to_cc_ev(const union snd_ump_midi1_msg *val,
109			       struct snd_seq_event *ev)
110{
111	ev->data.control.channel = val->cc.channel;
112	ev->data.control.param = val->cc.index;
113	ev->data.control.value = val->cc.data;
114}
115
116/* Encoding MIDI 1.0 UMP packet */
117struct seq_ump_midi1_to_ev {
118	int seq_type;
119	void (*encode)(const union snd_ump_midi1_msg *val, struct snd_seq_event *ev);
120};
121
122/* Encoders for MIDI1 status 0x80-0xe0 */
123static struct seq_ump_midi1_to_ev midi1_msg_encoders[] = {
124	{SNDRV_SEQ_EVENT_NOTEOFF,	ump_midi1_to_note_ev},	/* 0x80 */
125	{SNDRV_SEQ_EVENT_NOTEON,	ump_midi1_to_note_ev},	/* 0x90 */
126	{SNDRV_SEQ_EVENT_KEYPRESS,	ump_midi1_to_note_ev},	/* 0xa0 */
127	{SNDRV_SEQ_EVENT_CONTROLLER,	ump_midi1_to_cc_ev},	/* 0xb0 */
128	{SNDRV_SEQ_EVENT_PGMCHANGE,	ump_midi1_to_ctrl_ev},	/* 0xc0 */
129	{SNDRV_SEQ_EVENT_CHANPRESS,	ump_midi1_to_ctrl_ev},	/* 0xd0 */
130	{SNDRV_SEQ_EVENT_PITCHBEND,	ump_midi1_to_pitchbend_ev}, /* 0xe0 */
131};
132
133static int cvt_ump_midi1_to_event(const union snd_ump_midi1_msg *val,
134				  struct snd_seq_event *ev)
135{
136	unsigned char status = val->note.status;
137
138	if (status < 0x8 || status > 0xe)
139		return 0; /* invalid - skip */
140	status -= 8;
141	ev->type = midi1_msg_encoders[status].seq_type;
142	ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
143	midi1_msg_encoders[status].encode(val, ev);
144	return 1;
145}
146
147/* MIDI System message */
148
149/* encode one parameter value*/
150static void ump_system_to_one_param_ev(const union snd_ump_midi1_msg *val,
151				       struct snd_seq_event *ev)
152{
153	ev->data.control.value = val->system.parm1;
154}
155
156/* encode song position */
157static void ump_system_to_songpos_ev(const union snd_ump_midi1_msg *val,
158				     struct snd_seq_event *ev)
159{
160	ev->data.control.value = (val->system.parm1 << 7) | val->system.parm2;
161}
162
163/* Encoders for 0xf0 - 0xff */
164static struct seq_ump_midi1_to_ev system_msg_encoders[] = {
165	{SNDRV_SEQ_EVENT_NONE,		NULL},	 /* 0xf0 */
166	{SNDRV_SEQ_EVENT_QFRAME,	ump_system_to_one_param_ev}, /* 0xf1 */
167	{SNDRV_SEQ_EVENT_SONGPOS,	ump_system_to_songpos_ev}, /* 0xf2 */
168	{SNDRV_SEQ_EVENT_SONGSEL,	ump_system_to_one_param_ev}, /* 0xf3 */
169	{SNDRV_SEQ_EVENT_NONE,		NULL}, /* 0xf4 */
170	{SNDRV_SEQ_EVENT_NONE,		NULL}, /* 0xf5 */
171	{SNDRV_SEQ_EVENT_TUNE_REQUEST,	NULL}, /* 0xf6 */
172	{SNDRV_SEQ_EVENT_NONE,		NULL}, /* 0xf7 */
173	{SNDRV_SEQ_EVENT_CLOCK,		NULL}, /* 0xf8 */
174	{SNDRV_SEQ_EVENT_NONE,		NULL}, /* 0xf9 */
175	{SNDRV_SEQ_EVENT_START,		NULL}, /* 0xfa */
176	{SNDRV_SEQ_EVENT_CONTINUE,	NULL}, /* 0xfb */
177	{SNDRV_SEQ_EVENT_STOP,		NULL}, /* 0xfc */
178	{SNDRV_SEQ_EVENT_NONE,		NULL}, /* 0xfd */
179	{SNDRV_SEQ_EVENT_SENSING,	NULL}, /* 0xfe */
180	{SNDRV_SEQ_EVENT_RESET,		NULL}, /* 0xff */
181};
182
183static int cvt_ump_system_to_event(const union snd_ump_midi1_msg *val,
184				   struct snd_seq_event *ev)
185{
186	unsigned char status = val->system.status;
187
188	if ((status & 0xf0) != UMP_MIDI1_MSG_REALTIME)
189		return 0; /* invalid status - skip */
190	status &= 0x0f;
191	ev->type = system_msg_encoders[status].seq_type;
192	ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
193	if (ev->type == SNDRV_SEQ_EVENT_NONE)
194		return 0;
195	if (system_msg_encoders[status].encode)
196		system_msg_encoders[status].encode(val, ev);
197	return 1;
198}
199
200/* MIDI 2.0 CVM */
201
202/* encode note event */
203static int ump_midi2_to_note_ev(const union snd_ump_midi2_msg *val,
204				struct snd_seq_event *ev)
205{
206	ev->data.note.channel = val->note.channel;
207	ev->data.note.note = val->note.note;
208	ev->data.note.velocity = downscale_16_to_7bit(val->note.velocity);
209	/* correct note-on velocity 0 to 1;
210	 * it's no longer equivalent as not-off for MIDI 2.0
211	 */
212	if (ev->type == SNDRV_SEQ_EVENT_NOTEON &&
213	    !ev->data.note.velocity)
214		ev->data.note.velocity = 1;
215	return 1;
216}
217
218/* encode pitch wheel change */
219static int ump_midi2_to_pitchbend_ev(const union snd_ump_midi2_msg *val,
220				     struct snd_seq_event *ev)
221{
222	ev->data.control.channel = val->pb.channel;
223	ev->data.control.value = downscale_32_to_14bit(val->pb.data);
224	ev->data.control.value -= 8192;
225	return 1;
226}
227
228/* encode midi control change */
229static int ump_midi2_to_cc_ev(const union snd_ump_midi2_msg *val,
230			      struct snd_seq_event *ev)
231{
232	ev->data.control.channel = val->cc.channel;
233	ev->data.control.param = val->cc.index;
234	ev->data.control.value = downscale_32_to_7bit(val->cc.data);
235	return 1;
236}
237
238/* encode midi program change */
239static int ump_midi2_to_pgm_ev(const union snd_ump_midi2_msg *val,
240			       struct snd_seq_event *ev)
241{
242	int size = 1;
243
244	ev->data.control.channel = val->pg.channel;
245	if (val->pg.bank_valid) {
246		ev->type = SNDRV_SEQ_EVENT_CONTROL14;
247		ev->data.control.param = UMP_CC_BANK_SELECT;
248		ev->data.control.value = (val->pg.bank_msb << 7) | val->pg.bank_lsb;
249		ev[1] = ev[0];
250		ev++;
251		ev->type = SNDRV_SEQ_EVENT_PGMCHANGE;
252		size = 2;
253	}
254	ev->data.control.value = val->pg.program;
255	return size;
256}
257
258/* encode one parameter controls */
259static int ump_midi2_to_ctrl_ev(const union snd_ump_midi2_msg *val,
260				struct snd_seq_event *ev)
261{
262	ev->data.control.channel = val->caf.channel;
263	ev->data.control.value = downscale_32_to_7bit(val->caf.data);
264	return 1;
265}
266
267/* encode RPN/NRPN */
268static int ump_midi2_to_rpn_ev(const union snd_ump_midi2_msg *val,
269			       struct snd_seq_event *ev)
270{
271	ev->data.control.channel = val->rpn.channel;
272	ev->data.control.param = (val->rpn.bank << 7) | val->rpn.index;
273	ev->data.control.value = downscale_32_to_14bit(val->rpn.data);
274	return 1;
275}
276
277/* Encoding MIDI 2.0 UMP Packet */
278struct seq_ump_midi2_to_ev {
279	int seq_type;
280	int (*encode)(const union snd_ump_midi2_msg *val, struct snd_seq_event *ev);
281};
282
283/* Encoders for MIDI2 status 0x00-0xf0 */
284static struct seq_ump_midi2_to_ev midi2_msg_encoders[] = {
285	{SNDRV_SEQ_EVENT_NONE,		NULL},			/* 0x00 */
286	{SNDRV_SEQ_EVENT_NONE,		NULL},			/* 0x10 */
287	{SNDRV_SEQ_EVENT_REGPARAM,	ump_midi2_to_rpn_ev},	/* 0x20 */
288	{SNDRV_SEQ_EVENT_NONREGPARAM,	ump_midi2_to_rpn_ev},	/* 0x30 */
289	{SNDRV_SEQ_EVENT_NONE,		NULL},			/* 0x40 */
290	{SNDRV_SEQ_EVENT_NONE,		NULL},			/* 0x50 */
291	{SNDRV_SEQ_EVENT_NONE,		NULL},			/* 0x60 */
292	{SNDRV_SEQ_EVENT_NONE,		NULL},			/* 0x70 */
293	{SNDRV_SEQ_EVENT_NOTEOFF,	ump_midi2_to_note_ev},	/* 0x80 */
294	{SNDRV_SEQ_EVENT_NOTEON,	ump_midi2_to_note_ev},	/* 0x90 */
295	{SNDRV_SEQ_EVENT_KEYPRESS,	ump_midi2_to_note_ev},	/* 0xa0 */
296	{SNDRV_SEQ_EVENT_CONTROLLER,	ump_midi2_to_cc_ev},	/* 0xb0 */
297	{SNDRV_SEQ_EVENT_PGMCHANGE,	ump_midi2_to_pgm_ev},	/* 0xc0 */
298	{SNDRV_SEQ_EVENT_CHANPRESS,	ump_midi2_to_ctrl_ev},	/* 0xd0 */
299	{SNDRV_SEQ_EVENT_PITCHBEND,	ump_midi2_to_pitchbend_ev}, /* 0xe0 */
300	{SNDRV_SEQ_EVENT_NONE,		NULL},			/* 0xf0 */
301};
302
303static int cvt_ump_midi2_to_event(const union snd_ump_midi2_msg *val,
304				  struct snd_seq_event *ev)
305{
306	unsigned char status = val->note.status;
307
308	ev->type = midi2_msg_encoders[status].seq_type;
309	if (ev->type == SNDRV_SEQ_EVENT_NONE)
310		return 0; /* skip */
311	ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
312	return midi2_msg_encoders[status].encode(val, ev);
313}
314
315/* parse and compose for a sysex var-length event */
316static int cvt_ump_sysex7_to_event(const u32 *data, unsigned char *buf,
317				   struct snd_seq_event *ev)
318{
319	unsigned char status;
320	unsigned char bytes;
321	u32 val;
322	int size = 0;
323
324	val = data[0];
325	status = ump_sysex_message_status(val);
326	bytes = ump_sysex_message_length(val);
327	if (bytes > 6)
328		return 0; // skip
329
330	if (status == UMP_SYSEX_STATUS_SINGLE ||
331	    status == UMP_SYSEX_STATUS_START) {
332		buf[0] = UMP_MIDI1_MSG_SYSEX_START;
333		size = 1;
334	}
335
336	if (bytes > 0)
337		buf[size++] = (val >> 8) & 0x7f;
338	if (bytes > 1)
339		buf[size++] = val & 0x7f;
340	val = data[1];
341	if (bytes > 2)
342		buf[size++] = (val >> 24) & 0x7f;
343	if (bytes > 3)
344		buf[size++] = (val >> 16) & 0x7f;
345	if (bytes > 4)
346		buf[size++] = (val >> 8) & 0x7f;
347	if (bytes > 5)
348		buf[size++] = val & 0x7f;
349
350	if (status == UMP_SYSEX_STATUS_SINGLE ||
351	    status == UMP_SYSEX_STATUS_END)
352		buf[size++] = UMP_MIDI1_MSG_SYSEX_END;
353
354	ev->type = SNDRV_SEQ_EVENT_SYSEX;
355	ev->flags = SNDRV_SEQ_EVENT_LENGTH_VARIABLE;
356	ev->data.ext.len = size;
357	ev->data.ext.ptr = buf;
358	return 1;
359}
360
361/* convert UMP packet from MIDI 1.0 to MIDI 2.0 and deliver it */
362static int cvt_ump_midi1_to_midi2(struct snd_seq_client *dest,
363				  struct snd_seq_client_port *dest_port,
364				  struct snd_seq_event *__event,
365				  int atomic, int hop)
366{
367	struct snd_seq_ump_event *event = (struct snd_seq_ump_event *)__event;
368	struct snd_seq_ump_event ev_cvt;
369	const union snd_ump_midi1_msg *midi1 = (const union snd_ump_midi1_msg *)event->ump;
370	union snd_ump_midi2_msg *midi2 = (union snd_ump_midi2_msg *)ev_cvt.ump;
371
372	ev_cvt = *event;
373	memset(&ev_cvt.ump, 0, sizeof(ev_cvt.ump));
374
375	midi2->note.type = UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE;
376	midi2->note.group = midi1->note.group;
377	midi2->note.status = midi1->note.status;
378	midi2->note.channel = midi1->note.channel;
379	switch (midi1->note.status) {
380	case UMP_MSG_STATUS_NOTE_ON:
381	case UMP_MSG_STATUS_NOTE_OFF:
382		midi2->note.note = midi1->note.note;
383		midi2->note.velocity = upscale_7_to_16bit(midi1->note.velocity);
384		break;
385	case UMP_MSG_STATUS_POLY_PRESSURE:
386		midi2->paf.note = midi1->paf.note;
387		midi2->paf.data = upscale_7_to_32bit(midi1->paf.data);
388		break;
389	case UMP_MSG_STATUS_CC:
390		midi2->cc.index = midi1->cc.index;
391		midi2->cc.data = upscale_7_to_32bit(midi1->cc.data);
392		break;
393	case UMP_MSG_STATUS_PROGRAM:
394		midi2->pg.program = midi1->pg.program;
395		break;
396	case UMP_MSG_STATUS_CHANNEL_PRESSURE:
397		midi2->caf.data = upscale_7_to_32bit(midi1->caf.data);
398		break;
399	case UMP_MSG_STATUS_PITCH_BEND:
400		midi2->pb.data = upscale_14_to_32bit((midi1->pb.data_msb << 7) |
401						     midi1->pb.data_lsb);
402		break;
403	default:
404		return 0;
405	}
406
407	return __snd_seq_deliver_single_event(dest, dest_port,
408					      (struct snd_seq_event *)&ev_cvt,
409					      atomic, hop);
410}
411
412/* convert UMP packet from MIDI 2.0 to MIDI 1.0 and deliver it */
413static int cvt_ump_midi2_to_midi1(struct snd_seq_client *dest,
414				  struct snd_seq_client_port *dest_port,
415				  struct snd_seq_event *__event,
416				  int atomic, int hop)
417{
418	struct snd_seq_ump_event *event = (struct snd_seq_ump_event *)__event;
419	struct snd_seq_ump_event ev_cvt;
420	union snd_ump_midi1_msg *midi1 = (union snd_ump_midi1_msg *)ev_cvt.ump;
421	const union snd_ump_midi2_msg *midi2 = (const union snd_ump_midi2_msg *)event->ump;
422	u16 v;
423
424	ev_cvt = *event;
425	memset(&ev_cvt.ump, 0, sizeof(ev_cvt.ump));
426
427	midi1->note.type = UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE;
428	midi1->note.group = midi2->note.group;
429	midi1->note.status = midi2->note.status;
430	midi1->note.channel = midi2->note.channel;
431	switch (midi2->note.status) {
432	case UMP_MSG_STATUS_NOTE_ON:
433	case UMP_MSG_STATUS_NOTE_OFF:
434		midi1->note.note = midi2->note.note;
435		midi1->note.velocity = downscale_16_to_7bit(midi2->note.velocity);
436		break;
437	case UMP_MSG_STATUS_POLY_PRESSURE:
438		midi1->paf.note = midi2->paf.note;
439		midi1->paf.data = downscale_32_to_7bit(midi2->paf.data);
440		break;
441	case UMP_MSG_STATUS_CC:
442		midi1->cc.index = midi2->cc.index;
443		midi1->cc.data = downscale_32_to_7bit(midi2->cc.data);
444		break;
445	case UMP_MSG_STATUS_PROGRAM:
446		midi1->pg.program = midi2->pg.program;
447		break;
448	case UMP_MSG_STATUS_CHANNEL_PRESSURE:
449		midi1->caf.data = downscale_32_to_7bit(midi2->caf.data);
450		break;
451	case UMP_MSG_STATUS_PITCH_BEND:
452		v = downscale_32_to_14bit(midi2->pb.data);
453		midi1->pb.data_msb = v >> 7;
454		midi1->pb.data_lsb = v & 0x7f;
455		break;
456	default:
457		return 0;
458	}
459
460	return __snd_seq_deliver_single_event(dest, dest_port,
461					      (struct snd_seq_event *)&ev_cvt,
462					      atomic, hop);
463}
464
465/* convert UMP to a legacy ALSA seq event and deliver it */
466static int cvt_ump_to_any(struct snd_seq_client *dest,
467			  struct snd_seq_client_port *dest_port,
468			  struct snd_seq_event *event,
469			  unsigned char type,
470			  int atomic, int hop)
471{
472	struct snd_seq_event ev_cvt[2]; /* up to two events */
473	struct snd_seq_ump_event *ump_ev = (struct snd_seq_ump_event *)event;
474	/* use the second event as a temp buffer for saving stack usage */
475	unsigned char *sysex_buf = (unsigned char *)(ev_cvt + 1);
476	unsigned char flags = event->flags & ~SNDRV_SEQ_EVENT_UMP;
477	int i, len, err;
478
479	ev_cvt[0] = ev_cvt[1] = *event;
480	ev_cvt[0].flags = flags;
481	ev_cvt[1].flags = flags;
482	switch (type) {
483	case UMP_MSG_TYPE_SYSTEM:
484		len = cvt_ump_system_to_event((union snd_ump_midi1_msg *)ump_ev->ump,
485					      ev_cvt);
486		break;
487	case UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE:
488		len = cvt_ump_midi1_to_event((union snd_ump_midi1_msg *)ump_ev->ump,
489					     ev_cvt);
490		break;
491	case UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE:
492		len = cvt_ump_midi2_to_event((union snd_ump_midi2_msg *)ump_ev->ump,
493					     ev_cvt);
494		break;
495	case UMP_MSG_TYPE_DATA:
496		len = cvt_ump_sysex7_to_event(ump_ev->ump, sysex_buf, ev_cvt);
497		break;
498	default:
499		return 0;
500	}
501
502	for (i = 0; i < len; i++) {
503		err = __snd_seq_deliver_single_event(dest, dest_port,
504						     &ev_cvt[i], atomic, hop);
505		if (err < 0)
506			return err;
507	}
508
509	return 0;
510}
511
512/* Replace UMP group field with the destination and deliver */
513static int deliver_with_group_convert(struct snd_seq_client *dest,
514				      struct snd_seq_client_port *dest_port,
515				      struct snd_seq_ump_event *ump_ev,
516				      int atomic, int hop)
517{
518	struct snd_seq_ump_event ev = *ump_ev;
519
520	/* rewrite the group to the destination port */
521	ev.ump[0] &= ~(0xfU << 24);
522	/* fill with the new group; the dest_port->ump_group field is 1-based */
523	ev.ump[0] |= ((dest_port->ump_group - 1) << 24);
524
525	return __snd_seq_deliver_single_event(dest, dest_port,
526					      (struct snd_seq_event *)&ev,
527					      atomic, hop);
528}
529
530/* apply the UMP event filter; return true to skip the event */
531static bool ump_event_filtered(struct snd_seq_client *dest,
532			       const struct snd_seq_ump_event *ev)
533{
534	unsigned char group;
535
536	group = ump_message_group(ev->ump[0]);
537	if (ump_is_groupless_msg(ump_message_type(ev->ump[0])))
538		return dest->group_filter & (1U << 0);
539	/* check the bitmap for 1-based group number */
540	return dest->group_filter & (1U << (group + 1));
541}
542
543/* Convert from UMP packet and deliver */
544int snd_seq_deliver_from_ump(struct snd_seq_client *source,
545			     struct snd_seq_client *dest,
546			     struct snd_seq_client_port *dest_port,
547			     struct snd_seq_event *event,
548			     int atomic, int hop)
549{
550	struct snd_seq_ump_event *ump_ev = (struct snd_seq_ump_event *)event;
551	unsigned char type;
552
553	if (snd_seq_ev_is_variable(event))
554		return 0; // skip, no variable event for UMP, so far
555	if (ump_event_filtered(dest, ump_ev))
556		return 0; // skip if group filter is set and matching
557	type = ump_message_type(ump_ev->ump[0]);
558
559	if (snd_seq_client_is_ump(dest)) {
560		if (snd_seq_client_is_midi2(dest) &&
561		    type == UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE)
562			return cvt_ump_midi1_to_midi2(dest, dest_port,
563						      event, atomic, hop);
564		else if (!snd_seq_client_is_midi2(dest) &&
565			 type == UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE)
566			return cvt_ump_midi2_to_midi1(dest, dest_port,
567						      event, atomic, hop);
568		/* non-EP port and different group is set? */
569		if (dest_port->ump_group &&
570		    !ump_is_groupless_msg(type) &&
571		    ump_message_group(*ump_ev->ump) + 1 != dest_port->ump_group)
572			return deliver_with_group_convert(dest, dest_port,
573							  ump_ev, atomic, hop);
574		/* copy as-is */
575		return __snd_seq_deliver_single_event(dest, dest_port,
576						      event, atomic, hop);
577	}
578
579	return cvt_ump_to_any(dest, dest_port, event, type, atomic, hop);
580}
581
582/*
583 * MIDI1 sequencer event -> UMP conversion
584 */
585
586/* Conversion to UMP MIDI 1.0 */
587
588/* convert note on/off event to MIDI 1.0 UMP */
589static int note_ev_to_ump_midi1(const struct snd_seq_event *event,
590				struct snd_seq_client_port *dest_port,
591				union snd_ump_midi1_msg *data,
592				unsigned char status)
593{
594	if (!event->data.note.velocity)
595		status = UMP_MSG_STATUS_NOTE_OFF;
596	data->note.status = status;
597	data->note.channel = event->data.note.channel & 0x0f;
598	data->note.velocity = event->data.note.velocity & 0x7f;
599	data->note.note = event->data.note.note & 0x7f;
600	return 1;
601}
602
603/* convert CC event to MIDI 1.0 UMP */
604static int cc_ev_to_ump_midi1(const struct snd_seq_event *event,
605			      struct snd_seq_client_port *dest_port,
606			      union snd_ump_midi1_msg *data,
607			      unsigned char status)
608{
609	data->cc.status = status;
610	data->cc.channel = event->data.control.channel & 0x0f;
611	data->cc.index = event->data.control.param;
612	data->cc.data = event->data.control.value;
613	return 1;
614}
615
616/* convert one-parameter control event to MIDI 1.0 UMP */
617static int ctrl_ev_to_ump_midi1(const struct snd_seq_event *event,
618				struct snd_seq_client_port *dest_port,
619				union snd_ump_midi1_msg *data,
620				unsigned char status)
621{
622	data->caf.status = status;
623	data->caf.channel = event->data.control.channel & 0x0f;
624	data->caf.data = event->data.control.value & 0x7f;
625	return 1;
626}
627
628/* convert pitchbend event to MIDI 1.0 UMP */
629static int pitchbend_ev_to_ump_midi1(const struct snd_seq_event *event,
630				     struct snd_seq_client_port *dest_port,
631				     union snd_ump_midi1_msg *data,
632				     unsigned char status)
633{
634	int val = event->data.control.value + 8192;
635
636	val = clamp(val, 0, 0x3fff);
637	data->pb.status = status;
638	data->pb.channel = event->data.control.channel & 0x0f;
639	data->pb.data_msb = (val >> 7) & 0x7f;
640	data->pb.data_lsb = val & 0x7f;
641	return 1;
642}
643
644/* convert 14bit control event to MIDI 1.0 UMP; split to two events */
645static int ctrl14_ev_to_ump_midi1(const struct snd_seq_event *event,
646				  struct snd_seq_client_port *dest_port,
647				  union snd_ump_midi1_msg *data,
648				  unsigned char status)
649{
650	data->cc.status = UMP_MSG_STATUS_CC;
651	data->cc.channel = event->data.control.channel & 0x0f;
652	data->cc.index = event->data.control.param & 0x7f;
653	if (event->data.control.param < 0x20) {
654		data->cc.data = (event->data.control.value >> 7) & 0x7f;
655		data[1] = data[0];
656		data[1].cc.index = event->data.control.param | 0x20;
657		data[1].cc.data = event->data.control.value & 0x7f;
658		return 2;
659	}
660
661	data->cc.data = event->data.control.value & 0x7f;
662	return 1;
663}
664
665/* convert RPN/NRPN event to MIDI 1.0 UMP; split to four events */
666static int rpn_ev_to_ump_midi1(const struct snd_seq_event *event,
667			       struct snd_seq_client_port *dest_port,
668			       union snd_ump_midi1_msg *data,
669			       unsigned char status)
670{
671	bool is_rpn = (status == UMP_MSG_STATUS_RPN);
672
673	data->cc.status = UMP_MSG_STATUS_CC;
674	data->cc.channel = event->data.control.channel & 0x0f;
675	data[1] = data[2] = data[3] = data[0];
676
677	data[0].cc.index = is_rpn ? UMP_CC_RPN_MSB : UMP_CC_NRPN_MSB;
678	data[0].cc.data = (event->data.control.param >> 7) & 0x7f;
679	data[1].cc.index = is_rpn ? UMP_CC_RPN_LSB : UMP_CC_NRPN_LSB;
680	data[1].cc.data = event->data.control.param & 0x7f;
681	data[2].cc.index = UMP_CC_DATA;
682	data[2].cc.data = (event->data.control.value >> 7) & 0x7f;
683	data[3].cc.index = UMP_CC_DATA_LSB;
684	data[3].cc.data = event->data.control.value & 0x7f;
685	return 4;
686}
687
688/* convert system / RT message to UMP */
689static int system_ev_to_ump_midi1(const struct snd_seq_event *event,
690				  struct snd_seq_client_port *dest_port,
691				  union snd_ump_midi1_msg *data,
692				  unsigned char status)
693{
694	data->system.status = status;
695	return 1;
696}
697
698/* convert system / RT message with 1 parameter to UMP */
699static int system_1p_ev_to_ump_midi1(const struct snd_seq_event *event,
700				     struct snd_seq_client_port *dest_port,
701				     union snd_ump_midi1_msg *data,
702				     unsigned char status)
703{
704	data->system.status = status;
705	data->system.parm1 = event->data.control.value & 0x7f;
706	return 1;
707}
708
709/* convert system / RT message with two parameters to UMP */
710static int system_2p_ev_to_ump_midi1(const struct snd_seq_event *event,
711				     struct snd_seq_client_port *dest_port,
712				     union snd_ump_midi1_msg *data,
713				     unsigned char status)
714{
715	data->system.status = status;
716	data->system.parm1 = (event->data.control.value >> 7) & 0x7f;
717	data->system.parm2 = event->data.control.value & 0x7f;
718	return 1;
719}
720
721/* Conversion to UMP MIDI 2.0 */
722
723/* convert note on/off event to MIDI 2.0 UMP */
724static int note_ev_to_ump_midi2(const struct snd_seq_event *event,
725				struct snd_seq_client_port *dest_port,
726				union snd_ump_midi2_msg *data,
727				unsigned char status)
728{
729	if (!event->data.note.velocity)
730		status = UMP_MSG_STATUS_NOTE_OFF;
731	data->note.status = status;
732	data->note.channel = event->data.note.channel & 0x0f;
733	data->note.note = event->data.note.note & 0x7f;
734	data->note.velocity = upscale_7_to_16bit(event->data.note.velocity & 0x7f);
735	return 1;
736}
737
738/* convert PAF event to MIDI 2.0 UMP */
739static int paf_ev_to_ump_midi2(const struct snd_seq_event *event,
740			       struct snd_seq_client_port *dest_port,
741			       union snd_ump_midi2_msg *data,
742			       unsigned char status)
743{
744	data->paf.status = status;
745	data->paf.channel = event->data.note.channel & 0x0f;
746	data->paf.note = event->data.note.note & 0x7f;
747	data->paf.data = upscale_7_to_32bit(event->data.note.velocity & 0x7f);
748	return 1;
749}
750
751/* set up the MIDI2 RPN/NRPN packet data from the parsed info */
752static void fill_rpn(struct snd_seq_ump_midi2_bank *cc,
753		     union snd_ump_midi2_msg *data)
754{
755	if (cc->rpn_set) {
756		data->rpn.status = UMP_MSG_STATUS_RPN;
757		data->rpn.bank = cc->cc_rpn_msb;
758		data->rpn.index = cc->cc_rpn_lsb;
759		cc->rpn_set = 0;
760		cc->cc_rpn_msb = cc->cc_rpn_lsb = 0;
761	} else {
762		data->rpn.status = UMP_MSG_STATUS_NRPN;
763		data->rpn.bank = cc->cc_nrpn_msb;
764		data->rpn.index = cc->cc_nrpn_lsb;
765		cc->nrpn_set = 0;
766		cc->cc_nrpn_msb = cc->cc_nrpn_lsb = 0;
767	}
768	data->rpn.data = upscale_14_to_32bit((cc->cc_data_msb << 7) |
769					     cc->cc_data_lsb);
770	cc->cc_data_msb = cc->cc_data_lsb = 0;
771}
772
773/* convert CC event to MIDI 2.0 UMP */
774static int cc_ev_to_ump_midi2(const struct snd_seq_event *event,
775			      struct snd_seq_client_port *dest_port,
776			      union snd_ump_midi2_msg *data,
777			      unsigned char status)
778{
779	unsigned char channel = event->data.control.channel & 0x0f;
780	unsigned char index = event->data.control.param & 0x7f;
781	unsigned char val = event->data.control.value & 0x7f;
782	struct snd_seq_ump_midi2_bank *cc = &dest_port->midi2_bank[channel];
783
784	/* process special CC's (bank/rpn/nrpn) */
785	switch (index) {
786	case UMP_CC_RPN_MSB:
787		cc->rpn_set = 1;
788		cc->cc_rpn_msb = val;
789		return 0; // skip
790	case UMP_CC_RPN_LSB:
791		cc->rpn_set = 1;
792		cc->cc_rpn_lsb = val;
793		return 0; // skip
794	case UMP_CC_NRPN_MSB:
795		cc->nrpn_set = 1;
796		cc->cc_nrpn_msb = val;
797		return 0; // skip
798	case UMP_CC_NRPN_LSB:
799		cc->nrpn_set = 1;
800		cc->cc_nrpn_lsb = val;
801		return 0; // skip
802	case UMP_CC_DATA:
803		cc->cc_data_msb = val;
804		return 0; // skip
805	case UMP_CC_BANK_SELECT:
806		cc->bank_set = 1;
807		cc->cc_bank_msb = val;
808		return 0; // skip
809	case UMP_CC_BANK_SELECT_LSB:
810		cc->bank_set = 1;
811		cc->cc_bank_lsb = val;
812		return 0; // skip
813	case UMP_CC_DATA_LSB:
814		cc->cc_data_lsb = val;
815		if (!(cc->rpn_set || cc->nrpn_set))
816			return 0; // skip
817		fill_rpn(cc, data);
818		return 1;
819	}
820
821	data->cc.status = status;
822	data->cc.channel = channel;
823	data->cc.index = index;
824	data->cc.data = upscale_7_to_32bit(event->data.control.value & 0x7f);
825	return 1;
826}
827
828/* convert one-parameter control event to MIDI 2.0 UMP */
829static int ctrl_ev_to_ump_midi2(const struct snd_seq_event *event,
830				struct snd_seq_client_port *dest_port,
831				union snd_ump_midi2_msg *data,
832				unsigned char status)
833{
834	data->caf.status = status;
835	data->caf.channel = event->data.control.channel & 0x0f;
836	data->caf.data = upscale_7_to_32bit(event->data.control.value & 0x7f);
837	return 1;
838}
839
840/* convert program change event to MIDI 2.0 UMP */
841static int pgm_ev_to_ump_midi2(const struct snd_seq_event *event,
842			       struct snd_seq_client_port *dest_port,
843			       union snd_ump_midi2_msg *data,
844			       unsigned char status)
845{
846	unsigned char channel = event->data.control.channel & 0x0f;
847	struct snd_seq_ump_midi2_bank *cc = &dest_port->midi2_bank[channel];
848
849	data->pg.status = status;
850	data->pg.channel = channel;
851	data->pg.program = event->data.control.value & 0x7f;
852	if (cc->bank_set) {
853		data->pg.bank_valid = 1;
854		data->pg.bank_msb = cc->cc_bank_msb;
855		data->pg.bank_lsb = cc->cc_bank_lsb;
856		cc->bank_set = 0;
857		cc->cc_bank_msb = cc->cc_bank_lsb = 0;
858	}
859	return 1;
860}
861
862/* convert pitchbend event to MIDI 2.0 UMP */
863static int pitchbend_ev_to_ump_midi2(const struct snd_seq_event *event,
864				     struct snd_seq_client_port *dest_port,
865				     union snd_ump_midi2_msg *data,
866				     unsigned char status)
867{
868	int val = event->data.control.value + 8192;
869
870	val = clamp(val, 0, 0x3fff);
871	data->pb.status = status;
872	data->pb.channel = event->data.control.channel & 0x0f;
873	data->pb.data = upscale_14_to_32bit(val);
874	return 1;
875}
876
877/* convert 14bit control event to MIDI 2.0 UMP; split to two events */
878static int ctrl14_ev_to_ump_midi2(const struct snd_seq_event *event,
879				  struct snd_seq_client_port *dest_port,
880				  union snd_ump_midi2_msg *data,
881				  unsigned char status)
882{
883	unsigned char channel = event->data.control.channel & 0x0f;
884	unsigned char index = event->data.control.param & 0x7f;
885	struct snd_seq_ump_midi2_bank *cc = &dest_port->midi2_bank[channel];
886	unsigned char msb, lsb;
887
888	msb = (event->data.control.value >> 7) & 0x7f;
889	lsb = event->data.control.value & 0x7f;
890	/* process special CC's (bank/rpn/nrpn) */
891	switch (index) {
892	case UMP_CC_BANK_SELECT:
893		cc->cc_bank_msb = msb;
894		fallthrough;
895	case UMP_CC_BANK_SELECT_LSB:
896		cc->bank_set = 1;
897		cc->cc_bank_lsb = lsb;
898		return 0; // skip
899	case UMP_CC_RPN_MSB:
900		cc->cc_rpn_msb = msb;
901		fallthrough;
902	case UMP_CC_RPN_LSB:
903		cc->rpn_set = 1;
904		cc->cc_rpn_lsb = lsb;
905		return 0; // skip
906	case UMP_CC_NRPN_MSB:
907		cc->cc_nrpn_msb = msb;
908		fallthrough;
909	case UMP_CC_NRPN_LSB:
910		cc->nrpn_set = 1;
911		cc->cc_nrpn_lsb = lsb;
912		return 0; // skip
913	case UMP_CC_DATA:
914		cc->cc_data_msb = msb;
915		fallthrough;
916	case UMP_CC_DATA_LSB:
917		cc->cc_data_lsb = lsb;
918		if (!(cc->rpn_set || cc->nrpn_set))
919			return 0; // skip
920		fill_rpn(cc, data);
921		return 1;
922	}
923
924	data->cc.status = UMP_MSG_STATUS_CC;
925	data->cc.channel = channel;
926	data->cc.index = index;
927	if (event->data.control.param < 0x20) {
928		data->cc.data = upscale_7_to_32bit(msb);
929		data[1] = data[0];
930		data[1].cc.index = event->data.control.param | 0x20;
931		data[1].cc.data = upscale_7_to_32bit(lsb);
932		return 2;
933	}
934
935	data->cc.data = upscale_7_to_32bit(lsb);
936	return 1;
937}
938
939/* convert RPN/NRPN event to MIDI 2.0 UMP */
940static int rpn_ev_to_ump_midi2(const struct snd_seq_event *event,
941			       struct snd_seq_client_port *dest_port,
942			       union snd_ump_midi2_msg *data,
943			       unsigned char status)
944{
945	data->rpn.status = status;
946	data->rpn.channel = event->data.control.channel;
947	data->rpn.bank = (event->data.control.param >> 7) & 0x7f;
948	data->rpn.index = event->data.control.param & 0x7f;
949	data->rpn.data = upscale_14_to_32bit(event->data.control.value & 0x3fff);
950	return 1;
951}
952
953/* convert system / RT message to UMP */
954static int system_ev_to_ump_midi2(const struct snd_seq_event *event,
955				  struct snd_seq_client_port *dest_port,
956				  union snd_ump_midi2_msg *data,
957				  unsigned char status)
958{
959	return system_ev_to_ump_midi1(event, dest_port,
960				      (union snd_ump_midi1_msg *)data,
961				      status);
962}
963
964/* convert system / RT message with 1 parameter to UMP */
965static int system_1p_ev_to_ump_midi2(const struct snd_seq_event *event,
966				     struct snd_seq_client_port *dest_port,
967				     union snd_ump_midi2_msg *data,
968				     unsigned char status)
969{
970	return system_1p_ev_to_ump_midi1(event, dest_port,
971					 (union snd_ump_midi1_msg *)data,
972					 status);
973}
974
975/* convert system / RT message with two parameters to UMP */
976static int system_2p_ev_to_ump_midi2(const struct snd_seq_event *event,
977				     struct snd_seq_client_port *dest_port,
978				     union snd_ump_midi2_msg *data,
979				     unsigned char status)
980{
981	return system_1p_ev_to_ump_midi1(event, dest_port,
982					 (union snd_ump_midi1_msg *)data,
983					 status);
984}
985
986struct seq_ev_to_ump {
987	int seq_type;
988	unsigned char status;
989	int (*midi1_encode)(const struct snd_seq_event *event,
990			    struct snd_seq_client_port *dest_port,
991			    union snd_ump_midi1_msg *data,
992			    unsigned char status);
993	int (*midi2_encode)(const struct snd_seq_event *event,
994			    struct snd_seq_client_port *dest_port,
995			    union snd_ump_midi2_msg *data,
996			    unsigned char status);
997};
998
999static const struct seq_ev_to_ump seq_ev_ump_encoders[] = {
1000	{ SNDRV_SEQ_EVENT_NOTEON, UMP_MSG_STATUS_NOTE_ON,
1001	  note_ev_to_ump_midi1, note_ev_to_ump_midi2 },
1002	{ SNDRV_SEQ_EVENT_NOTEOFF, UMP_MSG_STATUS_NOTE_OFF,
1003	  note_ev_to_ump_midi1, note_ev_to_ump_midi2 },
1004	{ SNDRV_SEQ_EVENT_KEYPRESS, UMP_MSG_STATUS_POLY_PRESSURE,
1005	  note_ev_to_ump_midi1, paf_ev_to_ump_midi2 },
1006	{ SNDRV_SEQ_EVENT_CONTROLLER, UMP_MSG_STATUS_CC,
1007	  cc_ev_to_ump_midi1, cc_ev_to_ump_midi2 },
1008	{ SNDRV_SEQ_EVENT_PGMCHANGE, UMP_MSG_STATUS_PROGRAM,
1009	  ctrl_ev_to_ump_midi1, pgm_ev_to_ump_midi2 },
1010	{ SNDRV_SEQ_EVENT_CHANPRESS, UMP_MSG_STATUS_CHANNEL_PRESSURE,
1011	  ctrl_ev_to_ump_midi1, ctrl_ev_to_ump_midi2 },
1012	{ SNDRV_SEQ_EVENT_PITCHBEND, UMP_MSG_STATUS_PITCH_BEND,
1013	  pitchbend_ev_to_ump_midi1, pitchbend_ev_to_ump_midi2 },
1014	{ SNDRV_SEQ_EVENT_CONTROL14, 0,
1015	  ctrl14_ev_to_ump_midi1, ctrl14_ev_to_ump_midi2 },
1016	{ SNDRV_SEQ_EVENT_NONREGPARAM, UMP_MSG_STATUS_NRPN,
1017	  rpn_ev_to_ump_midi1, rpn_ev_to_ump_midi2 },
1018	{ SNDRV_SEQ_EVENT_REGPARAM, UMP_MSG_STATUS_RPN,
1019	  rpn_ev_to_ump_midi1, rpn_ev_to_ump_midi2 },
1020	{ SNDRV_SEQ_EVENT_QFRAME, UMP_SYSTEM_STATUS_MIDI_TIME_CODE,
1021	  system_1p_ev_to_ump_midi1, system_1p_ev_to_ump_midi2 },
1022	{ SNDRV_SEQ_EVENT_SONGPOS, UMP_SYSTEM_STATUS_SONG_POSITION,
1023	  system_2p_ev_to_ump_midi1, system_2p_ev_to_ump_midi2 },
1024	{ SNDRV_SEQ_EVENT_SONGSEL, UMP_SYSTEM_STATUS_SONG_SELECT,
1025	  system_1p_ev_to_ump_midi1, system_1p_ev_to_ump_midi2 },
1026	{ SNDRV_SEQ_EVENT_TUNE_REQUEST, UMP_SYSTEM_STATUS_TUNE_REQUEST,
1027	  system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
1028	{ SNDRV_SEQ_EVENT_CLOCK, UMP_SYSTEM_STATUS_TIMING_CLOCK,
1029	  system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
1030	{ SNDRV_SEQ_EVENT_START, UMP_SYSTEM_STATUS_START,
1031	  system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
1032	{ SNDRV_SEQ_EVENT_CONTINUE, UMP_SYSTEM_STATUS_CONTINUE,
1033	  system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
1034	{ SNDRV_SEQ_EVENT_STOP, UMP_SYSTEM_STATUS_STOP,
1035	  system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
1036	{ SNDRV_SEQ_EVENT_SENSING, UMP_SYSTEM_STATUS_ACTIVE_SENSING,
1037	  system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
1038};
1039
1040static const struct seq_ev_to_ump *find_ump_encoder(int type)
1041{
1042	int i;
1043
1044	for (i = 0; i < ARRAY_SIZE(seq_ev_ump_encoders); i++)
1045		if (seq_ev_ump_encoders[i].seq_type == type)
1046			return &seq_ev_ump_encoders[i];
1047
1048	return NULL;
1049}
1050
1051static void setup_ump_event(struct snd_seq_ump_event *dest,
1052			    const struct snd_seq_event *src)
1053{
1054	memcpy(dest, src, sizeof(*src));
1055	dest->type = 0;
1056	dest->flags |= SNDRV_SEQ_EVENT_UMP;
1057	dest->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
1058	memset(dest->ump, 0, sizeof(dest->ump));
1059}
1060
1061/* Convert ALSA seq event to UMP MIDI 1.0 and deliver it */
1062static int cvt_to_ump_midi1(struct snd_seq_client *dest,
1063			    struct snd_seq_client_port *dest_port,
1064			    struct snd_seq_event *event,
1065			    int atomic, int hop)
1066{
1067	const struct seq_ev_to_ump *encoder;
1068	struct snd_seq_ump_event ev_cvt;
1069	union snd_ump_midi1_msg data[4];
1070	int i, n, err;
1071
1072	encoder = find_ump_encoder(event->type);
1073	if (!encoder)
1074		return __snd_seq_deliver_single_event(dest, dest_port,
1075						      event, atomic, hop);
1076
1077	data->raw = make_raw_ump(dest_port, UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE);
1078	n = encoder->midi1_encode(event, dest_port, data, encoder->status);
1079	if (!n)
1080		return 0;
1081
1082	setup_ump_event(&ev_cvt, event);
1083	for (i = 0; i < n; i++) {
1084		ev_cvt.ump[0] = data[i].raw;
1085		err = __snd_seq_deliver_single_event(dest, dest_port,
1086						     (struct snd_seq_event *)&ev_cvt,
1087						     atomic, hop);
1088		if (err < 0)
1089			return err;
1090	}
1091
1092	return 0;
1093}
1094
1095/* Convert ALSA seq event to UMP MIDI 2.0 and deliver it */
1096static int cvt_to_ump_midi2(struct snd_seq_client *dest,
1097			    struct snd_seq_client_port *dest_port,
1098			    struct snd_seq_event *event,
1099			    int atomic, int hop)
1100{
1101	const struct seq_ev_to_ump *encoder;
1102	struct snd_seq_ump_event ev_cvt;
1103	union snd_ump_midi2_msg data[2];
1104	int i, n, err;
1105
1106	encoder = find_ump_encoder(event->type);
1107	if (!encoder)
1108		return __snd_seq_deliver_single_event(dest, dest_port,
1109						      event, atomic, hop);
1110
1111	data->raw[0] = make_raw_ump(dest_port, UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE);
1112	data->raw[1] = 0;
1113	n = encoder->midi2_encode(event, dest_port, data, encoder->status);
1114	if (!n)
1115		return 0;
1116
1117	setup_ump_event(&ev_cvt, event);
1118	for (i = 0; i < n; i++) {
1119		memcpy(ev_cvt.ump, &data[i], sizeof(data[i]));
1120		err = __snd_seq_deliver_single_event(dest, dest_port,
1121						     (struct snd_seq_event *)&ev_cvt,
1122						     atomic, hop);
1123		if (err < 0)
1124			return err;
1125	}
1126
1127	return 0;
1128}
1129
1130/* Fill up a sysex7 UMP from the byte stream */
1131static void fill_sysex7_ump(struct snd_seq_client_port *dest_port,
1132			    u32 *val, u8 status, u8 *buf, int len)
1133{
1134	memset(val, 0, 8);
1135	memcpy((u8 *)val + 2, buf, len);
1136#ifdef __LITTLE_ENDIAN
1137	swab32_array(val, 2);
1138#endif
1139	val[0] |= ump_compose(UMP_MSG_TYPE_DATA, get_ump_group(dest_port),
1140			      status, len);
1141}
1142
1143/* Convert sysex var event to UMP sysex7 packets and deliver them */
1144static int cvt_sysex_to_ump(struct snd_seq_client *dest,
1145			    struct snd_seq_client_port *dest_port,
1146			    struct snd_seq_event *event,
1147			    int atomic, int hop)
1148{
1149	struct snd_seq_ump_event ev_cvt;
1150	unsigned char status;
1151	u8 buf[6], *xbuf;
1152	int offset = 0;
1153	int len, err;
1154
1155	if (!snd_seq_ev_is_variable(event))
1156		return 0;
1157
1158	setup_ump_event(&ev_cvt, event);
1159	for (;;) {
1160		len = snd_seq_expand_var_event_at(event, sizeof(buf), buf, offset);
1161		if (len <= 0)
1162			break;
1163		if (WARN_ON(len > 6))
1164			break;
1165		offset += len;
1166		xbuf = buf;
1167		if (*xbuf == UMP_MIDI1_MSG_SYSEX_START) {
1168			status = UMP_SYSEX_STATUS_START;
1169			xbuf++;
1170			len--;
1171			if (len > 0 && xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) {
1172				status = UMP_SYSEX_STATUS_SINGLE;
1173				len--;
1174			}
1175		} else {
1176			if (xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) {
1177				status = UMP_SYSEX_STATUS_END;
1178				len--;
1179			} else {
1180				status = UMP_SYSEX_STATUS_CONTINUE;
1181			}
1182		}
1183		fill_sysex7_ump(dest_port, ev_cvt.ump, status, xbuf, len);
1184		err = __snd_seq_deliver_single_event(dest, dest_port,
1185						     (struct snd_seq_event *)&ev_cvt,
1186						     atomic, hop);
1187		if (err < 0)
1188			return err;
1189	}
1190	return 0;
1191}
1192
1193/* Convert to UMP packet and deliver */
1194int snd_seq_deliver_to_ump(struct snd_seq_client *source,
1195			   struct snd_seq_client *dest,
1196			   struct snd_seq_client_port *dest_port,
1197			   struct snd_seq_event *event,
1198			   int atomic, int hop)
1199{
1200	if (dest->group_filter & (1U << dest_port->ump_group))
1201		return 0; /* group filtered - skip the event */
1202	if (event->type == SNDRV_SEQ_EVENT_SYSEX)
1203		return cvt_sysex_to_ump(dest, dest_port, event, atomic, hop);
1204	else if (snd_seq_client_is_midi2(dest))
1205		return cvt_to_ump_midi2(dest, dest_port, event, atomic, hop);
1206	else
1207		return cvt_to_ump_midi1(dest, dest_port, event, atomic, hop);
1208}
1209