docs(steam): gadget PoC — interface 2 PROVEN (Steam opens + XInput-reserves it)

On the Deck (which ships dummy_hcd + raw_gadget + configfs f_hid), a pure-shell
configfs gadget stood up a real 3-interface USB Deck (kbd=0/mouse=1/controller=2,
28de:1205) on a dummy_hcd loopback UDC. hid-steam bound all 3 interfaces, and
crucially Steam PROMOTED the interface-2 controller: "Local Device Found ...
Interface: 2 ... Steam controller device opened for index 14 ... Steam Controller
reserving XInput slot 1" — exactly where the interface -1 UHID Deck was filtered.

It then failed only at feature-report exchange (f_hid can't serve HID GET_REPORT:
"steam_send_report: error -32", "couldn't get controller details ... zombie
controller"), and no gamepad evdev formed for the same reason. So interface 2 is
necessary AND sufficient for Steam to open+XInput-reserve the Deck; the remaining
piece is serving feature/output reports, which raw_gadget can (full control,
like UHID). Next: a raw_gadget 3-interface Deck emulator. Doc §11. Not pushed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-29 14:13:22 +00:00
parent c75f39fd8e
commit a81f1304cd
+26
View File
@@ -732,3 +732,29 @@ configfs) or a kernel USB bus driver — a much larger, less portable lift, and
1. A **live SDL/non-Steam game** on a Linux host actually consuming the virtual Deck's grips/trackpads
(the path that *does* work) — needs a real Deck/SC client + a Steam-Input-disabled consumer.
2. The **Moonlight paddle regression** from the M3 xpad-map change (stock paddle client → host).
### Gadget PoC — interface 2 is PROVEN on the Deck (2026-06-29)
SteamOS ships every primitive (`CONFIG_USB_DUMMY_HCD=m`, `CONFIG_USB_RAW_GADGET=m`,
`CONFIG_USB_CONFIGFS_F_HID=y`), so the gadget path is testable on the Deck itself with no
module-building. A pure-shell **configfs gadget** (`deck_gadget_up.sh`) stood up a real 3-interface
USB Deck on a `dummy_hcd` loopback UDC — keyboard = interface 0, mouse = 1, **controller = interface
2** (`STEAMDECK_RDESC`), `28DE:1205`. Result:
- It enumerates as a real USB device (`lsusb: 28de:1205 Valve Software Steam Deck Controller`) and
`hid-steam` binds **all three** interfaces — the controller on `bInterfaceNumber=02`.
- **Steam promoted it:** `Local Device Found … Interface: 2 … !! Steam controller device opened for
index 14 … Steam Controller reserving XInput slot 1`. *This is the proof: a device on interface 2
IS opened + XInput-reserved by Steam, where the interface-`-1` UHID device was filtered out.*
- It then failed at the next step — `f_hid` can't serve HID **feature reports** (`hid-steam:
steam_send_report: error -32 (ae 16 01)` → serial `XXXXXXXXXX`; Steam: `couldn't get controller
details … GetControllerInfo failed … Disconnecting zombie controller`). No gamepad evdev was
created either, for the same reason (hid-steam can't complete Deck init without the feature/output
channel).
**Conclusion: the wall is fully characterised and climbable.** Interface 2 is necessary *and*
sufficient for Steam to open + XInput-reserve the Deck; the only remaining piece is serving the
HID feature/output reports, which `f_hid` can't but **`raw_gadget` can** (userspace handles every
control transfer, exactly like the UHID path). Next: a `raw_gadget` userspace emulator of the
3-interface Deck (controller on interface 2) that answers the serial/attribute/settings feature
reports + streams the 64-byte state report — then re-test hid-steam gamepad evdev + Steam promotion.