feat(host/steam): harden the gadget feature contract — fixes the evdev churn
The virtual Deck's gamepad evdev was churning (destroyed + recreated) because Steam kept re-probing: GetControllerInfo reads HID feature reports, and the gadget served zeros for them. Captured the real contract off a physical Deck (packaging/linux/steam-deck-gadget/get_deck_attrs.c, hidraw HIDIOCGFEATURE — usbmon truncates to 32B) and implemented it in steam_gadget.rs::feature_reply: - 0x83 GET_ATTRIBUTES_VALUES: [83, 2d, 9×(attr-id, u32-LE)] — product id 0x1205, a per-instance unit serial (0x0a/0x04, so a gadget never collides with a real Deck or another gadget), and the capability attrs (0x09=0x2e, 0x0b=0x0fa0, rest 0). - 0xAE GET_STRING_ATTRIBUTE: [ae, len, attr, ascii] — serial (attr 1) / board serial (attr 0). - other commands (0x87 settings): echo the last write. Validated on the Deck: 1 connect / 0 disconnect / 1 gamepad evdev (was constant churn), Steam activates the gadget cleanly (no GetControllerInfo failed, no zombie) and emits its X-Box 360 pad. usbmon on the gadget's bus confirms our state reports (pressed button at byte 8) are delivered on the interrupt-IN and consumed by hid-steam — so with M1/M2's byte-8→BTN_SOUTH decode the input chain is proven end-to-end. Remaining: a foreground-game confirmation of Steam Input's XInput mapping, then default the gadget on for SteamOS. Workspace clippy/fmt/test green. Not pushed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -807,3 +807,18 @@ With the A button held in the streamed report on a `pressa` build, on the Deck:
|
||||
Conclusion: input delivery + format are proven; the only gap is the gamepad-evdev transience, which is
|
||||
a **feature-report-completeness** problem — exactly what the host backend fixes (serve the full Deck
|
||||
feature/attribute contract so Steam stops fighting it). That's the next step, not more PoC patching.
|
||||
|
||||
### Feature contract hardened — the churn is fixed (2026-06-29)
|
||||
|
||||
The gamepad-evdev churn was Steam re-probing because the gadget served zeros for the HID feature
|
||||
reports Steam's `GetControllerInfo` reads. The real contract was captured from a physical Deck
|
||||
(`packaging/linux/steam-deck-gadget/get_deck_attrs.c`, hidraw `HIDIOCGFEATURE`) and implemented in
|
||||
`steam_gadget.rs::feature_reply`: the **`0x83` GET_ATTRIBUTES_VALUES** blob (`[83,2d, 9×(id,u32-LE)]`
|
||||
— product id `0x1205`, a per-instance unit serial, capability attrs) plus the **`0xAE`** string
|
||||
attributes (serial / board serial) and a settings echo. Result on the Deck: **1 connect / 0
|
||||
disconnect / 1 gamepad evdev** (was constant churn), Steam *activates* the gadget cleanly (no
|
||||
`GetControllerInfo failed`, no zombie) and emits its **X-Box 360 pad 1**. usbmon on the gadget's bus
|
||||
confirms our state reports (pressed button at byte 8) are delivered on the interrupt-IN and consumed
|
||||
by hid-steam — so with M1/M2's byte-8→BTN_SOUTH decode, the input chain is proven end-to-end. The
|
||||
only piece left is a foreground-game confirmation that Steam Input maps it onto the X-Box pad (Steam
|
||||
only maps contextually), after which the gadget can default on for SteamOS hosts.
|
||||
|
||||
Reference in New Issue
Block a user