Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Feb 10-13, 2025
Register
Loading...
Note: File does not exist in v5.4.
   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.parm2 << 7) | val->system.parm1;
 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	struct ump_cvt_to_ump_bank *cc;
 372
 373	ev_cvt = *event;
 374	memset(&ev_cvt.ump, 0, sizeof(ev_cvt.ump));
 375
 376	midi2->note.type = UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE;
 377	midi2->note.group = midi1->note.group;
 378	midi2->note.status = midi1->note.status;
 379	midi2->note.channel = midi1->note.channel;
 380	switch (midi1->note.status) {
 381	case UMP_MSG_STATUS_NOTE_ON:
 382	case UMP_MSG_STATUS_NOTE_OFF:
 383		midi2->note.note = midi1->note.note;
 384		midi2->note.velocity = upscale_7_to_16bit(midi1->note.velocity);
 385		break;
 386	case UMP_MSG_STATUS_POLY_PRESSURE:
 387		midi2->paf.note = midi1->paf.note;
 388		midi2->paf.data = upscale_7_to_32bit(midi1->paf.data);
 389		break;
 390	case UMP_MSG_STATUS_CC:
 391		cc = &dest_port->midi2_bank[midi1->note.channel];
 392		switch (midi1->cc.index) {
 393		case UMP_CC_BANK_SELECT:
 394			cc->bank_set = 1;
 395			cc->cc_bank_msb = midi1->cc.data;
 396			return 0; // skip
 397		case UMP_CC_BANK_SELECT_LSB:
 398			cc->bank_set = 1;
 399			cc->cc_bank_lsb = midi1->cc.data;
 400			return 0; // skip
 401		}
 402		midi2->cc.index = midi1->cc.index;
 403		midi2->cc.data = upscale_7_to_32bit(midi1->cc.data);
 404		break;
 405	case UMP_MSG_STATUS_PROGRAM:
 406		midi2->pg.program = midi1->pg.program;
 407		cc = &dest_port->midi2_bank[midi1->note.channel];
 408		if (cc->bank_set) {
 409			midi2->pg.bank_valid = 1;
 410			midi2->pg.bank_msb = cc->cc_bank_msb;
 411			midi2->pg.bank_lsb = cc->cc_bank_lsb;
 412			cc->bank_set = 0;
 413		}
 414		break;
 415	case UMP_MSG_STATUS_CHANNEL_PRESSURE:
 416		midi2->caf.data = upscale_7_to_32bit(midi1->caf.data);
 417		break;
 418	case UMP_MSG_STATUS_PITCH_BEND:
 419		midi2->pb.data = upscale_14_to_32bit((midi1->pb.data_msb << 7) |
 420						     midi1->pb.data_lsb);
 421		break;
 422	default:
 423		return 0;
 424	}
 425
 426	return __snd_seq_deliver_single_event(dest, dest_port,
 427					      (struct snd_seq_event *)&ev_cvt,
 428					      atomic, hop);
 429}
 430
 431/* convert UMP packet from MIDI 2.0 to MIDI 1.0 and deliver it */
 432static int cvt_ump_midi2_to_midi1(struct snd_seq_client *dest,
 433				  struct snd_seq_client_port *dest_port,
 434				  struct snd_seq_event *__event,
 435				  int atomic, int hop)
 436{
 437	struct snd_seq_ump_event *event = (struct snd_seq_ump_event *)__event;
 438	struct snd_seq_ump_event ev_cvt;
 439	union snd_ump_midi1_msg *midi1 = (union snd_ump_midi1_msg *)ev_cvt.ump;
 440	const union snd_ump_midi2_msg *midi2 = (const union snd_ump_midi2_msg *)event->ump;
 441	int err;
 442	u16 v;
 443
 444	ev_cvt = *event;
 445	memset(&ev_cvt.ump, 0, sizeof(ev_cvt.ump));
 446
 447	midi1->note.type = UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE;
 448	midi1->note.group = midi2->note.group;
 449	midi1->note.status = midi2->note.status;
 450	midi1->note.channel = midi2->note.channel;
 451	switch (midi2->note.status) {
 452	case UMP_MSG_STATUS_NOTE_ON:
 453	case UMP_MSG_STATUS_NOTE_OFF:
 454		midi1->note.note = midi2->note.note;
 455		midi1->note.velocity = downscale_16_to_7bit(midi2->note.velocity);
 456		break;
 457	case UMP_MSG_STATUS_POLY_PRESSURE:
 458		midi1->paf.note = midi2->paf.note;
 459		midi1->paf.data = downscale_32_to_7bit(midi2->paf.data);
 460		break;
 461	case UMP_MSG_STATUS_CC:
 462		midi1->cc.index = midi2->cc.index;
 463		midi1->cc.data = downscale_32_to_7bit(midi2->cc.data);
 464		break;
 465	case UMP_MSG_STATUS_PROGRAM:
 466		if (midi2->pg.bank_valid) {
 467			midi1->cc.status = UMP_MSG_STATUS_CC;
 468			midi1->cc.index = UMP_CC_BANK_SELECT;
 469			midi1->cc.data = midi2->pg.bank_msb;
 470			err = __snd_seq_deliver_single_event(dest, dest_port,
 471							     (struct snd_seq_event *)&ev_cvt,
 472							     atomic, hop);
 473			if (err < 0)
 474				return err;
 475			midi1->cc.index = UMP_CC_BANK_SELECT_LSB;
 476			midi1->cc.data = midi2->pg.bank_lsb;
 477			err = __snd_seq_deliver_single_event(dest, dest_port,
 478							     (struct snd_seq_event *)&ev_cvt,
 479							     atomic, hop);
 480			if (err < 0)
 481				return err;
 482			midi1->note.status = midi2->note.status;
 483		}
 484		midi1->pg.program = midi2->pg.program;
 485		break;
 486	case UMP_MSG_STATUS_CHANNEL_PRESSURE:
 487		midi1->caf.data = downscale_32_to_7bit(midi2->caf.data);
 488		break;
 489	case UMP_MSG_STATUS_PITCH_BEND:
 490		v = downscale_32_to_14bit(midi2->pb.data);
 491		midi1->pb.data_msb = v >> 7;
 492		midi1->pb.data_lsb = v & 0x7f;
 493		break;
 494	default:
 495		return 0;
 496	}
 497
 498	return __snd_seq_deliver_single_event(dest, dest_port,
 499					      (struct snd_seq_event *)&ev_cvt,
 500					      atomic, hop);
 501}
 502
 503/* convert UMP to a legacy ALSA seq event and deliver it */
 504static int cvt_ump_to_any(struct snd_seq_client *dest,
 505			  struct snd_seq_client_port *dest_port,
 506			  struct snd_seq_event *event,
 507			  unsigned char type,
 508			  int atomic, int hop)
 509{
 510	struct snd_seq_event ev_cvt[2]; /* up to two events */
 511	struct snd_seq_ump_event *ump_ev = (struct snd_seq_ump_event *)event;
 512	/* use the second event as a temp buffer for saving stack usage */
 513	unsigned char *sysex_buf = (unsigned char *)(ev_cvt + 1);
 514	unsigned char flags = event->flags & ~SNDRV_SEQ_EVENT_UMP;
 515	int i, len, err;
 516
 517	ev_cvt[0] = ev_cvt[1] = *event;
 518	ev_cvt[0].flags = flags;
 519	ev_cvt[1].flags = flags;
 520	switch (type) {
 521	case UMP_MSG_TYPE_SYSTEM:
 522		len = cvt_ump_system_to_event((union snd_ump_midi1_msg *)ump_ev->ump,
 523					      ev_cvt);
 524		break;
 525	case UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE:
 526		len = cvt_ump_midi1_to_event((union snd_ump_midi1_msg *)ump_ev->ump,
 527					     ev_cvt);
 528		break;
 529	case UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE:
 530		len = cvt_ump_midi2_to_event((union snd_ump_midi2_msg *)ump_ev->ump,
 531					     ev_cvt);
 532		break;
 533	case UMP_MSG_TYPE_DATA:
 534		len = cvt_ump_sysex7_to_event(ump_ev->ump, sysex_buf, ev_cvt);
 535		break;
 536	default:
 537		return 0;
 538	}
 539
 540	for (i = 0; i < len; i++) {
 541		err = __snd_seq_deliver_single_event(dest, dest_port,
 542						     &ev_cvt[i], atomic, hop);
 543		if (err < 0)
 544			return err;
 545	}
 546
 547	return 0;
 548}
 549
 550/* Replace UMP group field with the destination and deliver */
 551static int deliver_with_group_convert(struct snd_seq_client *dest,
 552				      struct snd_seq_client_port *dest_port,
 553				      struct snd_seq_ump_event *ump_ev,
 554				      int atomic, int hop)
 555{
 556	struct snd_seq_ump_event ev = *ump_ev;
 557
 558	/* rewrite the group to the destination port */
 559	ev.ump[0] &= ~(0xfU << 24);
 560	/* fill with the new group; the dest_port->ump_group field is 1-based */
 561	ev.ump[0] |= ((dest_port->ump_group - 1) << 24);
 562
 563	return __snd_seq_deliver_single_event(dest, dest_port,
 564					      (struct snd_seq_event *)&ev,
 565					      atomic, hop);
 566}
 567
 568/* apply the UMP event filter; return true to skip the event */
 569static bool ump_event_filtered(struct snd_seq_client *dest,
 570			       const struct snd_seq_ump_event *ev)
 571{
 572	unsigned char group;
 573
 574	group = ump_message_group(ev->ump[0]);
 575	if (ump_is_groupless_msg(ump_message_type(ev->ump[0])))
 576		return dest->group_filter & (1U << 0);
 577	/* check the bitmap for 1-based group number */
 578	return dest->group_filter & (1U << (group + 1));
 579}
 580
 581/* Convert from UMP packet and deliver */
 582int snd_seq_deliver_from_ump(struct snd_seq_client *source,
 583			     struct snd_seq_client *dest,
 584			     struct snd_seq_client_port *dest_port,
 585			     struct snd_seq_event *event,
 586			     int atomic, int hop)
 587{
 588	struct snd_seq_ump_event *ump_ev = (struct snd_seq_ump_event *)event;
 589	unsigned char type;
 590
 591	if (snd_seq_ev_is_variable(event))
 592		return 0; // skip, no variable event for UMP, so far
 593	if (ump_event_filtered(dest, ump_ev))
 594		return 0; // skip if group filter is set and matching
 595	type = ump_message_type(ump_ev->ump[0]);
 596
 597	if (snd_seq_client_is_ump(dest)) {
 598		bool is_midi2 = snd_seq_client_is_midi2(dest) &&
 599			!dest_port->is_midi1;
 600
 601		if (is_midi2 && type == UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE)
 602			return cvt_ump_midi1_to_midi2(dest, dest_port,
 603						      event, atomic, hop);
 604		else if (!is_midi2 && type == UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE)
 605			return cvt_ump_midi2_to_midi1(dest, dest_port,
 606						      event, atomic, hop);
 607		/* non-EP port and different group is set? */
 608		if (dest_port->ump_group &&
 609		    !ump_is_groupless_msg(type) &&
 610		    ump_message_group(*ump_ev->ump) + 1 != dest_port->ump_group)
 611			return deliver_with_group_convert(dest, dest_port,
 612							  ump_ev, atomic, hop);
 613		/* copy as-is */
 614		return __snd_seq_deliver_single_event(dest, dest_port,
 615						      event, atomic, hop);
 616	}
 617
 618	return cvt_ump_to_any(dest, dest_port, event, type, atomic, hop);
 619}
 620
 621/*
 622 * MIDI1 sequencer event -> UMP conversion
 623 */
 624
 625/* Conversion to UMP MIDI 1.0 */
 626
 627/* convert note on/off event to MIDI 1.0 UMP */
 628static int note_ev_to_ump_midi1(const struct snd_seq_event *event,
 629				struct snd_seq_client_port *dest_port,
 630				union snd_ump_midi1_msg *data,
 631				unsigned char status)
 632{
 633	if (!event->data.note.velocity)
 634		status = UMP_MSG_STATUS_NOTE_OFF;
 635	data->note.status = status;
 636	data->note.channel = event->data.note.channel & 0x0f;
 637	data->note.velocity = event->data.note.velocity & 0x7f;
 638	data->note.note = event->data.note.note & 0x7f;
 639	return 1;
 640}
 641
 642/* convert CC event to MIDI 1.0 UMP */
 643static int cc_ev_to_ump_midi1(const struct snd_seq_event *event,
 644			      struct snd_seq_client_port *dest_port,
 645			      union snd_ump_midi1_msg *data,
 646			      unsigned char status)
 647{
 648	data->cc.status = status;
 649	data->cc.channel = event->data.control.channel & 0x0f;
 650	data->cc.index = event->data.control.param;
 651	data->cc.data = event->data.control.value;
 652	return 1;
 653}
 654
 655/* convert one-parameter control event to MIDI 1.0 UMP */
 656static int ctrl_ev_to_ump_midi1(const struct snd_seq_event *event,
 657				struct snd_seq_client_port *dest_port,
 658				union snd_ump_midi1_msg *data,
 659				unsigned char status)
 660{
 661	data->caf.status = status;
 662	data->caf.channel = event->data.control.channel & 0x0f;
 663	data->caf.data = event->data.control.value & 0x7f;
 664	return 1;
 665}
 666
 667/* convert pitchbend event to MIDI 1.0 UMP */
 668static int pitchbend_ev_to_ump_midi1(const struct snd_seq_event *event,
 669				     struct snd_seq_client_port *dest_port,
 670				     union snd_ump_midi1_msg *data,
 671				     unsigned char status)
 672{
 673	int val = event->data.control.value + 8192;
 674
 675	val = clamp(val, 0, 0x3fff);
 676	data->pb.status = status;
 677	data->pb.channel = event->data.control.channel & 0x0f;
 678	data->pb.data_msb = (val >> 7) & 0x7f;
 679	data->pb.data_lsb = val & 0x7f;
 680	return 1;
 681}
 682
 683/* convert 14bit control event to MIDI 1.0 UMP; split to two events */
 684static int ctrl14_ev_to_ump_midi1(const struct snd_seq_event *event,
 685				  struct snd_seq_client_port *dest_port,
 686				  union snd_ump_midi1_msg *data,
 687				  unsigned char status)
 688{
 689	data->cc.status = UMP_MSG_STATUS_CC;
 690	data->cc.channel = event->data.control.channel & 0x0f;
 691	data->cc.index = event->data.control.param & 0x7f;
 692	if (event->data.control.param < 0x20) {
 693		data->cc.data = (event->data.control.value >> 7) & 0x7f;
 694		data[1] = data[0];
 695		data[1].cc.index = event->data.control.param | 0x20;
 696		data[1].cc.data = event->data.control.value & 0x7f;
 697		return 2;
 698	}
 699
 700	data->cc.data = event->data.control.value & 0x7f;
 701	return 1;
 702}
 703
 704/* convert RPN/NRPN event to MIDI 1.0 UMP; split to four events */
 705static int rpn_ev_to_ump_midi1(const struct snd_seq_event *event,
 706			       struct snd_seq_client_port *dest_port,
 707			       union snd_ump_midi1_msg *data,
 708			       unsigned char status)
 709{
 710	bool is_rpn = (status == UMP_MSG_STATUS_RPN);
 711
 712	data->cc.status = UMP_MSG_STATUS_CC;
 713	data->cc.channel = event->data.control.channel & 0x0f;
 714	data[1] = data[2] = data[3] = data[0];
 715
 716	data[0].cc.index = is_rpn ? UMP_CC_RPN_MSB : UMP_CC_NRPN_MSB;
 717	data[0].cc.data = (event->data.control.param >> 7) & 0x7f;
 718	data[1].cc.index = is_rpn ? UMP_CC_RPN_LSB : UMP_CC_NRPN_LSB;
 719	data[1].cc.data = event->data.control.param & 0x7f;
 720	data[2].cc.index = UMP_CC_DATA;
 721	data[2].cc.data = (event->data.control.value >> 7) & 0x7f;
 722	data[3].cc.index = UMP_CC_DATA_LSB;
 723	data[3].cc.data = event->data.control.value & 0x7f;
 724	return 4;
 725}
 726
 727/* convert system / RT message to UMP */
 728static int system_ev_to_ump_midi1(const struct snd_seq_event *event,
 729				  struct snd_seq_client_port *dest_port,
 730				  union snd_ump_midi1_msg *data,
 731				  unsigned char status)
 732{
 733	data->system.type = UMP_MSG_TYPE_SYSTEM; // override
 734	data->system.status = status;
 735	return 1;
 736}
 737
 738/* convert system / RT message with 1 parameter to UMP */
 739static int system_1p_ev_to_ump_midi1(const struct snd_seq_event *event,
 740				     struct snd_seq_client_port *dest_port,
 741				     union snd_ump_midi1_msg *data,
 742				     unsigned char status)
 743{
 744	data->system.type = UMP_MSG_TYPE_SYSTEM; // override
 745	data->system.status = status;
 746	data->system.parm1 = event->data.control.value & 0x7f;
 747	return 1;
 748}
 749
 750/* convert system / RT message with two parameters to UMP */
 751static int system_2p_ev_to_ump_midi1(const struct snd_seq_event *event,
 752				     struct snd_seq_client_port *dest_port,
 753				     union snd_ump_midi1_msg *data,
 754				     unsigned char status)
 755{
 756	data->system.type = UMP_MSG_TYPE_SYSTEM; // override
 757	data->system.status = status;
 758	data->system.parm1 = event->data.control.value & 0x7f;
 759	data->system.parm2 = (event->data.control.value >> 7) & 0x7f;
 760	return 1;
 761}
 762
 763/* Conversion to UMP MIDI 2.0 */
 764
 765/* convert note on/off event to MIDI 2.0 UMP */
 766static int note_ev_to_ump_midi2(const struct snd_seq_event *event,
 767				struct snd_seq_client_port *dest_port,
 768				union snd_ump_midi2_msg *data,
 769				unsigned char status)
 770{
 771	if (!event->data.note.velocity)
 772		status = UMP_MSG_STATUS_NOTE_OFF;
 773	data->note.status = status;
 774	data->note.channel = event->data.note.channel & 0x0f;
 775	data->note.note = event->data.note.note & 0x7f;
 776	data->note.velocity = upscale_7_to_16bit(event->data.note.velocity & 0x7f);
 777	return 1;
 778}
 779
 780/* convert PAF event to MIDI 2.0 UMP */
 781static int paf_ev_to_ump_midi2(const struct snd_seq_event *event,
 782			       struct snd_seq_client_port *dest_port,
 783			       union snd_ump_midi2_msg *data,
 784			       unsigned char status)
 785{
 786	data->paf.status = status;
 787	data->paf.channel = event->data.note.channel & 0x0f;
 788	data->paf.note = event->data.note.note & 0x7f;
 789	data->paf.data = upscale_7_to_32bit(event->data.note.velocity & 0x7f);
 790	return 1;
 791}
 792
 793static void reset_rpn(struct ump_cvt_to_ump_bank *cc)
 794{
 795	cc->rpn_set = 0;
 796	cc->nrpn_set = 0;
 797	cc->cc_rpn_msb = cc->cc_rpn_lsb = 0;
 798	cc->cc_data_msb = cc->cc_data_lsb = 0;
 799	cc->cc_data_msb_set = cc->cc_data_lsb_set = 0;
 800}
 801
 802/* set up the MIDI2 RPN/NRPN packet data from the parsed info */
 803static int fill_rpn(struct ump_cvt_to_ump_bank *cc,
 804		    union snd_ump_midi2_msg *data,
 805		    unsigned char channel,
 806		    bool flush)
 807{
 808	if (!(cc->cc_data_lsb_set || cc->cc_data_msb_set))
 809		return 0; // skip
 810	/* when not flushing, wait for complete data set */
 811	if (!flush && (!cc->cc_data_lsb_set || !cc->cc_data_msb_set))
 812		return 0; // skip
 813
 814	if (cc->rpn_set) {
 815		data->rpn.status = UMP_MSG_STATUS_RPN;
 816		data->rpn.bank = cc->cc_rpn_msb;
 817		data->rpn.index = cc->cc_rpn_lsb;
 818	} else if (cc->nrpn_set) {
 819		data->rpn.status = UMP_MSG_STATUS_NRPN;
 820		data->rpn.bank = cc->cc_nrpn_msb;
 821		data->rpn.index = cc->cc_nrpn_lsb;
 822	} else {
 823		return 0; // skip
 824	}
 825
 826	data->rpn.data = upscale_14_to_32bit((cc->cc_data_msb << 7) |
 827					     cc->cc_data_lsb);
 828	data->rpn.channel = channel;
 829
 830	reset_rpn(cc);
 831	return 1;
 832}
 833
 834/* convert CC event to MIDI 2.0 UMP */
 835static int cc_ev_to_ump_midi2(const struct snd_seq_event *event,
 836			      struct snd_seq_client_port *dest_port,
 837			      union snd_ump_midi2_msg *data,
 838			      unsigned char status)
 839{
 840	unsigned char channel = event->data.control.channel & 0x0f;
 841	unsigned char index = event->data.control.param & 0x7f;
 842	unsigned char val = event->data.control.value & 0x7f;
 843	struct ump_cvt_to_ump_bank *cc = &dest_port->midi2_bank[channel];
 844	int ret;
 845
 846	/* process special CC's (bank/rpn/nrpn) */
 847	switch (index) {
 848	case UMP_CC_RPN_MSB:
 849		ret = fill_rpn(cc, data, channel, true);
 850		cc->rpn_set = 1;
 851		cc->cc_rpn_msb = val;
 852		if (cc->cc_rpn_msb == 0x7f && cc->cc_rpn_lsb == 0x7f)
 853			reset_rpn(cc);
 854		return ret;
 855	case UMP_CC_RPN_LSB:
 856		ret = fill_rpn(cc, data, channel, true);
 857		cc->rpn_set = 1;
 858		cc->cc_rpn_lsb = val;
 859		if (cc->cc_rpn_msb == 0x7f && cc->cc_rpn_lsb == 0x7f)
 860			reset_rpn(cc);
 861		return ret;
 862	case UMP_CC_NRPN_MSB:
 863		ret = fill_rpn(cc, data, channel, true);
 864		cc->nrpn_set = 1;
 865		cc->cc_nrpn_msb = val;
 866		return ret;
 867	case UMP_CC_NRPN_LSB:
 868		ret = fill_rpn(cc, data, channel, true);
 869		cc->nrpn_set = 1;
 870		cc->cc_nrpn_lsb = val;
 871		return ret;
 872	case UMP_CC_DATA:
 873		cc->cc_data_msb_set = 1;
 874		cc->cc_data_msb = val;
 875		return fill_rpn(cc, data, channel, false);
 876	case UMP_CC_BANK_SELECT:
 877		cc->bank_set = 1;
 878		cc->cc_bank_msb = val;
 879		return 0; // skip
 880	case UMP_CC_BANK_SELECT_LSB:
 881		cc->bank_set = 1;
 882		cc->cc_bank_lsb = val;
 883		return 0; // skip
 884	case UMP_CC_DATA_LSB:
 885		cc->cc_data_lsb_set = 1;
 886		cc->cc_data_lsb = val;
 887		return fill_rpn(cc, data, channel, false);
 888	}
 889
 890	data->cc.status = status;
 891	data->cc.channel = channel;
 892	data->cc.index = index;
 893	data->cc.data = upscale_7_to_32bit(event->data.control.value & 0x7f);
 894	return 1;
 895}
 896
 897/* convert one-parameter control event to MIDI 2.0 UMP */
 898static int ctrl_ev_to_ump_midi2(const struct snd_seq_event *event,
 899				struct snd_seq_client_port *dest_port,
 900				union snd_ump_midi2_msg *data,
 901				unsigned char status)
 902{
 903	data->caf.status = status;
 904	data->caf.channel = event->data.control.channel & 0x0f;
 905	data->caf.data = upscale_7_to_32bit(event->data.control.value & 0x7f);
 906	return 1;
 907}
 908
 909/* convert program change event to MIDI 2.0 UMP */
 910static int pgm_ev_to_ump_midi2(const struct snd_seq_event *event,
 911			       struct snd_seq_client_port *dest_port,
 912			       union snd_ump_midi2_msg *data,
 913			       unsigned char status)
 914{
 915	unsigned char channel = event->data.control.channel & 0x0f;
 916	struct ump_cvt_to_ump_bank *cc = &dest_port->midi2_bank[channel];
 917
 918	data->pg.status = status;
 919	data->pg.channel = channel;
 920	data->pg.program = event->data.control.value & 0x7f;
 921	if (cc->bank_set) {
 922		data->pg.bank_valid = 1;
 923		data->pg.bank_msb = cc->cc_bank_msb;
 924		data->pg.bank_lsb = cc->cc_bank_lsb;
 925		cc->bank_set = 0;
 926	}
 927	return 1;
 928}
 929
 930/* convert pitchbend event to MIDI 2.0 UMP */
 931static int pitchbend_ev_to_ump_midi2(const struct snd_seq_event *event,
 932				     struct snd_seq_client_port *dest_port,
 933				     union snd_ump_midi2_msg *data,
 934				     unsigned char status)
 935{
 936	int val = event->data.control.value + 8192;
 937
 938	val = clamp(val, 0, 0x3fff);
 939	data->pb.status = status;
 940	data->pb.channel = event->data.control.channel & 0x0f;
 941	data->pb.data = upscale_14_to_32bit(val);
 942	return 1;
 943}
 944
 945/* convert 14bit control event to MIDI 2.0 UMP; split to two events */
 946static int ctrl14_ev_to_ump_midi2(const struct snd_seq_event *event,
 947				  struct snd_seq_client_port *dest_port,
 948				  union snd_ump_midi2_msg *data,
 949				  unsigned char status)
 950{
 951	unsigned char channel = event->data.control.channel & 0x0f;
 952	unsigned char index = event->data.control.param & 0x7f;
 953	struct ump_cvt_to_ump_bank *cc = &dest_port->midi2_bank[channel];
 954	unsigned char msb, lsb;
 955	int ret;
 956
 957	msb = (event->data.control.value >> 7) & 0x7f;
 958	lsb = event->data.control.value & 0x7f;
 959	/* process special CC's (bank/rpn/nrpn) */
 960	switch (index) {
 961	case UMP_CC_BANK_SELECT:
 962		cc->cc_bank_msb = msb;
 963		fallthrough;
 964	case UMP_CC_BANK_SELECT_LSB:
 965		cc->bank_set = 1;
 966		cc->cc_bank_lsb = lsb;
 967		return 0; // skip
 968	case UMP_CC_RPN_MSB:
 969	case UMP_CC_RPN_LSB:
 970		ret = fill_rpn(cc, data, channel, true);
 971		cc->cc_rpn_msb = msb;
 972		cc->cc_rpn_lsb = lsb;
 973		cc->rpn_set = 1;
 974		if (cc->cc_rpn_msb == 0x7f && cc->cc_rpn_lsb == 0x7f)
 975			reset_rpn(cc);
 976		return ret;
 977	case UMP_CC_NRPN_MSB:
 978	case UMP_CC_NRPN_LSB:
 979		ret = fill_rpn(cc, data, channel, true);
 980		cc->cc_nrpn_msb = msb;
 981		cc->nrpn_set = 1;
 982		cc->cc_nrpn_lsb = lsb;
 983		return ret;
 984	case UMP_CC_DATA:
 985	case UMP_CC_DATA_LSB:
 986		cc->cc_data_msb_set = cc->cc_data_lsb_set = 1;
 987		cc->cc_data_msb = msb;
 988		cc->cc_data_lsb = lsb;
 989		return fill_rpn(cc, data, channel, false);
 990	}
 991
 992	data->cc.status = UMP_MSG_STATUS_CC;
 993	data->cc.channel = channel;
 994	data->cc.index = index;
 995	if (event->data.control.param < 0x20) {
 996		data->cc.data = upscale_7_to_32bit(msb);
 997		data[1] = data[0];
 998		data[1].cc.index = event->data.control.param | 0x20;
 999		data[1].cc.data = upscale_7_to_32bit(lsb);
1000		return 2;
1001	}
1002
1003	data->cc.data = upscale_7_to_32bit(lsb);
1004	return 1;
1005}
1006
1007/* convert RPN/NRPN event to MIDI 2.0 UMP */
1008static int rpn_ev_to_ump_midi2(const struct snd_seq_event *event,
1009			       struct snd_seq_client_port *dest_port,
1010			       union snd_ump_midi2_msg *data,
1011			       unsigned char status)
1012{
1013	data->rpn.status = status;
1014	data->rpn.channel = event->data.control.channel;
1015	data->rpn.bank = (event->data.control.param >> 7) & 0x7f;
1016	data->rpn.index = event->data.control.param & 0x7f;
1017	data->rpn.data = upscale_14_to_32bit(event->data.control.value & 0x3fff);
1018	return 1;
1019}
1020
1021/* convert system / RT message to UMP */
1022static int system_ev_to_ump_midi2(const struct snd_seq_event *event,
1023				  struct snd_seq_client_port *dest_port,
1024				  union snd_ump_midi2_msg *data,
1025				  unsigned char status)
1026{
1027	return system_ev_to_ump_midi1(event, dest_port,
1028				      (union snd_ump_midi1_msg *)data,
1029				      status);
1030}
1031
1032/* convert system / RT message with 1 parameter to UMP */
1033static int system_1p_ev_to_ump_midi2(const struct snd_seq_event *event,
1034				     struct snd_seq_client_port *dest_port,
1035				     union snd_ump_midi2_msg *data,
1036				     unsigned char status)
1037{
1038	return system_1p_ev_to_ump_midi1(event, dest_port,
1039					 (union snd_ump_midi1_msg *)data,
1040					 status);
1041}
1042
1043/* convert system / RT message with two parameters to UMP */
1044static int system_2p_ev_to_ump_midi2(const struct snd_seq_event *event,
1045				     struct snd_seq_client_port *dest_port,
1046				     union snd_ump_midi2_msg *data,
1047				     unsigned char status)
1048{
1049	return system_2p_ev_to_ump_midi1(event, dest_port,
1050					 (union snd_ump_midi1_msg *)data,
1051					 status);
1052}
1053
1054struct seq_ev_to_ump {
1055	int seq_type;
1056	unsigned char status;
1057	int (*midi1_encode)(const struct snd_seq_event *event,
1058			    struct snd_seq_client_port *dest_port,
1059			    union snd_ump_midi1_msg *data,
1060			    unsigned char status);
1061	int (*midi2_encode)(const struct snd_seq_event *event,
1062			    struct snd_seq_client_port *dest_port,
1063			    union snd_ump_midi2_msg *data,
1064			    unsigned char status);
1065};
1066
1067static const struct seq_ev_to_ump seq_ev_ump_encoders[] = {
1068	{ SNDRV_SEQ_EVENT_NOTEON, UMP_MSG_STATUS_NOTE_ON,
1069	  note_ev_to_ump_midi1, note_ev_to_ump_midi2 },
1070	{ SNDRV_SEQ_EVENT_NOTEOFF, UMP_MSG_STATUS_NOTE_OFF,
1071	  note_ev_to_ump_midi1, note_ev_to_ump_midi2 },
1072	{ SNDRV_SEQ_EVENT_KEYPRESS, UMP_MSG_STATUS_POLY_PRESSURE,
1073	  note_ev_to_ump_midi1, paf_ev_to_ump_midi2 },
1074	{ SNDRV_SEQ_EVENT_CONTROLLER, UMP_MSG_STATUS_CC,
1075	  cc_ev_to_ump_midi1, cc_ev_to_ump_midi2 },
1076	{ SNDRV_SEQ_EVENT_PGMCHANGE, UMP_MSG_STATUS_PROGRAM,
1077	  ctrl_ev_to_ump_midi1, pgm_ev_to_ump_midi2 },
1078	{ SNDRV_SEQ_EVENT_CHANPRESS, UMP_MSG_STATUS_CHANNEL_PRESSURE,
1079	  ctrl_ev_to_ump_midi1, ctrl_ev_to_ump_midi2 },
1080	{ SNDRV_SEQ_EVENT_PITCHBEND, UMP_MSG_STATUS_PITCH_BEND,
1081	  pitchbend_ev_to_ump_midi1, pitchbend_ev_to_ump_midi2 },
1082	{ SNDRV_SEQ_EVENT_CONTROL14, 0,
1083	  ctrl14_ev_to_ump_midi1, ctrl14_ev_to_ump_midi2 },
1084	{ SNDRV_SEQ_EVENT_NONREGPARAM, UMP_MSG_STATUS_NRPN,
1085	  rpn_ev_to_ump_midi1, rpn_ev_to_ump_midi2 },
1086	{ SNDRV_SEQ_EVENT_REGPARAM, UMP_MSG_STATUS_RPN,
1087	  rpn_ev_to_ump_midi1, rpn_ev_to_ump_midi2 },
1088	{ SNDRV_SEQ_EVENT_QFRAME, UMP_SYSTEM_STATUS_MIDI_TIME_CODE,
1089	  system_1p_ev_to_ump_midi1, system_1p_ev_to_ump_midi2 },
1090	{ SNDRV_SEQ_EVENT_SONGPOS, UMP_SYSTEM_STATUS_SONG_POSITION,
1091	  system_2p_ev_to_ump_midi1, system_2p_ev_to_ump_midi2 },
1092	{ SNDRV_SEQ_EVENT_SONGSEL, UMP_SYSTEM_STATUS_SONG_SELECT,
1093	  system_1p_ev_to_ump_midi1, system_1p_ev_to_ump_midi2 },
1094	{ SNDRV_SEQ_EVENT_TUNE_REQUEST, UMP_SYSTEM_STATUS_TUNE_REQUEST,
1095	  system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
1096	{ SNDRV_SEQ_EVENT_CLOCK, UMP_SYSTEM_STATUS_TIMING_CLOCK,
1097	  system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
1098	{ SNDRV_SEQ_EVENT_START, UMP_SYSTEM_STATUS_START,
1099	  system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
1100	{ SNDRV_SEQ_EVENT_CONTINUE, UMP_SYSTEM_STATUS_CONTINUE,
1101	  system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
1102	{ SNDRV_SEQ_EVENT_STOP, UMP_SYSTEM_STATUS_STOP,
1103	  system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
1104	{ SNDRV_SEQ_EVENT_SENSING, UMP_SYSTEM_STATUS_ACTIVE_SENSING,
1105	  system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
1106	{ SNDRV_SEQ_EVENT_RESET, UMP_SYSTEM_STATUS_RESET,
1107	  system_ev_to_ump_midi1, system_ev_to_ump_midi2 },
1108};
1109
1110static const struct seq_ev_to_ump *find_ump_encoder(int type)
1111{
1112	int i;
1113
1114	for (i = 0; i < ARRAY_SIZE(seq_ev_ump_encoders); i++)
1115		if (seq_ev_ump_encoders[i].seq_type == type)
1116			return &seq_ev_ump_encoders[i];
1117
1118	return NULL;
1119}
1120
1121static void setup_ump_event(struct snd_seq_ump_event *dest,
1122			    const struct snd_seq_event *src)
1123{
1124	memcpy(dest, src, sizeof(*src));
1125	dest->type = 0;
1126	dest->flags |= SNDRV_SEQ_EVENT_UMP;
1127	dest->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
1128	memset(dest->ump, 0, sizeof(dest->ump));
1129}
1130
1131/* Convert ALSA seq event to UMP MIDI 1.0 and deliver it */
1132static int cvt_to_ump_midi1(struct snd_seq_client *dest,
1133			    struct snd_seq_client_port *dest_port,
1134			    struct snd_seq_event *event,
1135			    int atomic, int hop)
1136{
1137	const struct seq_ev_to_ump *encoder;
1138	struct snd_seq_ump_event ev_cvt;
1139	union snd_ump_midi1_msg data[4];
1140	int i, n, err;
1141
1142	encoder = find_ump_encoder(event->type);
1143	if (!encoder)
1144		return __snd_seq_deliver_single_event(dest, dest_port,
1145						      event, atomic, hop);
1146
1147	data->raw = make_raw_ump(dest_port, UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE);
1148	n = encoder->midi1_encode(event, dest_port, data, encoder->status);
1149	if (!n)
1150		return 0;
1151
1152	setup_ump_event(&ev_cvt, event);
1153	for (i = 0; i < n; i++) {
1154		ev_cvt.ump[0] = data[i].raw;
1155		err = __snd_seq_deliver_single_event(dest, dest_port,
1156						     (struct snd_seq_event *)&ev_cvt,
1157						     atomic, hop);
1158		if (err < 0)
1159			return err;
1160	}
1161
1162	return 0;
1163}
1164
1165/* Convert ALSA seq event to UMP MIDI 2.0 and deliver it */
1166static int cvt_to_ump_midi2(struct snd_seq_client *dest,
1167			    struct snd_seq_client_port *dest_port,
1168			    struct snd_seq_event *event,
1169			    int atomic, int hop)
1170{
1171	const struct seq_ev_to_ump *encoder;
1172	struct snd_seq_ump_event ev_cvt;
1173	union snd_ump_midi2_msg data[2];
1174	int i, n, err;
1175
1176	encoder = find_ump_encoder(event->type);
1177	if (!encoder)
1178		return __snd_seq_deliver_single_event(dest, dest_port,
1179						      event, atomic, hop);
1180
1181	data->raw[0] = make_raw_ump(dest_port, UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE);
1182	data->raw[1] = 0;
1183	n = encoder->midi2_encode(event, dest_port, data, encoder->status);
1184	if (!n)
1185		return 0;
1186
1187	setup_ump_event(&ev_cvt, event);
1188	for (i = 0; i < n; i++) {
1189		memcpy(ev_cvt.ump, &data[i], sizeof(data[i]));
1190		err = __snd_seq_deliver_single_event(dest, dest_port,
1191						     (struct snd_seq_event *)&ev_cvt,
1192						     atomic, hop);
1193		if (err < 0)
1194			return err;
1195	}
1196
1197	return 0;
1198}
1199
1200/* Fill up a sysex7 UMP from the byte stream */
1201static void fill_sysex7_ump(struct snd_seq_client_port *dest_port,
1202			    u32 *val, u8 status, u8 *buf, int len)
1203{
1204	memset(val, 0, 8);
1205	memcpy((u8 *)val + 2, buf, len);
1206#ifdef __LITTLE_ENDIAN
1207	swab32_array(val, 2);
1208#endif
1209	val[0] |= ump_compose(UMP_MSG_TYPE_DATA, get_ump_group(dest_port),
1210			      status, len);
1211}
1212
1213/* Convert sysex var event to UMP sysex7 packets and deliver them */
1214static int cvt_sysex_to_ump(struct snd_seq_client *dest,
1215			    struct snd_seq_client_port *dest_port,
1216			    struct snd_seq_event *event,
1217			    int atomic, int hop)
1218{
1219	struct snd_seq_ump_event ev_cvt;
1220	unsigned char status;
1221	u8 buf[8], *xbuf;
1222	int offset = 0;
1223	int len, err;
1224	bool finished = false;
1225
1226	if (!snd_seq_ev_is_variable(event))
1227		return 0;
1228
1229	setup_ump_event(&ev_cvt, event);
1230	while (!finished) {
1231		len = snd_seq_expand_var_event_at(event, sizeof(buf), buf, offset);
1232		if (len <= 0)
1233			break;
1234		if (WARN_ON(len > sizeof(buf)))
1235			break;
1236
1237		xbuf = buf;
1238		status = UMP_SYSEX_STATUS_CONTINUE;
1239		/* truncate the sysex start-marker */
1240		if (*xbuf == UMP_MIDI1_MSG_SYSEX_START) {
1241			status = UMP_SYSEX_STATUS_START;
1242			len--;
1243			offset++;
1244			xbuf++;
1245		}
1246
1247		/* if the last of this packet or the 1st byte of the next packet
1248		 * is the end-marker, finish the transfer with this packet
1249		 */
1250		if (len > 0 && len < 8 &&
1251		    xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) {
1252			if (status == UMP_SYSEX_STATUS_START)
1253				status = UMP_SYSEX_STATUS_SINGLE;
1254			else
1255				status = UMP_SYSEX_STATUS_END;
1256			len--;
1257			finished = true;
1258		}
1259
1260		len = min(len, 6);
1261		fill_sysex7_ump(dest_port, ev_cvt.ump, status, xbuf, len);
1262		err = __snd_seq_deliver_single_event(dest, dest_port,
1263						     (struct snd_seq_event *)&ev_cvt,
1264						     atomic, hop);
1265		if (err < 0)
1266			return err;
1267		offset += len;
1268	}
1269	return 0;
1270}
1271
1272/* Convert to UMP packet and deliver */
1273int snd_seq_deliver_to_ump(struct snd_seq_client *source,
1274			   struct snd_seq_client *dest,
1275			   struct snd_seq_client_port *dest_port,
1276			   struct snd_seq_event *event,
1277			   int atomic, int hop)
1278{
1279	if (dest->group_filter & (1U << dest_port->ump_group))
1280		return 0; /* group filtered - skip the event */
1281	if (event->type == SNDRV_SEQ_EVENT_SYSEX)
1282		return cvt_sysex_to_ump(dest, dest_port, event, atomic, hop);
1283	else if (snd_seq_client_is_midi2(dest) && !dest_port->is_midi1)
1284		return cvt_to_ump_midi2(dest, dest_port, event, atomic, hop);
1285	else
1286		return cvt_to_ump_midi1(dest, dest_port, event, atomic, hop);
1287}