Skip to content

Commit 35298cb

Browse files
patches: fix broken multiple controller support for ds5/ds5e/ds4
1 parent d796884 commit 35298cb

1 file changed

Lines changed: 99 additions & 0 deletions

File tree

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2+
From: GE-Proton <git@localhost>
3+
Date: Sun, 16 Aug 2026 00:00:00 -0600
4+
Subject: [PATCH] winebus: Match DualSense hotplug cleanup by physical identity.
5+
6+
The DualSense hidraw preference patch removes stale devices before exposing a
7+
new hidraw node. Matching those devices only by VID, PID, and HID usage also
8+
matches every other connected controller of the same model. Adding a second
9+
DualSense therefore unlinks the first controller and leaves its reports without
10+
a Wine device.
11+
12+
Restrict DualSense cleanup to the same physical controller. Prefer the stable
13+
serial reported by USB or HID_UNIQ reported by Bluetooth. If a USB device has
14+
no usable serial, only match interfaces carrying the same bus container ID,
15+
which identifies the current USB connection. If neither identity is available,
16+
leave the existing device for the normal udev removal path instead of risking
17+
the removal of a different controller.
18+
19+
This preserves stale reconnect and evdev sibling cleanup without preventing
20+
multiple identical DualSense controllers from being connected concurrently.
21+
---
22+
dlls/winebus.sys/main.c | 47 +++++++++++++++++++++++++++++++++++++-----
23+
1 file changed, 42 insertions(+), 5 deletions(-)
24+
25+
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c
26+
--- a/dlls/winebus.sys/main.c
27+
+++ b/dlls/winebus.sys/main.c
28+
@@ -696,16 +696,57 @@ static void bus_unlink_hid_device(DEVICE_OBJECT *device)
29+
RtlLeaveCriticalSection(&device_list_cs);
30+
}
31+
32+
-static void bus_unlink_devices_from_vid_pid(struct device_desc *desc, USAGE_AND_PAGE *usages)
33+
+static BOOL device_desc_has_stable_serial(const struct device_desc *desc)
34+
+{
35+
+ return desc->serialnumber[0] && wcscmp(desc->serialnumber, L"0000");
36+
+}
37+
+
38+
+static BOOL device_desc_matches_physical_device(const struct device_desc *left,
39+
+ const struct device_desc *right)
40+
+{
41+
+ if (left->bus_type != right->bus_type) return FALSE;
42+
+
43+
+ if (device_desc_has_stable_serial(left) && device_desc_has_stable_serial(right))
44+
+ return !wcscmp(left->serialnumber, right->serialnumber);
45+
+
46+
+ if (left->bus_type == BUS_TYPE_USB &&
47+
+ !IsEqualGUID(&left->bus_container_id, &GUID_NULL) &&
48+
+ !IsEqualGUID(&right->bus_container_id, &GUID_NULL))
49+
+ return IsEqualGUID(&left->bus_container_id, &right->bus_container_id);
50+
+
51+
+ return FALSE;
52+
+}
53+
+
54+
+static DEVICE_OBJECT *bus_find_device_from_identity(const BOOL is_hidraw,
55+
+ struct device_desc *desc, USAGE_AND_PAGE *usages)
56+
+{
57+
+ struct device_extension *ext;
58+
+ UINT buttons;
59+
+ USAGE_AND_PAGE found_usages;
60+
+
61+
+ LIST_FOR_EACH_ENTRY(ext, &device_list, struct device_extension, entry)
62+
+ {
63+
+ found_usages = get_device_usages(ext->unix_device, &buttons);
64+
+ if (ext->desc.is_hidraw == is_hidraw && ext->desc.vid == desc->vid &&
65+
+ ext->desc.pid == desc->pid && found_usages.UsagePage == usages->UsagePage &&
66+
+ found_usages.Usage == usages->Usage &&
67+
+ device_desc_matches_physical_device(&ext->desc, desc))
68+
+ return ext->device;
69+
+ }
70+
+
71+
+ return NULL;
72+
+}
73+
+
74+
+static void bus_unlink_devices_from_identity(struct device_desc *desc, USAGE_AND_PAGE *usages)
75+
{
76+
DEVICE_OBJECT *device;
77+
78+
- while ((device = bus_find_device_from_vid_pid(FALSE, desc, usages)))
79+
+ while ((device = bus_find_device_from_identity(FALSE, desc, usages)))
80+
bus_unlink_hid_device(device);
81+
82+
/* Fast USB reconnect can create a new hidraw node before the old removal event
83+
* is processed. Remove stale matching hidraw devices before exposing the new one. */
84+
- while ((device = bus_find_device_from_vid_pid(TRUE, desc, usages)))
85+
+ while ((device = bus_find_device_from_identity(TRUE, desc, usages)))
86+
bus_unlink_hid_device(device);
87+
}
88+
89+
@@ -1576,7 +1617,7 @@ static DWORD CALLBACK bus_main_thread(void *args)
90+
{
91+
RtlEnterCriticalSection(&device_list_cs);
92+
if (is_dualsense_gamepad(desc.vid, desc.pid))
93+
- bus_unlink_devices_from_vid_pid(&event->device_created.desc, &usages);
94+
+ bus_unlink_devices_from_identity(&event->device_created.desc, &usages);
95+
else if ((device = bus_find_device_from_vid_pid(FALSE, &event->device_created.desc, &usages)))
96+
bus_unlink_hid_device(device);
97+
device = bus_create_hid_device(&event->device_created.desc, event->device);
98+
--
99+
2.51.0

0 commit comments

Comments
 (0)