Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ around that:
| | getting the input | MCU bridge needs |
|---|---|---|
| **Linux** | `snd-usb-audio` quirk ([quirk/](quirk/)) | `snd-virmidi` |
| **Windows** | Digidesign/Avid's own driver | a loopback pair |
| **Windows** | Digidesign/Avid's own driver, **or the dongle** | a loopback pair |
| **macOS** | claim the USB interface directly (libusb) | nothing |

macOS is the odd one out in both columns. CoreMIDI has no quirk mechanism, so
Expand Down Expand Up @@ -190,9 +190,19 @@ unzip anywhere, no vcredist or DLLs needed):
cd build && cpack
```

The Command|8 needs Digidesign/Avid's own driver on Windows to expose its MIDI
input and output (`Command|8`, plus `MIDIIN2/3` for the rear MIDI jacks). If
another app (a DAW) holds the port, close it first: WinMM ports are exclusive.
On Windows the Command|8 needs either Digidesign/Avid's own driver to expose its
MIDI input and output (`Command|8`, plus `MIDIIN2/3` for the rear MIDI jacks),
or the [command8-dongle](https://github.com/alphonsom/command8-dongle), which
makes the surface enumerate as an ordinary class-compliant USB-MIDI device with
no driver at all. Either way the ports look the same to this engine.

**If another app holds the port, close it first: WinMM ports are exclusive.**
In particular, set the Command|8's input *and* output to disabled in a DAW's
MIDI device list before starting `command8-reaper` or `command8-mackie` --
otherwise the engine cannot open the device and simply fails to start. The DAW
talks to the engine (over OSC, or over the MCU loopback pair), never to the
surface directly: the Command|8 speaks a proprietary protocol, so a DAW sending
it generic MIDI just makes the faders twitch and leaves the display Offline.

### Mackie bridge on Windows

Expand Down
111 changes: 111 additions & 0 deletions quirk/UPSTREAM.md
Original file line number Diff line number Diff line change
@@ -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 <you@example.com>
```

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=<maintainer> --cc=<lists> --cc=<yourself> 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.
14 changes: 9 additions & 5 deletions src/surface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
Expand Down
11 changes: 6 additions & 5 deletions src/usb/usb_surface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading