| From 1ca8b201309d842642f221db7f02f71c0af5be2d Mon Sep 17 00:00:00 2001 |
| From: Clemens Ladisch <clemens@ladisch.de> |
| Date: Sun, 15 Nov 2015 22:38:29 +0100 |
| Subject: ALSA: usb-audio: prevent CH345 multiport output SysEx corruption |
| |
| commit 1ca8b201309d842642f221db7f02f71c0af5be2d upstream. |
| |
| The CH345 USB MIDI chip has two output ports. However, they are |
| multiplexed through one pin, and the number of ports cannot be reduced |
| even for hardware that implements only one connector, so for those |
| devices, data sent to either port ends up on the same hardware output. |
| This becomes a problem when both ports are used at the same time, as |
| longer MIDI commands (such as SysEx messages) are likely to be |
| interrupted by messages from the other port, and thus to get lost. |
| |
| It would not be possible for the driver to detect how many ports the |
| device actually has, except that in practice, _all_ devices built with |
| the CH345 have only one port. So we can just ignore the device's |
| descriptors, and hardcode one output port. |
| |
| Signed-off-by: Clemens Ladisch <clemens@ladisch.de> |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Zefan Li <lizefan@huawei.com> |
| --- |
| sound/usb/midi.c | 3 +++ |
| sound/usb/quirks-table.h | 11 +++++++++++ |
| sound/usb/quirks.c | 1 + |
| sound/usb/usbaudio.h | 1 + |
| 4 files changed, 16 insertions(+) |
| |
| --- a/sound/usb/midi.c |
| +++ b/sound/usb/midi.c |
| @@ -2215,6 +2215,9 @@ int snd_usbmidi_create(struct snd_card * |
| |
| err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); |
| break; |
| + case QUIRK_MIDI_CH345: |
| + err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); |
| + break; |
| default: |
| snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); |
| err = -ENXIO; |
| --- a/sound/usb/quirks-table.h |
| +++ b/sound/usb/quirks-table.h |
| @@ -2689,6 +2689,17 @@ YAMAHA_DEVICE(0x7010, "UB99"), |
| .idProduct = 0x1020, |
| }, |
| |
| +/* QinHeng devices */ |
| +{ |
| + USB_DEVICE(0x1a86, 0x752d), |
| + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { |
| + .vendor_name = "QinHeng", |
| + .product_name = "CH345", |
| + .ifnum = 1, |
| + .type = QUIRK_MIDI_CH345 |
| + } |
| +}, |
| + |
| /* KeithMcMillen Stringport */ |
| { |
| USB_DEVICE(0x1f38, 0x0001), |
| --- a/sound/usb/quirks.c |
| +++ b/sound/usb/quirks.c |
| @@ -311,6 +311,7 @@ int snd_usb_create_quirk(struct snd_usb_ |
| [QUIRK_MIDI_CME] = create_any_midi_quirk, |
| [QUIRK_MIDI_AKAI] = create_any_midi_quirk, |
| [QUIRK_MIDI_FTDI] = create_any_midi_quirk, |
| + [QUIRK_MIDI_CH345] = create_any_midi_quirk, |
| [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, |
| [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, |
| [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, |
| --- a/sound/usb/usbaudio.h |
| +++ b/sound/usb/usbaudio.h |
| @@ -81,6 +81,7 @@ enum quirk_type { |
| QUIRK_MIDI_AKAI, |
| QUIRK_MIDI_US122L, |
| QUIRK_MIDI_FTDI, |
| + QUIRK_MIDI_CH345, |
| QUIRK_AUDIO_STANDARD_INTERFACE, |
| QUIRK_AUDIO_FIXED_ENDPOINT, |
| QUIRK_AUDIO_EDIROL_UAXX, |