xref: /openbmc/linux/sound/core/seq/seq_midi_event.c (revision 731922a5)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  MIDI byte <-> sequencer event coder
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>,
6c1017a4cSJaroslav Kysela  *                        Jaroslav Kysela <perex@perex.cz>
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds #include <linux/slab.h>
101da177e4SLinus Torvalds #include <linux/errno.h>
111da177e4SLinus Torvalds #include <linux/string.h>
12da155d5bSPaul Gortmaker #include <linux/module.h>
131da177e4SLinus Torvalds #include <sound/core.h>
141da177e4SLinus Torvalds #include <sound/seq_kernel.h>
151da177e4SLinus Torvalds #include <sound/seq_midi_event.h>
161da177e4SLinus Torvalds #include <sound/asoundef.h>
171da177e4SLinus Torvalds 
18c1017a4cSJaroslav Kysela MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>");
191da177e4SLinus Torvalds MODULE_DESCRIPTION("MIDI byte <-> sequencer event coder");
201da177e4SLinus Torvalds MODULE_LICENSE("GPL");
211da177e4SLinus Torvalds 
22394d0516SClemens Ladisch /* event type, index into status_event[] */
23394d0516SClemens Ladisch /* from 0 to 6 are normal commands (note off, on, etc.) for 0x9?-0xe? */
24394d0516SClemens Ladisch #define ST_INVALID	7
251da177e4SLinus Torvalds #define ST_SPECIAL	8
261da177e4SLinus Torvalds #define ST_SYSEX	ST_SPECIAL
271da177e4SLinus Torvalds /* from 8 to 15 are events for 0xf0-0xf7 */
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds /*
311da177e4SLinus Torvalds  * prototypes
321da177e4SLinus Torvalds  */
33c7e0b5bfSTakashi Iwai static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
34c7e0b5bfSTakashi Iwai static void one_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
35c7e0b5bfSTakashi Iwai static void pitchbend_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
36c7e0b5bfSTakashi Iwai static void two_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
37c7e0b5bfSTakashi Iwai static void one_param_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
38c7e0b5bfSTakashi Iwai static void songpos_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
39c7e0b5bfSTakashi Iwai static void note_decode(struct snd_seq_event *ev, unsigned char *buf);
40c7e0b5bfSTakashi Iwai static void one_param_decode(struct snd_seq_event *ev, unsigned char *buf);
41c7e0b5bfSTakashi Iwai static void pitchbend_decode(struct snd_seq_event *ev, unsigned char *buf);
42c7e0b5bfSTakashi Iwai static void two_param_decode(struct snd_seq_event *ev, unsigned char *buf);
43c7e0b5bfSTakashi Iwai static void songpos_decode(struct snd_seq_event *ev, unsigned char *buf);
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds /*
461da177e4SLinus Torvalds  * event list
471da177e4SLinus Torvalds  */
48c7e0b5bfSTakashi Iwai static struct status_event_list {
491da177e4SLinus Torvalds 	int event;
501da177e4SLinus Torvalds 	int qlen;
51c7e0b5bfSTakashi Iwai 	void (*encode)(struct snd_midi_event *dev, struct snd_seq_event *ev);
52c7e0b5bfSTakashi Iwai 	void (*decode)(struct snd_seq_event *ev, unsigned char *buf);
531da177e4SLinus Torvalds } status_event[] = {
54394d0516SClemens Ladisch 	/* 0x80 - 0xef */
551da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_NOTEOFF,	 2, note_event, note_decode},
561da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_NOTEON,	 2, note_event, note_decode},
571da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_KEYPRESS,	 2, note_event, note_decode},
581da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_CONTROLLER,	 2, two_param_ctrl_event, two_param_decode},
591da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_PGMCHANGE,	 1, one_param_ctrl_event, one_param_decode},
601da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_CHANPRESS,	 1, one_param_ctrl_event, one_param_decode},
611da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_PITCHBEND,	 2, pitchbend_ctrl_event, pitchbend_decode},
62394d0516SClemens Ladisch 	/* invalid */
63bf8c1382SClemens Ladisch 	{SNDRV_SEQ_EVENT_NONE,		-1, NULL, NULL},
641da177e4SLinus Torvalds 	/* 0xf0 - 0xff */
651da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_SYSEX,		 1, NULL, NULL}, /* sysex: 0xf0 */
661da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_QFRAME,	 1, one_param_event, one_param_decode}, /* 0xf1 */
671da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_SONGPOS,	 2, songpos_event, songpos_decode}, /* 0xf2 */
681da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_SONGSEL,	 1, one_param_event, one_param_decode}, /* 0xf3 */
69bf8c1382SClemens Ladisch 	{SNDRV_SEQ_EVENT_NONE,		-1, NULL, NULL}, /* 0xf4 */
70bf8c1382SClemens Ladisch 	{SNDRV_SEQ_EVENT_NONE,		-1, NULL, NULL}, /* 0xf5 */
711da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_TUNE_REQUEST,	 0, NULL, NULL}, /* 0xf6 */
72bf8c1382SClemens Ladisch 	{SNDRV_SEQ_EVENT_NONE,		-1, NULL, NULL}, /* 0xf7 */
731da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_CLOCK,		 0, NULL, NULL}, /* 0xf8 */
74bf8c1382SClemens Ladisch 	{SNDRV_SEQ_EVENT_NONE,		-1, NULL, NULL}, /* 0xf9 */
751da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_START,		 0, NULL, NULL}, /* 0xfa */
761da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_CONTINUE,	 0, NULL, NULL}, /* 0xfb */
771da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_STOP, 		 0, NULL, NULL}, /* 0xfc */
78bf8c1382SClemens Ladisch 	{SNDRV_SEQ_EVENT_NONE, 		-1, NULL, NULL}, /* 0xfd */
791da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_SENSING, 	 0, NULL, NULL}, /* 0xfe */
801da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_RESET, 	 0, NULL, NULL}, /* 0xff */
811da177e4SLinus Torvalds };
821da177e4SLinus Torvalds 
83c7e0b5bfSTakashi Iwai static int extra_decode_ctrl14(struct snd_midi_event *dev, unsigned char *buf, int len,
84c7e0b5bfSTakashi Iwai 			       struct snd_seq_event *ev);
85c7e0b5bfSTakashi Iwai static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf, int count,
86c7e0b5bfSTakashi Iwai 			     struct snd_seq_event *ev);
871da177e4SLinus Torvalds 
88c7e0b5bfSTakashi Iwai static struct extra_event_list {
891da177e4SLinus Torvalds 	int event;
90c7e0b5bfSTakashi Iwai 	int (*decode)(struct snd_midi_event *dev, unsigned char *buf, int len,
91c7e0b5bfSTakashi Iwai 		      struct snd_seq_event *ev);
921da177e4SLinus Torvalds } extra_event[] = {
931da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_CONTROL14, extra_decode_ctrl14},
941da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_NONREGPARAM, extra_decode_xrpn},
951da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_REGPARAM, extra_decode_xrpn},
961da177e4SLinus Torvalds };
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds /*
991da177e4SLinus Torvalds  *  new/delete record
1001da177e4SLinus Torvalds  */
1011da177e4SLinus Torvalds 
snd_midi_event_new(int bufsize,struct snd_midi_event ** rdev)102c7e0b5bfSTakashi Iwai int snd_midi_event_new(int bufsize, struct snd_midi_event **rdev)
1031da177e4SLinus Torvalds {
104c7e0b5bfSTakashi Iwai 	struct snd_midi_event *dev;
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds 	*rdev = NULL;
107ecca82b4STakashi Iwai 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1081da177e4SLinus Torvalds 	if (dev == NULL)
1091da177e4SLinus Torvalds 		return -ENOMEM;
1101da177e4SLinus Torvalds 	if (bufsize > 0) {
1111da177e4SLinus Torvalds 		dev->buf = kmalloc(bufsize, GFP_KERNEL);
1121da177e4SLinus Torvalds 		if (dev->buf == NULL) {
1131da177e4SLinus Torvalds 			kfree(dev);
1141da177e4SLinus Torvalds 			return -ENOMEM;
1151da177e4SLinus Torvalds 		}
1161da177e4SLinus Torvalds 	}
1171da177e4SLinus Torvalds 	dev->bufsize = bufsize;
1181da177e4SLinus Torvalds 	dev->lastcmd = 0xff;
119394d0516SClemens Ladisch 	dev->type = ST_INVALID;
1201da177e4SLinus Torvalds 	spin_lock_init(&dev->lock);
1211da177e4SLinus Torvalds 	*rdev = dev;
1221da177e4SLinus Torvalds 	return 0;
1231da177e4SLinus Torvalds }
1249c8ddd10STakashi Iwai EXPORT_SYMBOL(snd_midi_event_new);
1251da177e4SLinus Torvalds 
snd_midi_event_free(struct snd_midi_event * dev)126c7e0b5bfSTakashi Iwai void snd_midi_event_free(struct snd_midi_event *dev)
1271da177e4SLinus Torvalds {
1281da177e4SLinus Torvalds 	if (dev != NULL) {
1291da177e4SLinus Torvalds 		kfree(dev->buf);
1301da177e4SLinus Torvalds 		kfree(dev);
1311da177e4SLinus Torvalds 	}
1321da177e4SLinus Torvalds }
1339c8ddd10STakashi Iwai EXPORT_SYMBOL(snd_midi_event_free);
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds /*
1361da177e4SLinus Torvalds  * initialize record
1371da177e4SLinus Torvalds  */
reset_encode(struct snd_midi_event * dev)138c7e0b5bfSTakashi Iwai static inline void reset_encode(struct snd_midi_event *dev)
1391da177e4SLinus Torvalds {
1401da177e4SLinus Torvalds 	dev->read = 0;
1411da177e4SLinus Torvalds 	dev->qlen = 0;
142394d0516SClemens Ladisch 	dev->type = ST_INVALID;
1431da177e4SLinus Torvalds }
1441da177e4SLinus Torvalds 
snd_midi_event_reset_encode(struct snd_midi_event * dev)145c7e0b5bfSTakashi Iwai void snd_midi_event_reset_encode(struct snd_midi_event *dev)
1461da177e4SLinus Torvalds {
1471da177e4SLinus Torvalds 	unsigned long flags;
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds 	spin_lock_irqsave(&dev->lock, flags);
1501da177e4SLinus Torvalds 	reset_encode(dev);
1511da177e4SLinus Torvalds 	spin_unlock_irqrestore(&dev->lock, flags);
1521da177e4SLinus Torvalds }
1539c8ddd10STakashi Iwai EXPORT_SYMBOL(snd_midi_event_reset_encode);
1541da177e4SLinus Torvalds 
snd_midi_event_reset_decode(struct snd_midi_event * dev)155c7e0b5bfSTakashi Iwai void snd_midi_event_reset_decode(struct snd_midi_event *dev)
1561da177e4SLinus Torvalds {
1571da177e4SLinus Torvalds 	unsigned long flags;
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 	spin_lock_irqsave(&dev->lock, flags);
1601da177e4SLinus Torvalds 	dev->lastcmd = 0xff;
1611da177e4SLinus Torvalds 	spin_unlock_irqrestore(&dev->lock, flags);
1621da177e4SLinus Torvalds }
1639c8ddd10STakashi Iwai EXPORT_SYMBOL(snd_midi_event_reset_decode);
1641da177e4SLinus Torvalds 
snd_midi_event_no_status(struct snd_midi_event * dev,int on)165c7e0b5bfSTakashi Iwai void snd_midi_event_no_status(struct snd_midi_event *dev, int on)
1661da177e4SLinus Torvalds {
1671da177e4SLinus Torvalds 	dev->nostat = on ? 1 : 0;
1681da177e4SLinus Torvalds }
1699c8ddd10STakashi Iwai EXPORT_SYMBOL(snd_midi_event_no_status);
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds /*
1721da177e4SLinus Torvalds  *  read one byte and encode to sequencer event:
173ef965ad5STakashi Iwai  *  return true if MIDI bytes are encoded to an event
174ef965ad5STakashi Iwai  *         false data is not finished
1751da177e4SLinus Torvalds  */
snd_midi_event_encode_byte(struct snd_midi_event * dev,unsigned char c,struct snd_seq_event * ev)176ef965ad5STakashi Iwai bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
177c7e0b5bfSTakashi Iwai 				struct snd_seq_event *ev)
1781da177e4SLinus Torvalds {
179ef965ad5STakashi Iwai 	bool rc = false;
1801da177e4SLinus Torvalds 	unsigned long flags;
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds 	if (c >= MIDI_CMD_COMMON_CLOCK) {
1831da177e4SLinus Torvalds 		/* real-time event */
1841da177e4SLinus Torvalds 		ev->type = status_event[ST_SPECIAL + c - 0xf0].event;
1851da177e4SLinus Torvalds 		ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
1861da177e4SLinus Torvalds 		ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
1870e75182cSClemens Ladisch 		return ev->type != SNDRV_SEQ_EVENT_NONE;
1881da177e4SLinus Torvalds 	}
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	spin_lock_irqsave(&dev->lock, flags);
191bf8c1382SClemens Ladisch 	if ((c & 0x80) &&
192bf8c1382SClemens Ladisch 	    (c != MIDI_CMD_COMMON_SYSEX_END || dev->type != ST_SYSEX)) {
193bf8c1382SClemens Ladisch 		/* new command */
194bf8c1382SClemens Ladisch 		dev->buf[0] = c;
195bf8c1382SClemens Ladisch 		if ((c & 0xf0) == 0xf0) /* system messages */
196bf8c1382SClemens Ladisch 			dev->type = (c & 0x0f) + ST_SPECIAL;
197bf8c1382SClemens Ladisch 		else
198bf8c1382SClemens Ladisch 			dev->type = (c >> 4) & 0x07;
199bf8c1382SClemens Ladisch 		dev->read = 1;
200bf8c1382SClemens Ladisch 		dev->qlen = status_event[dev->type].qlen;
201bf8c1382SClemens Ladisch 	} else {
2021da177e4SLinus Torvalds 		if (dev->qlen > 0) {
2031da177e4SLinus Torvalds 			/* rest of command */
2041da177e4SLinus Torvalds 			dev->buf[dev->read++] = c;
2051da177e4SLinus Torvalds 			if (dev->type != ST_SYSEX)
2061da177e4SLinus Torvalds 				dev->qlen--;
2071da177e4SLinus Torvalds 		} else {
208bf8c1382SClemens Ladisch 			/* running status */
209bf8c1382SClemens Ladisch 			dev->buf[1] = c;
2101da177e4SLinus Torvalds 			dev->qlen = status_event[dev->type].qlen - 1;
211bf8c1382SClemens Ladisch 			dev->read = 2;
2121da177e4SLinus Torvalds 		}
2131da177e4SLinus Torvalds 	}
2141da177e4SLinus Torvalds 	if (dev->qlen == 0) {
2151da177e4SLinus Torvalds 		ev->type = status_event[dev->type].event;
2161da177e4SLinus Torvalds 		ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
2171da177e4SLinus Torvalds 		ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
2181da177e4SLinus Torvalds 		if (status_event[dev->type].encode) /* set data values */
2191da177e4SLinus Torvalds 			status_event[dev->type].encode(dev, ev);
2200b664f72SClemens Ladisch 		if (dev->type >= ST_SPECIAL)
2210b664f72SClemens Ladisch 			dev->type = ST_INVALID;
222ef965ad5STakashi Iwai 		rc = true;
2231da177e4SLinus Torvalds 	} else 	if (dev->type == ST_SYSEX) {
2241da177e4SLinus Torvalds 		if (c == MIDI_CMD_COMMON_SYSEX_END ||
2251da177e4SLinus Torvalds 		    dev->read >= dev->bufsize) {
2261da177e4SLinus Torvalds 			ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
2271da177e4SLinus Torvalds 			ev->flags |= SNDRV_SEQ_EVENT_LENGTH_VARIABLE;
2281da177e4SLinus Torvalds 			ev->type = SNDRV_SEQ_EVENT_SYSEX;
2291da177e4SLinus Torvalds 			ev->data.ext.len = dev->read;
2301da177e4SLinus Torvalds 			ev->data.ext.ptr = dev->buf;
2311da177e4SLinus Torvalds 			if (c != MIDI_CMD_COMMON_SYSEX_END)
2321da177e4SLinus Torvalds 				dev->read = 0; /* continue to parse */
2331da177e4SLinus Torvalds 			else
2341da177e4SLinus Torvalds 				reset_encode(dev); /* all parsed */
235ef965ad5STakashi Iwai 			rc = true;
2361da177e4SLinus Torvalds 		}
2371da177e4SLinus Torvalds 	}
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds 	spin_unlock_irqrestore(&dev->lock, flags);
2401da177e4SLinus Torvalds 	return rc;
2411da177e4SLinus Torvalds }
2429c8ddd10STakashi Iwai EXPORT_SYMBOL(snd_midi_event_encode_byte);
2431da177e4SLinus Torvalds 
2441da177e4SLinus Torvalds /* encode note event */
note_event(struct snd_midi_event * dev,struct snd_seq_event * ev)245c7e0b5bfSTakashi Iwai static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
2461da177e4SLinus Torvalds {
2471da177e4SLinus Torvalds 	ev->data.note.channel = dev->buf[0] & 0x0f;
2481da177e4SLinus Torvalds 	ev->data.note.note = dev->buf[1];
2491da177e4SLinus Torvalds 	ev->data.note.velocity = dev->buf[2];
2501da177e4SLinus Torvalds }
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds /* encode one parameter controls */
one_param_ctrl_event(struct snd_midi_event * dev,struct snd_seq_event * ev)253c7e0b5bfSTakashi Iwai static void one_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
2541da177e4SLinus Torvalds {
2551da177e4SLinus Torvalds 	ev->data.control.channel = dev->buf[0] & 0x0f;
2561da177e4SLinus Torvalds 	ev->data.control.value = dev->buf[1];
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds /* encode pitch wheel change */
pitchbend_ctrl_event(struct snd_midi_event * dev,struct snd_seq_event * ev)260c7e0b5bfSTakashi Iwai static void pitchbend_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
2611da177e4SLinus Torvalds {
2621da177e4SLinus Torvalds 	ev->data.control.channel = dev->buf[0] & 0x0f;
2631da177e4SLinus Torvalds 	ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1] - 8192;
2641da177e4SLinus Torvalds }
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds /* encode midi control change */
two_param_ctrl_event(struct snd_midi_event * dev,struct snd_seq_event * ev)267c7e0b5bfSTakashi Iwai static void two_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
2681da177e4SLinus Torvalds {
2691da177e4SLinus Torvalds 	ev->data.control.channel = dev->buf[0] & 0x0f;
2701da177e4SLinus Torvalds 	ev->data.control.param = dev->buf[1];
2711da177e4SLinus Torvalds 	ev->data.control.value = dev->buf[2];
2721da177e4SLinus Torvalds }
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds /* encode one parameter value*/
one_param_event(struct snd_midi_event * dev,struct snd_seq_event * ev)275c7e0b5bfSTakashi Iwai static void one_param_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
2761da177e4SLinus Torvalds {
2771da177e4SLinus Torvalds 	ev->data.control.value = dev->buf[1];
2781da177e4SLinus Torvalds }
2791da177e4SLinus Torvalds 
2801da177e4SLinus Torvalds /* encode song position */
songpos_event(struct snd_midi_event * dev,struct snd_seq_event * ev)281c7e0b5bfSTakashi Iwai static void songpos_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
2821da177e4SLinus Torvalds {
2831da177e4SLinus Torvalds 	ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1];
2841da177e4SLinus Torvalds }
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds /*
2871da177e4SLinus Torvalds  * decode from a sequencer event to midi bytes
2881da177e4SLinus Torvalds  * return the size of decoded midi events
2891da177e4SLinus Torvalds  */
snd_midi_event_decode(struct snd_midi_event * dev,unsigned char * buf,long count,struct snd_seq_event * ev)290c7e0b5bfSTakashi Iwai long snd_midi_event_decode(struct snd_midi_event *dev, unsigned char *buf, long count,
291c7e0b5bfSTakashi Iwai 			   struct snd_seq_event *ev)
2921da177e4SLinus Torvalds {
2931da177e4SLinus Torvalds 	unsigned int cmd, type;
2941da177e4SLinus Torvalds 
2951da177e4SLinus Torvalds 	if (ev->type == SNDRV_SEQ_EVENT_NONE)
2961da177e4SLinus Torvalds 		return -ENOENT;
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds 	for (type = 0; type < ARRAY_SIZE(status_event); type++) {
2991da177e4SLinus Torvalds 		if (ev->type == status_event[type].event)
3001da177e4SLinus Torvalds 			goto __found;
3011da177e4SLinus Torvalds 	}
3021da177e4SLinus Torvalds 	for (type = 0; type < ARRAY_SIZE(extra_event); type++) {
3031da177e4SLinus Torvalds 		if (ev->type == extra_event[type].event)
3041da177e4SLinus Torvalds 			return extra_event[type].decode(dev, buf, count, ev);
3051da177e4SLinus Torvalds 	}
3061da177e4SLinus Torvalds 	return -ENOENT;
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds       __found:
3091da177e4SLinus Torvalds 	if (type >= ST_SPECIAL)
3101da177e4SLinus Torvalds 		cmd = 0xf0 + (type - ST_SPECIAL);
3111da177e4SLinus Torvalds 	else
3121da177e4SLinus Torvalds 		/* data.note.channel and data.control.channel is identical */
3131da177e4SLinus Torvalds 		cmd = 0x80 | (type << 4) | (ev->data.note.channel & 0x0f);
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 
3161da177e4SLinus Torvalds 	if (cmd == MIDI_CMD_COMMON_SYSEX) {
3171da177e4SLinus Torvalds 		snd_midi_event_reset_decode(dev);
3181da177e4SLinus Torvalds 		return snd_seq_expand_var_event(ev, count, buf, 1, 0);
3191da177e4SLinus Torvalds 	} else {
3201da177e4SLinus Torvalds 		int qlen;
3211da177e4SLinus Torvalds 		unsigned char xbuf[4];
3221da177e4SLinus Torvalds 		unsigned long flags;
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds 		spin_lock_irqsave(&dev->lock, flags);
3251da177e4SLinus Torvalds 		if ((cmd & 0xf0) == 0xf0 || dev->lastcmd != cmd || dev->nostat) {
3261da177e4SLinus Torvalds 			dev->lastcmd = cmd;
3271da177e4SLinus Torvalds 			spin_unlock_irqrestore(&dev->lock, flags);
3281da177e4SLinus Torvalds 			xbuf[0] = cmd;
3291da177e4SLinus Torvalds 			if (status_event[type].decode)
3301da177e4SLinus Torvalds 				status_event[type].decode(ev, xbuf + 1);
3311da177e4SLinus Torvalds 			qlen = status_event[type].qlen + 1;
3321da177e4SLinus Torvalds 		} else {
3331da177e4SLinus Torvalds 			spin_unlock_irqrestore(&dev->lock, flags);
3341da177e4SLinus Torvalds 			if (status_event[type].decode)
3351da177e4SLinus Torvalds 				status_event[type].decode(ev, xbuf + 0);
3361da177e4SLinus Torvalds 			qlen = status_event[type].qlen;
3371da177e4SLinus Torvalds 		}
3381da177e4SLinus Torvalds 		if (count < qlen)
3391da177e4SLinus Torvalds 			return -ENOMEM;
3401da177e4SLinus Torvalds 		memcpy(buf, xbuf, qlen);
3411da177e4SLinus Torvalds 		return qlen;
3421da177e4SLinus Torvalds 	}
3431da177e4SLinus Torvalds }
3449c8ddd10STakashi Iwai EXPORT_SYMBOL(snd_midi_event_decode);
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds /* decode note event */
note_decode(struct snd_seq_event * ev,unsigned char * buf)348c7e0b5bfSTakashi Iwai static void note_decode(struct snd_seq_event *ev, unsigned char *buf)
3491da177e4SLinus Torvalds {
3501da177e4SLinus Torvalds 	buf[0] = ev->data.note.note & 0x7f;
3511da177e4SLinus Torvalds 	buf[1] = ev->data.note.velocity & 0x7f;
3521da177e4SLinus Torvalds }
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds /* decode one parameter controls */
one_param_decode(struct snd_seq_event * ev,unsigned char * buf)355c7e0b5bfSTakashi Iwai static void one_param_decode(struct snd_seq_event *ev, unsigned char *buf)
3561da177e4SLinus Torvalds {
3571da177e4SLinus Torvalds 	buf[0] = ev->data.control.value & 0x7f;
3581da177e4SLinus Torvalds }
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds /* decode pitch wheel change */
pitchbend_decode(struct snd_seq_event * ev,unsigned char * buf)361c7e0b5bfSTakashi Iwai static void pitchbend_decode(struct snd_seq_event *ev, unsigned char *buf)
3621da177e4SLinus Torvalds {
3631da177e4SLinus Torvalds 	int value = ev->data.control.value + 8192;
3641da177e4SLinus Torvalds 	buf[0] = value & 0x7f;
3651da177e4SLinus Torvalds 	buf[1] = (value >> 7) & 0x7f;
3661da177e4SLinus Torvalds }
3671da177e4SLinus Torvalds 
3681da177e4SLinus Torvalds /* decode midi control change */
two_param_decode(struct snd_seq_event * ev,unsigned char * buf)369c7e0b5bfSTakashi Iwai static void two_param_decode(struct snd_seq_event *ev, unsigned char *buf)
3701da177e4SLinus Torvalds {
3711da177e4SLinus Torvalds 	buf[0] = ev->data.control.param & 0x7f;
3721da177e4SLinus Torvalds 	buf[1] = ev->data.control.value & 0x7f;
3731da177e4SLinus Torvalds }
3741da177e4SLinus Torvalds 
3751da177e4SLinus Torvalds /* decode song position */
songpos_decode(struct snd_seq_event * ev,unsigned char * buf)376c7e0b5bfSTakashi Iwai static void songpos_decode(struct snd_seq_event *ev, unsigned char *buf)
3771da177e4SLinus Torvalds {
3781da177e4SLinus Torvalds 	buf[0] = ev->data.control.value & 0x7f;
3791da177e4SLinus Torvalds 	buf[1] = (ev->data.control.value >> 7) & 0x7f;
3801da177e4SLinus Torvalds }
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds /* decode 14bit control */
extra_decode_ctrl14(struct snd_midi_event * dev,unsigned char * buf,int count,struct snd_seq_event * ev)383c7e0b5bfSTakashi Iwai static int extra_decode_ctrl14(struct snd_midi_event *dev, unsigned char *buf,
384c7e0b5bfSTakashi Iwai 			       int count, struct snd_seq_event *ev)
3851da177e4SLinus Torvalds {
3861da177e4SLinus Torvalds 	unsigned char cmd;
3871da177e4SLinus Torvalds 	int idx = 0;
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds 	cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
3901da177e4SLinus Torvalds 	if (ev->data.control.param < 0x20) {
3911da177e4SLinus Torvalds 		if (count < 4)
3921da177e4SLinus Torvalds 			return -ENOMEM;
3931da177e4SLinus Torvalds 		if (dev->nostat && count < 6)
3941da177e4SLinus Torvalds 			return -ENOMEM;
3951da177e4SLinus Torvalds 		if (cmd != dev->lastcmd || dev->nostat) {
3961da177e4SLinus Torvalds 			if (count < 5)
3971da177e4SLinus Torvalds 				return -ENOMEM;
3981da177e4SLinus Torvalds 			buf[idx++] = dev->lastcmd = cmd;
3991da177e4SLinus Torvalds 		}
4001da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.param;
4011da177e4SLinus Torvalds 		buf[idx++] = (ev->data.control.value >> 7) & 0x7f;
4021da177e4SLinus Torvalds 		if (dev->nostat)
4031da177e4SLinus Torvalds 			buf[idx++] = cmd;
4041da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.param + 0x20;
4051da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.value & 0x7f;
4061da177e4SLinus Torvalds 	} else {
4071da177e4SLinus Torvalds 		if (count < 2)
4081da177e4SLinus Torvalds 			return -ENOMEM;
4091da177e4SLinus Torvalds 		if (cmd != dev->lastcmd || dev->nostat) {
4101da177e4SLinus Torvalds 			if (count < 3)
4111da177e4SLinus Torvalds 				return -ENOMEM;
4121da177e4SLinus Torvalds 			buf[idx++] = dev->lastcmd = cmd;
4131da177e4SLinus Torvalds 		}
4141da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.param & 0x7f;
4151da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.value & 0x7f;
4161da177e4SLinus Torvalds 	}
4171da177e4SLinus Torvalds 	return idx;
4181da177e4SLinus Torvalds }
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds /* decode reg/nonreg param */
extra_decode_xrpn(struct snd_midi_event * dev,unsigned char * buf,int count,struct snd_seq_event * ev)421c7e0b5bfSTakashi Iwai static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf,
422c7e0b5bfSTakashi Iwai 			     int count, struct snd_seq_event *ev)
4231da177e4SLinus Torvalds {
4241da177e4SLinus Torvalds 	unsigned char cmd;
425731922a5STakashi Iwai 	const char *cbytes;
426731922a5STakashi Iwai 	static const char cbytes_nrpn[4] = { MIDI_CTL_NONREG_PARM_NUM_MSB,
4271da177e4SLinus Torvalds 				       MIDI_CTL_NONREG_PARM_NUM_LSB,
4281da177e4SLinus Torvalds 				       MIDI_CTL_MSB_DATA_ENTRY,
4291da177e4SLinus Torvalds 				       MIDI_CTL_LSB_DATA_ENTRY };
430731922a5STakashi Iwai 	static const char cbytes_rpn[4] =  { MIDI_CTL_REGIST_PARM_NUM_MSB,
4311da177e4SLinus Torvalds 				       MIDI_CTL_REGIST_PARM_NUM_LSB,
4321da177e4SLinus Torvalds 				       MIDI_CTL_MSB_DATA_ENTRY,
4331da177e4SLinus Torvalds 				       MIDI_CTL_LSB_DATA_ENTRY };
4341da177e4SLinus Torvalds 	unsigned char bytes[4];
4351da177e4SLinus Torvalds 	int idx = 0, i;
4361da177e4SLinus Torvalds 
4371da177e4SLinus Torvalds 	if (count < 8)
4381da177e4SLinus Torvalds 		return -ENOMEM;
4391da177e4SLinus Torvalds 	if (dev->nostat && count < 12)
4401da177e4SLinus Torvalds 		return -ENOMEM;
4411da177e4SLinus Torvalds 	cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
4426423f9eaSClemens Ladisch 	bytes[0] = (ev->data.control.param & 0x3f80) >> 7;
4436423f9eaSClemens Ladisch 	bytes[1] = ev->data.control.param & 0x007f;
4446423f9eaSClemens Ladisch 	bytes[2] = (ev->data.control.value & 0x3f80) >> 7;
4456423f9eaSClemens Ladisch 	bytes[3] = ev->data.control.value & 0x007f;
4461da177e4SLinus Torvalds 	if (cmd != dev->lastcmd && !dev->nostat) {
4471da177e4SLinus Torvalds 		if (count < 9)
4481da177e4SLinus Torvalds 			return -ENOMEM;
4491da177e4SLinus Torvalds 		buf[idx++] = dev->lastcmd = cmd;
4501da177e4SLinus Torvalds 	}
4511da177e4SLinus Torvalds 	cbytes = ev->type == SNDRV_SEQ_EVENT_NONREGPARAM ? cbytes_nrpn : cbytes_rpn;
4521da177e4SLinus Torvalds 	for (i = 0; i < 4; i++) {
4531da177e4SLinus Torvalds 		if (dev->nostat)
4541da177e4SLinus Torvalds 			buf[idx++] = dev->lastcmd = cmd;
4551da177e4SLinus Torvalds 		buf[idx++] = cbytes[i];
4561da177e4SLinus Torvalds 		buf[idx++] = bytes[i];
4571da177e4SLinus Torvalds 	}
4581da177e4SLinus Torvalds 	return idx;
4591da177e4SLinus Torvalds }
460