feat(gamepad): classic Steam Controller backend — Linux UHID via hid-steam (N3)

The reserved GamepadPref::SteamController = 5 slot goes live: the same
hid-steam driver under the wired-SC identity (28DE:1102,
ID_CONTROLLER_STATE), UHID-only in v1 (no captured SC USB interface
layout, so no Steam-Input promotion — the pre-usbip Deck state;
acceptable for discontinued hardware).

Layout pinned against the kernel's ID_CONTROLLER_STATE table: 24-bit
buttons at 8..11 (low bits shared with the Deck; grips at 9.7/10.0 =
the Deck's L5/R5 positions; right-pad click 10.2; joystick click 10.6),
u8 triggers at 11/12, the joystick/left-pad MULTIPLEX at 16..20 (a
left-pad contact shadows the stick, like real hardware's lpad_touched
flag), right pad at 20..24. Mapping: wire left stick -> SC stick; wire
right stick -> right-pad coords + touched bit (the SC's camera surface —
the second-stick loss is inherent); PADDLE1/2 -> the two grips (natively,
masked out of the fold input); PADDLE3/4 + MISC1 -> the remap policy.
The SC parser has NO gamepad_mode gate, so no mode-entry pulse.

SteamDeckPad grew a SteamModel (open_model); ScProto/SteamCtrlManager;
pick_gamepad flips SteamController -> itself on Linux (replacing the
Xbox360 fold); SDL picker splits Valve PIDs (Deck 1205 stays SteamDeck,
SC 1102/1142 now declare SteamController).

Verified: .21 clippy -D warnings + 304/0 tests + on-box UHID smoke
(hid-steam binds 1102, BTN_A + right-pad ABS_RX land on evdev, no mode
pulse); .133 clippy -D warnings green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 11:15:54 +02:00
parent 70a74b0d7c
commit 8c854e0a19
6 changed files with 417 additions and 25 deletions
+7 -3
View File
@@ -268,6 +268,7 @@ impl PadInfo {
GamepadPref::DualShock4 => "DualShock 4",
GamepadPref::XboxOne => "Xbox One",
GamepadPref::SteamDeck => "Steam Deck",
GamepadPref::SteamController => "Steam Controller",
GamepadPref::SwitchPro => "Switch Pro",
_ => "",
}
@@ -783,11 +784,14 @@ impl Worker {
self.subsystem.product_for_id(jid).unwrap_or(0),
);
// There is no SDL gamepad type for the Steam Deck / Steam Controller, so detect Valve by
// VID/PID (Deck 0x1205, SC wired 0x1102, SC dongle 0x1142) — the host then builds the virtual
// hid-steam pad with the back grips + dual trackpads and the right glyph identity.
if vid == 0x28DE && matches!(pid, 0x1205 | 0x1102 | 0x1142) {
// VID/PID — the host then builds the matching virtual hid-steam pad (grips + trackpads +
// the right glyph identity): Deck 0x1205; classic SC wired 0x1102 / dongle 0x1142.
if vid == 0x28DE && pid == 0x1205 {
pref = GamepadPref::SteamDeck;
}
if vid == 0x28DE && matches!(pid, 0x1102 | 0x1142) {
pref = GamepadPref::SteamController;
}
// The DualSense Edge has no distinct SDL gamepad type either (it reports PS5) — detect by
// VID/PID so the host builds the virtual Edge and this pad's back paddles land on native
// slots instead of the fold/drop policy.