fix(host/steam): load vhci_hcd at boot on sysext hosts so the Deck pad is Steam-Input-promotable
ci / web (push) Successful in 1m2s
ci / docs-site (push) Successful in 1m9s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 8s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 8s
decky / build-publish (push) Successful in 30s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 8s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 8s
apple / swift (push) Successful in 4m25s
ci / bench (push) Successful in 6m50s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 5m49s
docker / deploy-docs (push) Successful in 26s
windows-host / package (push) Successful in 8m40s
arch / build-publish (push) Successful in 11m22s
deb / build-publish (push) Successful in 12m27s
android / android (push) Successful in 16m50s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 19m19s
apple / screenshots (push) Successful in 19m19s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 17m14s
ci / rust (push) Successful in 25m14s

The virtual Steam Deck pad only appears in the host's Game Mode (and is
navigable) when it arrives as a real USB device via the usbip/vhci_hcd
transport — Steam Input won't promote the UHID hid-steam fallback
(Interface: -1). The host runs as an unprivileged --user service, so it
cannot modprobe vhci_hcd itself; the module must be loaded at boot and the
vhci attach/detach sysfs files chgrp'd to the `input` group by the udev
rule.

Packaging ships modules-load.d/punktfunk.conf + 60-punktfunk.rules under
the sysext's /usr/lib, but a systemd-sysext image MERGES after
systemd-modules-load and early udev have already run, so on a plain reboot
of a sysext host (e.g. Bazzite) those files are read too late: vhci_hcd is
never loaded, usbip fails, and the pad silently degrades to non-promoted
UHID — the controller vanishes from Game Mode. (deb/arch/rpm are
unaffected: real /usr is present at early boot.)

Fix: sysext post_merge now mirrors BOTH files into real /etc (read at the
normal early-boot time, shadowing the /usr copies by filename; refreshed
every merge since neither is user config), then reloads udev, modprobes
vhci-hcd, and re-triggers the vhci platform device for the live session.
Also raise the UHID-fallback log INFO->WARN with an actionable hint.

Verified on the .41 sysext host: after the /etc mirror, unloading vhci_hcd
and restarting systemd-modules-load (the real reader of /etc/modules-load.d)
reloads the module; a udev coldplug trigger makes attach/detach root:input
0660; the unprivileged host user can then write attach — the exact working
precondition for the usbip transport, now durable across reboot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-13 17:41:51 +02:00
parent a9dc6efe55
commit e5166c6e6e
2 changed files with 30 additions and 7 deletions
@@ -339,11 +339,18 @@ fn open_transport(idx: u8) -> Result<DeckTransport> {
}
}
}
// 3. UHID — universal fallback (works everywhere; Steam Input won't promote it).
// 3. UHID — universal fallback (works everywhere; Steam Input won't promote it). This is a
// DEGRADED outcome, not a normal one: a UHID device has no USB interface number (Interface: -1),
// so Steam Input ignores it and the controller never appears in Game Mode / can't navigate.
// Reaching here almost always means `vhci_hcd` isn't loaded (the host runs unprivileged and
// can't modprobe it) — load it at boot (packaging ships modules-load.d/punktfunk.conf +
// 60-punktfunk.rules; on a systemd-sysext host `punktfunk-sysext` mirrors both into /etc).
let p = SteamDeckPad::open(idx)?;
tracing::info!(
tracing::warn!(
index = idx,
"virtual Steam Deck created (UHID hid-steam — not Steam-Input-promoted)"
"virtual Steam Deck created as UHID hid-steam — Steam Input WON'T promote it (no USB \
interface), so it won't appear in Game Mode. Load vhci_hcd (usbip) so the pad arrives as a \
real USB device: `sudo modprobe vhci_hcd`, and ensure it loads at boot."
);
Ok(DeckTransport::Uhid(p))
}