From b8fd652cb8e9d1767a1e018d2e85cffe0d91889d Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Wed, 8 Jul 2026 10:50:19 +0200 Subject: [PATCH] fix(packaging): autoload vhci-hcd and open its attach files for the usbip Deck pad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Steam Input only adopts the virtual Steam Deck controller when it arrives as a real USB device (raw_gadget or usbip/vhci transports); the UHID fallback has no USB interface and Steam ignores it. On a stock host neither precondition for usbip held: vhci-hcd isn't loaded, and its sysfs attach/detach files are root-only while the host runs as a user service — so every session silently fell back to UHID and 'no controller appears on the host' (live-debugged 2026-07-08: client events all arrived, the pad existed, Steam just refused it). Ship both preconditions with the host packages: * modules-load.d/punktfunk.conf loads vhci-hcd at boot (rpm/deb/arch; Bazzite gets it via the RPM payload + a modprobe in the sysext post-merge hook) * a udev rule in 60-punktfunk.rules grants the input group write on vhci_hcd's attach/detach whenever the device appears Verified end-to-end on a live host: usbip in-process attach, hid-steam binds all three interfaces, 'Steam Deck' + motion evdev appear, and Steam adopts the pad (client-mode grab + its own virtual X360 emission). Co-Authored-By: Claude Fable 5 --- packaging/arch/PKGBUILD | 2 ++ packaging/bazzite/punktfunk-sysext.sh | 4 ++++ packaging/debian/build-deb.sh | 2 ++ packaging/rpm/punktfunk.spec | 5 +++++ scripts/60-punktfunk.rules | 7 +++++++ scripts/punktfunk-modules.conf | 8 ++++++++ 6 files changed, 28 insertions(+) create mode 100644 scripts/punktfunk-modules.conf diff --git a/packaging/arch/PKGBUILD b/packaging/arch/PKGBUILD index a794bd29..953bccc1 100644 --- a/packaging/arch/PKGBUILD +++ b/packaging/arch/PKGBUILD @@ -98,6 +98,8 @@ package_punktfunk-host() { install -Dm0755 "$T/punktfunk-host" "$pkgdir/usr/bin/punktfunk-host" # /dev/uinput + /dev/uhid -> input group (virtual gamepads + DualSense UHID) install -Dm0644 "$R/scripts/60-punktfunk.rules" "$pkgdir/usr/lib/udev/rules.d/60-punktfunk.rules" + # vhci-hcd autoload — usbip transport for the virtual Steam Deck pad (Steam only adopts USB pads) + install -Dm0644 "$R/scripts/punktfunk-modules.conf" "$pkgdir/usr/lib/modules-load.d/punktfunk.conf" # 32 MB UDP socket buffers (send-side headroom at high bitrate) install -Dm0644 "$R/scripts/99-punktfunk-net.conf" "$pkgdir/usr/lib/sysctl.d/99-punktfunk-net.conf" # systemd USER units (the host runs in the graphical session, not as root); repoint ExecStart. diff --git a/packaging/bazzite/punktfunk-sysext.sh b/packaging/bazzite/punktfunk-sysext.sh index f29f5661..07a209e5 100644 --- a/packaging/bazzite/punktfunk-sysext.sh +++ b/packaging/bazzite/punktfunk-sysext.sh @@ -77,6 +77,10 @@ post_merge() { for f in /usr/lib/sysctl.d/99-punktfunk-net.conf /usr/lib/sysctl.d/99-punktfunk-client-net.conf; do [ -f "$f" ] && sysctl -q -p "$f" 2>/dev/null || : done + # vhci-hcd now, no reboot (modules-load.d/punktfunk.conf covers boot): the usbip transport + # that makes the virtual Steam Deck pad a real USB device Steam Input adopts. The udev add + # event fires the 60-punktfunk.rules vhci rule, opening the attach files to the input group. + [ -f /usr/lib/modules-load.d/punktfunk.conf ] && modprobe vhci-hcd 2>/dev/null || : # The /etc payload a sysext can't carry. The gamescope-session drop-in is %config(noreplace): # only seed it, never clobber a local edit. The tray autostart entry is not user config. if [ -f "$ETC_SRC/gamescope-session-plus/sessions.d/steam" ] \ diff --git a/packaging/debian/build-deb.sh b/packaging/debian/build-deb.sh index 61a34d00..9c434412 100755 --- a/packaging/debian/build-deb.sh +++ b/packaging/debian/build-deb.sh @@ -42,6 +42,8 @@ SHAREDIR="$STAGE/usr/share/$PKG" # --- file layout (matches the RPM %install) ---------------------------------- install -Dm0755 "$BIN" "$STAGE/usr/bin/$PKG" install -Dm0644 scripts/60-punktfunk.rules "$STAGE/usr/lib/udev/rules.d/60-punktfunk.rules" +# vhci-hcd autoload — usbip transport for the virtual Steam Deck pad (Steam only adopts USB pads). +install -Dm0644 scripts/punktfunk-modules.conf "$STAGE/usr/lib/modules-load.d/punktfunk.conf" # UDP socket-buffer tuning (32 MB) — without it the kernel clamps the host's SO_SNDBUF to ~416 KB # and high-bitrate frames overflow it (send-side packet loss). systemd-sysctl applies it at boot. install -Dm0644 scripts/99-punktfunk-net.conf "$STAGE/usr/lib/sysctl.d/99-punktfunk-net.conf" diff --git a/packaging/rpm/punktfunk.spec b/packaging/rpm/punktfunk.spec index df4bc96e..40a46a27 100644 --- a/packaging/rpm/punktfunk.spec +++ b/packaging/rpm/punktfunk.spec @@ -195,6 +195,10 @@ install -Dm0755 target/release/punktfunk-host %{buildroot}%{_bindir}/punktfunk-h # udev rule — /dev/uinput access for virtual gamepads (input group). install -Dm0644 scripts/60-punktfunk.rules %{buildroot}%{_udevrulesdir}/60-punktfunk.rules +# vhci-hcd autoload — the usbip transport that makes the virtual Steam Deck controller a +# real USB device (Steam Input only adopts those; the UHID fallback is invisible to Steam). +install -Dm0644 scripts/punktfunk-modules.conf %{buildroot}%{_prefix}/lib/modules-load.d/punktfunk.conf + # UDP socket-buffer tuning (32 MB) — without it the kernel clamps the host's SO_SNDBUF to ~416 KB # and high-bitrate frames overflow it (send-side loss). systemd-sysctl applies it at boot. install -Dm0644 scripts/99-punktfunk-net.conf %{buildroot}%{_prefix}/lib/sysctl.d/99-punktfunk-net.conf @@ -309,6 +313,7 @@ install -Dm0644 web/web.env.example %{buildroot}%{_datadir}/punkt %{_bindir}/punktfunk-host %{_bindir}/punktfunk-tray %{_udevrulesdir}/60-punktfunk.rules +%{_prefix}/lib/modules-load.d/punktfunk.conf %{_prefix}/lib/sysctl.d/99-punktfunk-net.conf %{_prefix}/lib/firewalld/services/punktfunk-gamestream.xml %{_prefix}/lib/firewalld/services/punktfunk-native.xml diff --git a/scripts/60-punktfunk.rules b/scripts/60-punktfunk.rules index 20cd95dc..aa5a1ee7 100644 --- a/scripts/60-punktfunk.rules +++ b/scripts/60-punktfunk.rules @@ -10,3 +10,10 @@ # 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 `input` +# group write when vhci_hcd appears (module autoload: modules-load.d/punktfunk.conf). +ACTION=="add", SUBSYSTEM=="platform", KERNEL=="vhci_hcd.*", RUN+="/bin/sh -c 'chgrp input /sys%p/attach /sys%p/detach && chmod 0660 /sys%p/attach /sys%p/detach'" diff --git a/scripts/punktfunk-modules.conf b/scripts/punktfunk-modules.conf new file mode 100644 index 00000000..2886b707 --- /dev/null +++ b/scripts/punktfunk-modules.conf @@ -0,0 +1,8 @@ +# Kernel modules the punktfunk host needs at boot (installed as +# /usr/lib/modules-load.d/punktfunk.conf). +# +# vhci-hcd: the usbip virtual host controller — the transport that makes the virtual +# Steam Deck controller a real USB device so Steam Input adopts it (see +# inject/linux/steam_usbip.rs and the vhci rule in 60-punktfunk.rules). Without it the +# pad falls back to plain UHID, which Steam ignores ("no controller appears"). +vhci-hcd