From 90c2d8b3a0d8eccf4b1f511e2dbcc90a52628235 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Sat, 4 Jul 2026 11:14:24 +0000 Subject: [PATCH] fix(host): don't count punktfunk's own virtual Deck as a physical Steam controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Steam-conflict gate scanned /sys/bus/hid/devices for non-virtual 28DE devices, but the usbip/gadget virtual Decks present a REAL USB device (vhci resolves through vhci_hcd, not /devices/virtual/) — so a just-ended session's pad still detaching, or a concurrent session's live one, read as "physical Steam controller attached" and degraded every back-to-back Deck session to DualSense (observed live on Bazzite). Exclude our pads by their PFDK… serial (HID_UNIQ), with the vhci_hcd path as belt and braces. Co-Authored-By: Claude Fable 5 --- crates/punktfunk-host/src/punktfunk1.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/crates/punktfunk-host/src/punktfunk1.rs b/crates/punktfunk-host/src/punktfunk1.rs index 45418c3..df1a8dc 100644 --- a/crates/punktfunk-host/src/punktfunk1.rs +++ b/crates/punktfunk-host/src/punktfunk1.rs @@ -1911,6 +1911,13 @@ fn degrade_if_no_uhid(chosen: GamepadPref) -> GamepadPref { /// two Decks — confirmed conflict-prone on a Deck-as-host (the physical `28DE:1205` + Steam's /// `28DE:11FF` XInput output pad are both live). HID device dirs are named `BUS:VID:PID.INST` /// (uppercase); a UHID virtual device resolves through `/devices/virtual/…`, a real one does not. +/// +/// Punktfunk's OWN virtual Decks must never count: the usbip/gadget transports present a real USB +/// device (vhci resolves through `vhci_hcd`, NOT `/devices/virtual/`), so a just-ended session's +/// pad still detaching — or a concurrent session's live one — read as "physical" and degraded +/// every back-to-back Deck session to DualSense (observed live on Bazzite 2026-07-04). Ours are +/// recognizable by the `PFDK…` serial ([`steam_proto::deck_serial`]) in `HID_UNIQ`, with the +/// vhci path as belt and braces. #[cfg(target_os = "linux")] fn physical_steam_controller_present() -> bool { let Ok(entries) = std::fs::read_dir("/sys/bus/hid/devices") else { @@ -1920,8 +1927,16 @@ fn physical_steam_controller_present() -> bool { if !e.file_name().to_string_lossy().contains(":28DE:") { return false; } + if std::fs::read_to_string(e.path().join("uevent")) + .is_ok_and(|u| u.lines().any(|l| l.starts_with("HID_UNIQ=PFDK"))) + { + return false; // one of our own virtual Decks + } match std::fs::read_link(e.path()) { - Ok(target) => !target.to_string_lossy().contains("/virtual/"), + Ok(target) => { + let t = target.to_string_lossy(); + !t.contains("/virtual/") && !t.contains("vhci_hcd") + } Err(_) => true, } })