Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1299459

[PATCH 1/4] usb: gadget: f_midi: refactor state machine

Path csiph.com!2.us.feeder.erje.net!feeder.erje.net!2.eu.feeder.erje.net!nntpspool01.opticnetworks.net!aioe.org!bofh.it!news.nic.it!robomod
From "Felipe F. Tonello" <eu@felipetonello.com>
Newsgroups linux.kernel
Subject [PATCH 1/4] usb: gadget: f_midi: refactor state machine
Date Wed, 30 Dec 2015 20:10:03 +0100
Message-ID <qLuif-2ad-41@gated-at.bofh.it> (permalink)
References <qLuie-2ad-3@gated-at.bofh.it>
Dkim-Signature v=1; a=rsa-sha256; c=relaxed/relaxed; d=felipetonello-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=f6vpkEGRwup0dSPK+ot/vLcwDUM+v01eA4FCSWzMPdQ=; b=SAAe/1NuL3XOe2q7xfqNwW1DWDyrCacfo8MjFNZM2z8kYr9U6ZO+gi1GQNw7sEatPj lDAncO12Ad0PsSJSA+xnB/LdYQePJ4oAAs8zgfWqd07AuCvUyg4atSAqcGTlv/By2Tvy CsLavhwYVBDoduCKavG5J4iOCNswYZ4fUPPtfoh3OLnlSym0r3g7XF1ZaQLuEcRvU/Xo tNdfHmhGkl1FwaLIRTNbOTwaHCnlv/maz3AoQEwcSv/1wCNRjT/xJ7tYfui8LKnz9bwe 1CHlWlNjOJz/5zC3VvuDaADneeHR6/It3jGEJcwtKXJG3CKbDv7a7YQhc1q6kVqskvrk nOCA==
X-Google-Dkim-Signature v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=f6vpkEGRwup0dSPK+ot/vLcwDUM+v01eA4FCSWzMPdQ=; b=S13vW11oIqtyKlNF3o41KEoiVqCdVtp2xF8csD/VttILLVFdMKubGZvyEtE/P7JXJG l5tHsh+595Zy1hEZoXocy/+fWt8y16ms+OlGnUX5rkPkGmMFszIrr6dqG/VIWNjJ+EiF P+/sdewaUOnTgBmPfu1kZoO1FG+LXIQQ2CZ1jLhCIe1LF9qzZgXdS8K8JD2Fn7hLFq/h twn2lQXpVfAItO8JoxWdB82b5UiVtT/qNcoEuV1yy/1u1HUET59QZAmriU5wVqeKtCIV 76gZLBGvl88PVs7+jaENWXet4qxmg+oTQdFy7WKetX3PDuzcula4FZh030toy+7kIo0y rEVg==
X-Gm-Message-State ALoCoQl8X4BmRxz0CQ39vIwP5slFcDuerxFlzPVU2v6drmkBcAoTgN9YRN4EzGpmXS00irg4CFBezb/4dLB9XV0l22wZgFvH6w==
X-Received by 10.28.211.141 with SMTP id k135mr41719018wmg.51.1451502467775; Wed, 30 Dec 2015 11:07:47 -0800 (PST)
X-Mailer git-send-email 2.6.4
Sender robomod@news.nic.it
List-ID <linux-kernel.vger.kernel.org>
X-Mailing-List linux-kernel@vger.kernel.org
Approved robomod@news.nic.it
Lines 297
Organization linux.* mail to news gateway
X-Original-Cc linux-kernel@vger.kernel.org, Felipe Balbi <balbi@ti.com>, Robert Baldyga <r.baldyga@samsung.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Clemens Ladisch <clemens@ladisch.de>
X-Original-Date Wed, 30 Dec 2015 19:07:52 +0000
X-Original-Message-ID <1451502475-22794-2-git-send-email-eu@felipetonello.com>
X-Original-References <1451502475-22794-1-git-send-email-eu@felipetonello.com>
X-Original-Sender linux-kernel-owner@vger.kernel.org
Xref csiph.com linux.kernel:1299459

Show key headers only | View raw


This refactor results in a cleaner state machine code and as a result fixed a
bug when packaging a MIDI-USB packet right after a non-conformant MIDI byte stream.

Signed-off-by: Felipe F. Tonello <eu@felipetonello.com>
---
 drivers/usb/gadget/function/f_midi.c | 204 ++++++++++++++++++++++-------------
 1 file changed, 129 insertions(+), 75 deletions(-)

diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index fb1fe96d3215..c4b47f68e553 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -50,6 +50,19 @@ static const char f_midi_longname[] = "MIDI Gadget";
  */
 #define MAX_PORTS 16
 
+/* MIDI message states */
+enum {
+	STATE_INITIAL = 0,	/* pseudo state */
+	STATE_1PARAM,
+	STATE_2PARAM_1,
+	STATE_2PARAM_2,
+	STATE_SYSEX_0,
+	STATE_SYSEX_1,
+	STATE_SYSEX_2,
+	STATE_REAL_TIME,
+	STATE_FINISHED,		/* pseudo state */
+};
+
 /*
  * This is a gadget, and the IN/OUT naming is from the host's perspective.
  * USB -> OUT endpoint -> rawmidi
@@ -60,13 +73,6 @@ struct gmidi_in_port {
 	int active;
 	uint8_t cable;
 	uint8_t state;
-#define STATE_UNKNOWN	0
-#define STATE_1PARAM	1
-#define STATE_2PARAM_1	2
-#define STATE_2PARAM_2	3
-#define STATE_SYSEX_0	4
-#define STATE_SYSEX_1	5
-#define STATE_SYSEX_2	6
 	uint8_t data[2];
 };
 
@@ -400,118 +406,166 @@ static int f_midi_snd_free(struct snd_device *device)
 	return 0;
 }
 
-static void f_midi_transmit_packet(struct usb_request *req, uint8_t p0,
-					uint8_t p1, uint8_t p2, uint8_t p3)
-{
-	unsigned length = req->length;
-	u8 *buf = (u8 *)req->buf + length;
-
-	buf[0] = p0;
-	buf[1] = p1;
-	buf[2] = p2;
-	buf[3] = p3;
-	req->length = length + 4;
-}
-
 /*
  * Converts MIDI commands to USB MIDI packets.
  */
 static void f_midi_transmit_byte(struct usb_request *req,
 				 struct gmidi_in_port *port, uint8_t b)
 {
-	uint8_t p0 = port->cable << 4;
+	uint8_t p[4] = { port->cable << 4, 0, 0, 0 };
+	uint8_t next_state = STATE_INITIAL;
+
+	switch (b) {
+	case 0xf8 ... 0xff:
+		/* System Real-Time Messages */
+		p[0] |= 0x0f;
+		p[1] = b;
+		next_state = port->state;
+		port->state = STATE_REAL_TIME;
+		break;
 
-	if (b >= 0xf8) {
-		f_midi_transmit_packet(req, p0 | 0x0f, b, 0, 0);
-	} else if (b >= 0xf0) {
+	case 0xf7:
+		/* End of SysEx */
+		switch (port->state) {
+		case STATE_SYSEX_0:
+			p[0] |= 0x05;
+			p[1] = 0xf7;
+			next_state = STATE_FINISHED;
+			break;
+		case STATE_SYSEX_1:
+			p[0] |= 0x06;
+			p[1] = port->data[0];
+			p[2] = 0xf7;
+			next_state = STATE_FINISHED;
+			break;
+		case STATE_SYSEX_2:
+			p[0] |= 0x07;
+			p[1] = port->data[0];
+			p[2] = port->data[1];
+			p[3] = 0xf7;
+			next_state = STATE_FINISHED;
+			break;
+		default:
+			/* Ignore byte */
+			next_state = port->state;
+			port->state = STATE_INITIAL;
+		}
+		break;
+
+	case 0xf0 ... 0xf6:
+		/* System Common Messages */
+		port->data[0] = port->data[1] = 0;
+		port->state = STATE_INITIAL;
 		switch (b) {
 		case 0xf0:
 			port->data[0] = b;
-			port->state = STATE_SYSEX_1;
+			port->data[1] = 0;
+			next_state = STATE_SYSEX_1;
 			break;
 		case 0xf1:
 		case 0xf3:
 			port->data[0] = b;
-			port->state = STATE_1PARAM;
+			next_state = STATE_1PARAM;
 			break;
 		case 0xf2:
 			port->data[0] = b;
-			port->state = STATE_2PARAM_1;
+			next_state = STATE_2PARAM_1;
 			break;
 		case 0xf4:
 		case 0xf5:
-			port->state = STATE_UNKNOWN;
+			next_state = STATE_INITIAL;
 			break;
 		case 0xf6:
-			f_midi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0);
-			port->state = STATE_UNKNOWN;
-			break;
-		case 0xf7:
-			switch (port->state) {
-			case STATE_SYSEX_0:
-				f_midi_transmit_packet(req,
-					p0 | 0x05, 0xf7, 0, 0);
-				break;
-			case STATE_SYSEX_1:
-				f_midi_transmit_packet(req,
-					p0 | 0x06, port->data[0], 0xf7, 0);
-				break;
-			case STATE_SYSEX_2:
-				f_midi_transmit_packet(req,
-					p0 | 0x07, port->data[0],
-					port->data[1], 0xf7);
-				break;
-			}
-			port->state = STATE_UNKNOWN;
+			p[0] |= 0x05;
+			p[1] = 0xf6;
+			next_state = STATE_FINISHED;
 			break;
 		}
-	} else if (b >= 0x80) {
+		break;
+
+	case 0x80 ... 0xef:
+		/*
+		 * Channel Voice Messages, Channel Mode Messages
+		 * and Control Change Messages.
+		 */
 		port->data[0] = b;
+		port->data[1] = 0;
+		port->state = STATE_INITIAL;
 		if (b >= 0xc0 && b <= 0xdf)
-			port->state = STATE_1PARAM;
+			next_state = STATE_1PARAM;
 		else
-			port->state = STATE_2PARAM_1;
-	} else { /* b < 0x80 */
+			next_state = STATE_2PARAM_1;
+		break;
+
+	case 0x00 ... 0x7f:
+		/* Message parameters */
 		switch (port->state) {
 		case STATE_1PARAM:
-			if (port->data[0] < 0xf0) {
-				p0 |= port->data[0] >> 4;
-			} else {
-				p0 |= 0x02;
-				port->state = STATE_UNKNOWN;
-			}
-			f_midi_transmit_packet(req, p0, port->data[0], b, 0);
+			if (port->data[0] < 0xf0)
+				p[0] |= port->data[0] >> 4;
+			else
+				p[0] |= 0x02;
+
+			p[1] = port->data[0];
+			p[2] = b;
+			/* This is to allow Running State Messages */
+			next_state = STATE_1PARAM;
 			break;
 		case STATE_2PARAM_1:
 			port->data[1] = b;
-			port->state = STATE_2PARAM_2;
+			next_state = STATE_2PARAM_2;
 			break;
 		case STATE_2PARAM_2:
-			if (port->data[0] < 0xf0) {
-				p0 |= port->data[0] >> 4;
-				port->state = STATE_2PARAM_1;
-			} else {
-				p0 |= 0x03;
-				port->state = STATE_UNKNOWN;
-			}
-			f_midi_transmit_packet(req,
-				p0, port->data[0], port->data[1], b);
+			if (port->data[0] < 0xf0)
+				p[0] |= port->data[0] >> 4;
+			else
+				p[0] |= 0x03;
+
+			p[1] = port->data[0];
+			p[2] = port->data[1];
+			p[3] = b;
+			/* This is to allow Running State Messages */
+			next_state = STATE_2PARAM_1;
 			break;
 		case STATE_SYSEX_0:
 			port->data[0] = b;
-			port->state = STATE_SYSEX_1;
+			next_state = STATE_SYSEX_1;
 			break;
 		case STATE_SYSEX_1:
 			port->data[1] = b;
-			port->state = STATE_SYSEX_2;
+			next_state = STATE_SYSEX_2;
 			break;
 		case STATE_SYSEX_2:
-			f_midi_transmit_packet(req,
-				p0 | 0x04, port->data[0], port->data[1], b);
-			port->state = STATE_SYSEX_0;
+			p[0] |= 0x04;
+			p[1] = port->data[0];
+			p[2] = port->data[1];
+			p[3] = b;
+			next_state = STATE_SYSEX_0;
 			break;
 		}
+		break;
 	}
+
+	/* States where we have to write into the USB request */
+	if (next_state == STATE_FINISHED ||
+	    port->state == STATE_SYSEX_2 ||
+	    port->state == STATE_1PARAM ||
+	    port->state == STATE_2PARAM_2 ||
+	    port->state == STATE_REAL_TIME) {
+
+		unsigned length = req->length;
+		u8 *buf = (u8 *)req->buf + length;
+
+		memcpy(buf, p, sizeof(p));
+		req->length = length + sizeof(p);
+
+		if (next_state == STATE_FINISHED) {
+			next_state = STATE_INITIAL;
+			port->data[0] = port->data[1] = 0;
+		}
+	}
+
+	port->state = next_state;
 }
 
 static void f_midi_drop_out_substreams(struct f_midi *midi)
@@ -632,7 +686,7 @@ static int f_midi_in_open(struct snd_rawmidi_substream *substream)
 
 	VDBG(midi, "%s()\n", __func__);
 	midi->in_substream[substream->number] = substream;
-	midi->in_port[substream->number]->state = STATE_UNKNOWN;
+	midi->in_port[substream->number]->state = STATE_INITIAL;
 	return 0;
 }
 
-- 
2.6.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Back to linux.kernel | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

[PATCH 0/4] More improvements on MIDI gadget function "Felipe F. Tonello" <eu@felipetonello.com> - 2015-12-30 20:10 +0100
  [PATCH 2/4] usb: gadget: f_midi: added spinlock on transmit function "Felipe F. Tonello" <eu@felipetonello.com> - 2015-12-30 20:10 +0100
  [PATCH 1/4] usb: gadget: f_midi: refactor state machine "Felipe F. Tonello" <eu@felipetonello.com> - 2015-12-30 20:10 +0100
  [PATCH 3/4] usb: gadget: f_midi: remove useless midi reference from port struct "Felipe F. Tonello" <eu@felipetonello.com> - 2015-12-30 20:10 +0100
  [PATCH 4/4] usb: gadget: f_midi: add mutex_unlock under setup_fail label "Felipe F. Tonello" <eu@felipetonello.com> - 2015-12-30 20:10 +0100

csiph-web