Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions DS4Windows/DS4Control/ControlService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1740,15 +1740,21 @@ public bool Start(bool showlog = true)
AssignInitialDevices();
StartupDiag("AssignInitialDevices end");

// A force-closed prior development build can leave its
// USB/IP output imported. Remove those ports before HID
// discovery or DS4Windows will ingest its own VIIPER DS4,
// create a second output/UAC endpoint, and recurse.
ViiperUsbipPortManager.DetachStaleLocalViiperPorts();
// Let usbccgp/HID finish publishing removal before the
// first input snapshot; otherwise a detached interface can
// remain enumerable for one final discovery pass.
Thread.Sleep(250);
// This used to detach "stale" local VIIPER imports before
// HID discovery so a force-closed prior session's output
// could not be ingested as an input and recursed on. It
// detaches nothing now: identified only by controller
// VID/PID and a localhost URL, another application's live
// virtual pad is indistinguishable from a leftover, and on
// 2026-07-31 the sweep disconnected one mid-game. The pass
// still runs for its log line — any unmanaged local import
// is named, with a pointer to the Settings backend-process
// card, which can attribute leftovers and clear them with
// consent. The self-ingestion case that motivated the
// detach is accepted as a residual risk until inputs can
// recognise this app's own virtual pads; the startup
// warning above fires for exactly that state.
ViiperUsbipPortManager.ObserveLocalImports();

StartupDiag("DS4Devices.findControllers dispatch begin");
eventDispatcher.Invoke(() =>
Expand Down
18 changes: 9 additions & 9 deletions DS4Windows/DS4Control/Viiper/ViiperBackendDebugger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,15 +226,15 @@ private void RunDeviceProbe(ViiperVirtualDeviceType type, CancellationToken canc
int feedbackLength = ViiperStatePacketBuilder.GetFeedbackLength(type);
Log($"Device={type} viiperName={viiperDeviceName} packetLength={packetLength} feedbackLength={feedbackLength}");

// The stale-import sweep used to live inside CreateDeviceAndOpenStream;
// it now gates the output ladder in ViiperOutDevice instead, so this
// diagnostic runs its own. Reported rather than enforced: the point of
// the debugger is to say what it found.
ViiperStalePortSweep sweep =
ViiperUsbipPortManager.DetachStaleLocalViiperPorts();
Log(sweep.Cleared
? "Stale local VIIPER imports: none present"
: $"Stale local VIIPER imports UNPROVEN: {sweep.Reason}");
// The observation pass that gates the output ladder in
// ViiperOutDevice; run here too so the diagnostic records the
// same view. It only reads — unmanaged imports are logged by
// the pass itself and never touched.
ViiperImportObservation observation =
ViiperUsbipPortManager.ObserveLocalImports();
Log(observation.Observed
? "Imported usbip ports: readable"
: $"Imported usbip ports UNREADABLE: {observation.Reason}");

using ViiperDeviceStream stream = client.CreateDeviceAndOpenStream(type);
Log($"Device={type} create/open stream OK");
Expand Down
Loading
Loading