The virtual Steam Controller 2's hidraw node was root-only, so Steam never saw it #260

Merged
enricobuehler merged 1 commits from worktree-sc2-hidraw-udev into main 2026-08-15 22:52:44 +00:00
Owner

Field report (2026-08-15, Nobara host, game mode): the Android client captures a wired SC2 and says so — "Steam Controller 2 · Wired (USB) · Captured — streams as-is" — the host attaches the virtual pad over usbip cleanly, and Steam's Settings → Controller → Connected Controllers is empty. Buttons do nothing in games.

The log names the culprit by what is missing from it

Every kernel control transfer is present: device/config/string descriptors, SET_CONFIGURATION, SET_IDLE, and a GET of the 372-byte report descriptor. There is not one SET_REPORT and not one answering feature GET. The kernel enumerated the controller; Steam never opened it.

60-punktfunk.rules grants hidraw access per product id, and it lists what the host used to mint — the Sony pads, the Switch Pro, the Deck (28DE:1205) and the classic Steam Controller (28DE:1102). The two identities steam_backend_product mints for the SC2, wired 28DE:1302 and Puck 28DE:1304, were never added, so their nodes stayed root-only while the host runs as a user service.

The reporter's punktfunk group and vhci_hcd were both already fine — his log's attached via usbip … vhci_port=0 proves the attach step works. This is one step later, which is why every existing check passes and the pad still does nothing.

Why this one is fatal rather than degrading

For any other pad a missing hidraw rule costs rich feedback. For the SC2 it costs the controller:

  • No kernel driver claims the PID — mainline hid-steam stops at the Deck.
  • Its state reports ride a vendor collection, so there is no evdev node either.

Steam is the only consumer that exists, and a hidraw node Steam cannot open is not a degraded controller, it is no controller.

Leaning on the distro's steam-devices rules doesn't save it: those lists are per-PID and the SC2 shipped in 2026, so a host whose copy predates it grants nothing.

The change

Both identities added in the same two forms the Deck already uses — KERNELS for the UHID shape, ATTRS for the usbip/gadget one. Single source of truth: every distro installs this one file (the NixOS module takes it from the package via services.udev.packages), so no per-packaging change is needed.

Plus a troubleshooting section for the symptom, since users on an already-released host need the fix by hand: the drop-in rule, the one-line-plus-one-absence log signature that confirms the diagnosis, a pointer to the existing virtual-Deck section for the checks that come before this one, and a note that the trackpads needing Steam to act as a mouse is lizard mode being off on purpose rather than a fault.

Verification

Rules-only change, no code. The added lines mirror the existing Deck/Steam-Controller entries exactly in form and ordering.

Owed: on-glass confirmation — the reporter applying the equivalent /etc/udev/rules.d/61-punktfunk-sc2.rules, reconnecting, and Steam then listing the pad. Worth noting his distro may have covered this via a generic 28de rule in a newer steam-devices, in which case the empty list has a second cause; the log signature above distinguishes them.

Not addressed here, and tracked separately: the client's own input test shows nothing for a captured SC2 (isPad(event.device) rejects the capture's device-less synthesized events, and its sticks never synthesize MotionEvents at all). That will keep looking broken in the app even once Steam picks the pad up.

Field report (2026-08-15, Nobara host, game mode): the Android client captures a wired SC2 and says so — *"Steam Controller 2 · Wired (USB) · Captured — streams as-is"* — the host attaches the virtual pad over usbip cleanly, and Steam's **Settings → Controller → Connected Controllers** is empty. Buttons do nothing in games. ## The log names the culprit by what is missing from it Every kernel control transfer is present: device/config/string descriptors, `SET_CONFIGURATION`, `SET_IDLE`, and a `GET` of the 372-byte report descriptor. There is **not one `SET_REPORT`** and **not one `answering feature GET`**. The kernel enumerated the controller; Steam never opened it. `60-punktfunk.rules` grants hidraw access per product id, and it lists what the host used to mint — the Sony pads, the Switch Pro, the Deck (`28DE:1205`) and the classic Steam Controller (`28DE:1102`). The two identities `steam_backend_product` mints for the SC2, **wired `28DE:1302`** and **Puck `28DE:1304`**, were never added, so their nodes stayed root-only while the host runs as a user service. The reporter's `punktfunk` group and `vhci_hcd` were both already fine — his log's `attached via usbip … vhci_port=0` proves the attach step works. This is one step later, which is why every existing check passes and the pad still does nothing. ## Why this one is fatal rather than degrading For any other pad a missing hidraw rule costs rich feedback. For the SC2 it costs the controller: - No kernel driver claims the PID — mainline `hid-steam` stops at the Deck. - Its state reports ride a **vendor collection**, so there is no evdev node either. Steam is the only consumer that exists, and a hidraw node Steam cannot open is not a degraded controller, it is no controller. Leaning on the distro's `steam-devices` rules doesn't save it: those lists are per-PID and the SC2 shipped in 2026, so a host whose copy predates it grants nothing. ## The change Both identities added in the same two forms the Deck already uses — `KERNELS` for the UHID shape, `ATTRS` for the usbip/gadget one. **Single source of truth**: every distro installs this one file (the NixOS module takes it from the package via `services.udev.packages`), so no per-packaging change is needed. Plus a troubleshooting section for the symptom, since users on an already-released host need the fix by hand: the drop-in rule, the one-line-plus-one-absence log signature that confirms the diagnosis, a pointer to the existing virtual-Deck section for the checks that come *before* this one, and a note that the trackpads needing Steam to act as a mouse is lizard mode being off on purpose rather than a fault. ## Verification Rules-only change, no code. The added lines mirror the existing Deck/Steam-Controller entries exactly in form and ordering. **Owed: on-glass confirmation** — the reporter applying the equivalent `/etc/udev/rules.d/61-punktfunk-sc2.rules`, reconnecting, and Steam then listing the pad. Worth noting his distro may have covered this via a generic `28de` rule in a newer `steam-devices`, in which case the empty list has a second cause; the log signature above distinguishes them. Not addressed here, and tracked separately: the client's own **input test** shows nothing for a captured SC2 (`isPad(event.device)` rejects the capture's device-less synthesized events, and its sticks never synthesize `MotionEvent`s at all). That will keep looking broken in the app even once Steam picks the pad up.
enricobuehler added 1 commit 2026-08-15 22:48:58 +00:00
fix(host/udev): the virtual Steam Controller 2's hidraw node was root-only, so Steam never saw it
ci / web (pull_request) Successful in 2m16s
ci / rust-arm64 (pull_request) Successful in 3m25s
ci / bun-nix (pull_request) Successful in 34s
ci / docs-site (pull_request) Successful in 2m20s
ci / rust (pull_request) Successful in 7m28s
165a42fcc9
Field report: the Android client captures a wired SC2 and says so ("captured — streams as-is"),
the host attaches the virtual pad over usbip cleanly, and Steam's Settings → Controller →
Connected Controllers is empty. Nothing works in game mode.

The host's own log names the culprit by what is missing from it. Every kernel control transfer is
there — device/config/string descriptors, SET_CONFIGURATION, SET_IDLE, and a GET of the 372-byte
report descriptor — and there is not one SET_REPORT and not one `answering feature GET`. The
kernel enumerated the controller; Steam never opened it.

60-punktfunk.rules grants hidraw access per product id, and it lists what the host used to mint:
the Sony pads, the Switch Pro, the Deck (28DE:1205) and the classic Steam Controller (28DE:1102).
The SC2 identities `steam_backend_product` mints — wired 28DE:1302 and Puck 28DE:1304 — were never
added, so their nodes stayed root-only while the host runs as a user service.

For any other pad that would be a degradation. For this one it is total: no kernel driver claims
the PID (mainline hid-steam stops at the Deck) and the state reports ride a vendor collection, so
there is no evdev node either. Steam is the only consumer there is, and a hidraw node it cannot
open is not a degraded controller, it is no controller. Leaning on the distro's steam-devices
rules doesn't save it — those lists are per-PID and the SC2 shipped in 2026, so a host whose copy
predates it grants nothing.

Add both identities in the same two forms the Deck uses (KERNELS for the UHID shape, ATTRS for the
usbip/gadget one), and document the symptom in troubleshooting with the hand-rollable rule for
hosts on an older package, the one-line-plus-one-absence log signature, and a note that the
trackpads needing Steam to act as a mouse is lizard mode being off on purpose, not a fault.

Single source of truth: every distro installs this file (the NixOS module takes it from the
package via services.udev.packages), so no per-packaging change is needed.
enricobuehler merged commit f67a913ea7 into main 2026-08-15 22:52:44 +00:00
enricobuehler deleted branch worktree-sc2-hidraw-udev 2026-08-15 22:52:51 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#260