From cbbe1a034e0e4d296bfce235ff2fd34a767931a5 Mon Sep 17 00:00:00 2001 From: alphonsom Date: Sun, 9 Aug 2026 14:42:25 +0100 Subject: [PATCH 1/2] usb: correct the per-platform driver-binding comments Tested with the Command|8 connected directly and snd-usb-audio actually loaded, which had not been true before. The module binds BOTH interfaces and creates a card; the three ports it exposes are output-only: 1-2:1.0 driver=snd-usb-audio 1-2:1.1 driver=snd-usb-audio 2 [Command8]: USB-Audio - Command8 O hw:2,0,0 Command8 MIDI 1 O hw:2,0,1 Command8 MIDI 2 O hw:2,0,2 Command8 MIDI 3 That is exactly what quirk/ has always said: the parser creates no input port. The merge commit dd45b0c..3727597 claimed instead that snd-usb-audio binds neither interface and that nothing claims the device on any platform. That was measured on a machine where the module was simply not loaded, and is wrong. Its message cannot be corrected without rewriting pushed history, so the correction lives here and in the comments the code actually carries. The practical consequence is that libusb_set_auto_detach_kernel_driver is doing real work on Linux rather than being the no-op the old comment described. Now verified end to end: UsbSurface opens with snd-usb-audio bound, and the kernel driver is reattached when the interface is released. macOS and Windows are unchanged -- they reject the MIDIStreaming interface outright and expose nothing, so there is nothing to detach there. That is still what removes the biggest risk from the macOS plan, just for a narrower reason than previously stated. Co-Authored-By: Claude Opus 5 --- src/surface.hpp | 14 +++++++++----- src/usb/usb_surface.cpp | 11 ++++++----- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/surface.hpp b/src/surface.hpp index 47b6402..15ec21b 100644 --- a/src/surface.hpp +++ b/src/surface.hpp @@ -21,11 +21,15 @@ namespace command8 { // "Command|8" (the later ports show up as "MIDIIN2/3 (Command|8)"); the bar // also keeps it from matching the "Command8 MCU" loopback endpoints. // The value is unused wherever UsbSurface is the backend, which is everywhere -// libusb is available: it matches on VID/PID instead. No class driver on any -// platform successfully claims the MIDIStreaming interface -- on a stock Linux -// kernel snd-usb-audio binds neither interface, and the macOS and Windows class -// drivers reject it outright -- so there is no port to name and nothing to -// detach. On macOS there is no alternative backend at all. +// libusb is available: it matches on VID/PID instead. +// +// Platforms differ in how they fail. On Linux snd-usb-audio does bind both +// interfaces and creates a card, but only output ports -- "Command8 MIDI 1..3" +// all show direction O, with no input -- which is what the quirk exists to fix +// and what UsbSurface sidesteps. It therefore has to detach the kernel driver, +// which libusb_set_auto_detach_kernel_driver handles (verified: it reattaches +// on release). macOS and Windows reject the MIDIStreaming interface outright +// and expose nothing at all; on macOS there is no alternative backend. #if defined(_WIN32) inline constexpr const char* kDefaultPortMatch = "Command|8"; #elif defined(__APPLE__) diff --git a/src/usb/usb_surface.cpp b/src/usb/usb_surface.cpp index 7189da0..b401b19 100644 --- a/src/usb/usb_surface.cpp +++ b/src/usb/usb_surface.cpp @@ -158,11 +158,12 @@ bool UsbSurface::open(const std::string& port_match) { return false; } - // Belt and braces. In practice no class driver claims this interface on any - // platform -- a stock Linux kernel binds neither interface because the - // descriptors fail to parse -- so there is normally nothing to detach. This - // covers the case where the quirk-patched snd-usb-audio did bind it, and is - // a no-op (NOT_SUPPORTED) on macOS and Windows. + // Required on Linux, where snd-usb-audio does claim this interface -- with + // or without the quirk. It creates output-only ports from the malformed + // descriptors, so the interface is genuinely taken and must be detached; + // libusb reattaches the kernel driver when we release it. A no-op + // (NOT_SUPPORTED) on macOS and Windows, where no class driver accepts the + // device at all. libusb_set_auto_detach_kernel_driver(dev_, 1); const int r = libusb_claim_interface(dev_, C8_USB_INTERFACE); From 8cfa138e320ac0853b4ce382a19a8adb8b6ff969 Mon Sep 17 00:00:00 2001 From: alphonsom Date: Sun, 9 Aug 2026 14:54:34 +0100 Subject: [PATCH 2/2] quirk: document how to send the patch upstream The patch here is a plain diff; the kernel wants a git commit with a Signed-off-by, based on tiwai/sound.git for-next, sent inline by git send-email. Write that procedure down rather than rediscovering it. Includes a ready-to-use commit message built from what we measured: the amidi -l output showing output-only ports, the corrected diagnosis (bNumEmbMIDIJack claims three jacks where two exist, so the count is the field in error rather than bLength), and the wTotalLength inconsistency. It also pre-empts the one question a reviewer will reasonably ask -- why three in-cables when only two Embedded MIDI OUT jacks are declared. The answer is that the descriptors are internally inconsistent and contradict observed behaviour, so they are not a usable basis for anything, which is what justifies the fixed-endpoint quirk over a narrower fix. Co-Authored-By: Claude Opus 5 --- quirk/UPSTREAM.md | 111 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 quirk/UPSTREAM.md diff --git a/quirk/UPSTREAM.md b/quirk/UPSTREAM.md new file mode 100644 index 0000000..833ba19 --- /dev/null +++ b/quirk/UPSTREAM.md @@ -0,0 +1,111 @@ +# Sending the Command|8 quirk upstream + +The patch in this directory is a plain diff. The kernel wants a git commit with +a Signed-off-by, sent inline as email. This is the whole procedure. + +## 1. Get the right tree + +Sound patches go through Takashi Iwai's tree, not mainline directly: + +```sh +git clone https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git +cd sound +git checkout for-next +``` + +`for-next` is the branch new material is based on. Basing on `master` invites a +"please rebase" reply. + +## 2. Apply the change and commit + +```sh +patch -p1 < /path/to/0001-ALSA-usb-audio-add-Digidesign-Command8-MIDI-quirk.patch +git add sound/usb/quirks-table.h +git commit -s # -s adds Signed-off-by from your git identity +``` + +`Signed-off-by` is a legal statement (the Developer's Certificate of Origin), so +`user.name` must be your real name — a handle will be rejected. + +Suggested commit message, using what we actually measured: + +``` +ALSA: usb-audio: Add quirk for Digidesign Command|8 + +The Digidesign Command|8 control surface (0dba:8000) exposes a +MIDIStreaming interface whose class-specific bulk-IN endpoint descriptor +declares bNumEmbMIDIJack 3 but carries only two jack IDs. bLength 6 is +correct for the two that are present, so the count is the field in error, +not the length. The interface also declares only two Embedded MIDI OUT +jacks, and the MS header's wTotalLength (98) disagrees with the +descriptors actually present (82). + +As a result snd-usb-audio binds the device and creates a card, but only +output ports: + + $ amidi -l + Dir Device Name + O hw:2,0,0 Command8 MIDI 1 + O hw:2,0,1 Command8 MIDI 2 + O hw:2,0,2 Command8 MIDI 3 + +With no input port the surface's faders, encoders and buttons are +unreadable, which makes the device useless as a control surface. + +The declared jack topology does not describe the hardware either: both +Embedded MIDI OUT jacks are sourced from external (DIN) input jacks, yet +the surface's own data is observed arriving on cable 0. In practice the +device presents three inputs (the surface plus two DIN) and three +outputs. Rather than trying to repair individual fields, ignore the +descriptors and force fixed endpoints with 3 in and 3 out cables on the +MIDIStreaming interface; the bulk endpoints 0x01/0x81 are auto-detected. + +Tested on a Command|8 with firmware 02.01.02. + +Signed-off-by: Your Name +``` + +Adjust the firmware version if `tools/probe_command8.sh` reports a different +one, and drop the "Tested on" line only if it is not true. + +## 3. Check it before sending + +```sh +./scripts/checkpatch.pl --strict -g HEAD +``` + +Fix anything it reports. Warnings about long lines in quoted output are usually +tolerated, but style errors in the code are not. + +## 4. Find the recipients + +Do not guess the addresses — ask the tree: + +```sh +git format-patch -1 +./scripts/get_maintainer.pl 0001-*.patch +``` + +That will list Takashi Iwai (sound maintainer), the sound mailing list and +`linux-kernel@vger.kernel.org`. Send to the maintainers, CC the lists. + +## 5. Send it + +```sh +git send-email --to= --cc= --cc= 0001-*.patch +``` + +It must be plain-text and inline. Attachments and HTML mail are silently +dropped by the lists. If `git send-email` is not configured, `b4 send` is the +modern alternative and handles most of the setup for you. + +## What to expect + +Quirk-table additions are routine and usually applied quickly. The one question +a reviewer may reasonably ask is why 3 in-cables when only two Embedded MIDI OUT +jacks are declared. The answer is in the commit message and the code comment: +the descriptors are internally inconsistent and contradict observed behaviour, +so they are not a usable basis for anything — hence the fixed-endpoint quirk. + +Reply in-thread, plain text, no top-posting. If asked for changes, send a v2 +with a `---`-delimited changelog below the commit message.