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