stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Patch "ALSA: usb-audio: work around CH345 input SysEx corruption" has been added to the 3.10-stable tree
@ 2015-12-07  8:43 gregkh
  0 siblings, 0 replies; only message in thread
From: gregkh @ 2015-12-07  8:43 UTC (permalink / raw)
  To: clemens, gregkh, tiwai; +Cc: stable, stable-commits


This is a note to let you know that I've just added the patch titled

    ALSA: usb-audio: work around CH345 input SysEx corruption

to the 3.10-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     alsa-usb-audio-work-around-ch345-input-sysex-corruption.patch
and it can be found in the queue-3.10 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@vger.kernel.org> know about it.


>From a91e627e3f0ed820b11d86cdc04df38f65f33a70 Mon Sep 17 00:00:00 2001
From: Clemens Ladisch <clemens@ladisch.de>
Date: Sun, 15 Nov 2015 22:39:08 +0100
Subject: ALSA: usb-audio: work around CH345 input SysEx corruption

From: Clemens Ladisch <clemens@ladisch.de>

commit a91e627e3f0ed820b11d86cdc04df38f65f33a70 upstream.

One of the many faults of the QinHeng CH345 USB MIDI interface chip is
that it does not handle received SysEx messages correctly -- every second
event packet has a wrong code index number, which is the one from the last
seen message, instead of 4.  For example, the two messages "FE F0 01 02 03
04 05 06 07 08 09 0A 0B 0C 0D 0E F7" result in the following event
packets:

correct:       CH345:
0F FE 00 00    0F FE 00 00
04 F0 01 02    04 F0 01 02
04 03 04 05    0F 03 04 05
04 06 07 08    04 06 07 08
04 09 0A 0B    0F 09 0A 0B
04 0C 0D 0E    04 0C 0D 0E
05 F7 00 00    05 F7 00 00

A class-compliant driver must interpret an event packet with CIN 15 as
having a single data byte, so the other two bytes would be ignored.  The
message received by the host would then be missing two bytes out of six;
in this example, "F0 01 02 03 06 07 08 09 0C 0D 0E F7".

These corrupted SysEx event packages contain only data bytes, while the
CH345 uses event packets with a correct CIN value only for messages with
a status byte, so it is possible to distinguish between these two cases by
checking for the presence of this status byte.

(Other bugs in the CH345's input handling, such as the corruption resulting
from running status, cannot be worked around.)

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

---
 sound/usb/midi.c |   42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -174,6 +174,8 @@ struct snd_usb_midi_in_endpoint {
 		u8 running_status_length;
 	} ports[0x10];
 	u8 seen_f5;
+	bool in_sysex;
+	u8 last_cin;
 	u8 error_resubmit;
 	int current_port;
 };
@@ -465,6 +467,39 @@ static void snd_usbmidi_maudio_broken_ru
 }
 
 /*
+ * QinHeng CH345 is buggy: every second packet inside a SysEx has not CIN 4
+ * but the previously seen CIN, but still with three data bytes.
+ */
+static void ch345_broken_sysex_input(struct snd_usb_midi_in_endpoint *ep,
+				     uint8_t *buffer, int buffer_length)
+{
+	unsigned int i, cin, length;
+
+	for (i = 0; i + 3 < buffer_length; i += 4) {
+		if (buffer[i] == 0 && i > 0)
+			break;
+		cin = buffer[i] & 0x0f;
+		if (ep->in_sysex &&
+		    cin == ep->last_cin &&
+		    (buffer[i + 1 + (cin == 0x6)] & 0x80) == 0)
+			cin = 0x4;
+#if 0
+		if (buffer[i + 1] == 0x90) {
+			/*
+			 * Either a corrupted running status or a real note-on
+			 * message; impossible to detect reliably.
+			 */
+		}
+#endif
+		length = snd_usbmidi_cin_length[cin];
+		snd_usbmidi_input_data(ep, 0, &buffer[i + 1], length);
+		ep->in_sysex = cin == 0x4;
+		if (!ep->in_sysex)
+			ep->last_cin = cin;
+	}
+}
+
+/*
  * CME protocol: like the standard protocol, but SysEx commands are sent as a
  * single USB packet preceded by a 0x0F byte.
  */
@@ -650,6 +685,12 @@ static struct usb_protocol_ops snd_usbmi
 	.output_packet = snd_usbmidi_output_standard_packet,
 };
 
+static struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = {
+	.input = ch345_broken_sysex_input,
+	.output = snd_usbmidi_standard_output,
+	.output_packet = snd_usbmidi_output_standard_packet,
+};
+
 /*
  * AKAI MPD16 protocol:
  *
@@ -2218,6 +2259,7 @@ int snd_usbmidi_create(struct snd_card *
 		err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
 		break;
 	case QUIRK_MIDI_CH345:
+		umidi->usb_protocol_ops = &snd_usbmidi_ch345_broken_sysex_ops;
 		err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
 		break;
 	default:


Patches currently in stable-queue which might be from clemens@ladisch.de are

queue-3.10/alsa-usb-audio-work-around-ch345-input-sysex-corruption.patch
queue-3.10/alsa-usb-audio-prevent-ch345-multiport-output-sysex-corruption.patch
queue-3.10/alsa-usb-audio-add-packet-size-quirk-for-the-medeli-dd305.patch

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2015-12-07 12:23 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-12-07  8:43 Patch "ALSA: usb-audio: work around CH345 input SysEx corruption" has been added to the 3.10-stable tree gregkh

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).