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.
64 lines
5.1 KiB
Plaintext
64 lines
5.1 KiB
Plaintext
# udev rules for the punktfunk streaming host (mirrors Sunshine's 60-sunshine.rules).
|
|
#
|
|
# Grants the `input` group access to /dev/uinput (virtual X-Box-360 gamepads) and /dev/uhid
|
|
# (virtual DualSense via the kernel hid-playstation driver — LED, adaptive triggers, touchpad,
|
|
# gyro). `static_node` makes the nodes exist before their modules load.
|
|
#
|
|
# Install:
|
|
# sudo cp scripts/60-punktfunk.rules /etc/udev/rules.d/
|
|
# sudo usermod -aG input $USER # then re-login (or reboot)
|
|
# sudo udevadm control --reload-rules && sudo udevadm trigger
|
|
KERNEL=="uinput", SUBSYSTEM=="misc", OPTIONS+="static_node=uinput", GROUP="input", MODE="0660", TAG+="uaccess"
|
|
KERNEL=="uhid", SUBSYSTEM=="misc", OPTIONS+="static_node=uhid", GROUP="input", MODE="0660", TAG+="uaccess"
|
|
|
|
# usbip vhci attach/detach for the virtual Steam Deck controller. Steam Input only
|
|
# adopts the virtual Deck when it arrives as a USB device (usbip/vhci or raw_gadget);
|
|
# the UHID fallback has no USB interface and Steam ignores it. The sysfs attach files
|
|
# are root-only by default while the host runs as a user service — grant the dedicated
|
|
# `punktfunk` group write when vhci_hcd appears (module autoload: modules-load.d/punktfunk.conf).
|
|
#
|
|
# ⚠ This is deliberately NOT the `input` group (2026-08-05 review M-4). Writing `attach` hands the
|
|
# kernel a caller-supplied socket fd and materialises an arbitrary, fully userspace-emulated USB
|
|
# device — a root-only kernel primitive. Every packaging scriptlet tells the user to
|
|
# `usermod -aG input $USER` as step 1, so putting it on `input` handed that primitive to a group
|
|
# people are routinely told to join: a member could present a HID keyboard and inject keystrokes
|
|
# into a root TTY or the lock screen, or drive any of hundreds of in-tree USB drivers from
|
|
# userspace, all without CAP_SYS_ADMIN. The uinput/uhid grants above are already systemwide input
|
|
# injection, but neither reaches kernel USB enumeration — this one does, so it gets its own group
|
|
# that nothing else asks users to join.
|
|
ACTION=="add", SUBSYSTEM=="platform", KERNEL=="vhci_hcd.*", RUN+="/bin/sh -c 'chgrp punktfunk /sys%p/attach /sys%p/detach && chmod 0660 /sys%p/attach /sys%p/detach'"
|
|
|
|
# hidraw access for the VIRTUAL pads this host creates. Steam/SDL drive a DualSense's rich
|
|
# feedback (adaptive triggers, lightbar, player LEDs) exclusively over hidraw — the kernel has no
|
|
# evdev API for any of it — and Steam without hidraw demotes a PlayStation pad to a generic evdev
|
|
# device, losing its rumble handling too. hidraw nodes are root-only by default; the distro's
|
|
# steam-devices rules + logind's uaccess ACL cover only the active seat session, so a game
|
|
# launched outside it (a headless/dedicated streaming session) is silently feedback-dead.
|
|
# GROUP="input" makes access follow the same group the host itself already requires.
|
|
# KERNELS matches the HID device name (works for UHID devices, which have no USB parent);
|
|
# the ATTRS pair covers the usbip/gadget Deck, which IS a (virtual) USB device.
|
|
# DualSense (054C:0CE6) / DualSense Edge (054C:0DF2) / DualShock 4 (054C:09CC)
|
|
KERNEL=="hidraw*", KERNELS=="*054C:0CE6*", GROUP="input", MODE="0660", TAG+="uaccess"
|
|
KERNEL=="hidraw*", KERNELS=="*054C:0DF2*", GROUP="input", MODE="0660", TAG+="uaccess"
|
|
KERNEL=="hidraw*", KERNELS=="*054C:09CC*", GROUP="input", MODE="0660", TAG+="uaccess"
|
|
# Switch Pro Controller (057E:2009) — SDL's hidapi driver wants hidraw for rumble/LEDs too
|
|
KERNEL=="hidraw*", KERNELS=="*057E:2009*", GROUP="input", MODE="0660", TAG+="uaccess"
|
|
# Steam Deck (28DE:1205) / classic Steam Controller (28DE:1102), UHID and usbip/gadget forms
|
|
KERNEL=="hidraw*", KERNELS=="*28DE:1205*", GROUP="input", MODE="0660", TAG+="uaccess"
|
|
KERNEL=="hidraw*", KERNELS=="*28DE:1102*", GROUP="input", MODE="0660", TAG+="uaccess"
|
|
KERNEL=="hidraw*", ATTRS{idVendor}=="28de", ATTRS{idProduct}=="1205", GROUP="input", MODE="0660", TAG+="uaccess"
|
|
KERNEL=="hidraw*", ATTRS{idVendor}=="28de", ATTRS{idProduct}=="1102", GROUP="input", MODE="0660", TAG+="uaccess"
|
|
# Steam Controller 2 (Triton): wired 28DE:1302 and the Puck dongle 28DE:1304 — the two identities
|
|
# `steam_backend_product` mints. Steam is the ONLY consumer of this pad: no kernel driver claims
|
|
# the PID (mainline hid-steam stops at the Deck), so its state reports ride a vendor collection
|
|
# that yields no evdev node at all. A hidraw node Steam cannot open is therefore not a degraded
|
|
# controller, it is no controller — the pad enumerates, the kernel reads its report descriptor,
|
|
# and Steam's own device list stays empty (field report 2026-08-15: usbip attached cleanly, the
|
|
# log showed every kernel control transfer and not one SET_REPORT from Steam).
|
|
# Relying on the distro's steam-devices rules is not enough for a pad that shipped in 2026: those
|
|
# lists are per-PID and a host whose copy predates the SC2 leaves the node root-only.
|
|
KERNEL=="hidraw*", KERNELS=="*28DE:1302*", GROUP="input", MODE="0660", TAG+="uaccess"
|
|
KERNEL=="hidraw*", KERNELS=="*28DE:1304*", GROUP="input", MODE="0660", TAG+="uaccess"
|
|
KERNEL=="hidraw*", ATTRS{idVendor}=="28de", ATTRS{idProduct}=="1302", GROUP="input", MODE="0660", TAG+="uaccess"
|
|
KERNEL=="hidraw*", ATTRS{idVendor}=="28de", ATTRS{idProduct}=="1304", GROUP="input", MODE="0660", TAG+="uaccess"
|