As we are going to reuse the same device id when re-plugging a previously plugged SDL controller, the device interfaces are still present in the tree and IoRegisterDeviceInterface was not updating the device pointer.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/ntoskrnl.exe/pnp.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c index 03c4c401f97..17d61a096a0 100644 --- a/dlls/ntoskrnl.exe/pnp.c +++ b/dlls/ntoskrnl.exe/pnp.c @@ -622,7 +622,9 @@ NTSTATUS WINAPI IoRegisterDeviceInterface(DEVICE_OBJECT *device, const GUID *cla WCHAR device_instance_id[MAX_DEVICE_ID_LEN]; SP_DEVICE_INTERFACE_DETAIL_DATA_W *data; NTSTATUS status = STATUS_SUCCESS; + UNICODE_STRING device_path; struct device_interface *iface; + struct wine_rb_entry *entry; DWORD required; HDEVINFO set;
@@ -660,19 +662,32 @@ NTSTATUS WINAPI IoRegisterDeviceInterface(DEVICE_OBJECT *device, const GUID *cla
data->DevicePath[1] = '?'; TRACE("Returning path %s.\n", debugstr_w(data->DevicePath)); + RtlCreateUnicodeString( &device_path, data->DevicePath); + + entry = wine_rb_get( &device_interfaces, &device_path ); + if (entry) + { + iface = WINE_RB_ENTRY_VALUE( entry, struct device_interface, entry ); + if (iface->enabled) + ERR("Device interface %s is still enabled.\n", debugstr_us(&iface->symbolic_link)); + } + else + { + iface = heap_alloc_zero( sizeof(struct device_interface) ); + RtlCreateUnicodeString(&iface->symbolic_link, data->DevicePath); + if (wine_rb_put( &device_interfaces, &iface->symbolic_link, &iface->entry )) + ERR("Failed to insert interface %s into tree.\n", debugstr_us(&iface->symbolic_link)); + }
- iface = heap_alloc_zero( sizeof(struct device_interface) ); iface->device = device; iface->interface_class = *class_guid; - RtlCreateUnicodeString(&iface->symbolic_link, data->DevicePath); if (symbolic_link) RtlCreateUnicodeString( symbolic_link, data->DevicePath);
- if (wine_rb_put( &device_interfaces, &iface->symbolic_link, &iface->entry )) - ERR("Failed to insert interface %s into tree.\n", debugstr_us(&iface->symbolic_link)); - HeapFree( GetProcessHeap(), 0, data );
+ RtlFreeUnicodeString( &device_path ); + return status; }
-- 2.23.0
Some games are using the HID device id as the gamepad index for xinput API. When hotplugging devices, SDL increases its instance id and it doesn't match anymore with xinput gamepad numbers.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/bus_sdl.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index d3a1a19eeba..8fcec46d04d 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -744,17 +744,21 @@ static const platform_vtbl sdl_vtbl = set_feature_report, };
+static int compare_joystick_id(DEVICE_OBJECT *device, void* context) +{ + return impl_from_DEVICE_OBJECT(device)->id - PtrToUlong(context); +} + static BOOL set_report_from_event(SDL_Event *event) { DEVICE_OBJECT *device; struct platform_private *private; /* All the events coming in will have 'which' as a 3rd field */ - SDL_JoystickID index = ((SDL_JoyButtonEvent*)event)->which; - - device = bus_find_hid_device(&sdl_vtbl, ULongToPtr(index)); + SDL_JoystickID id = ((SDL_JoyButtonEvent*)event)->which; + device = bus_enumerate_hid_devices(&sdl_vtbl, compare_joystick_id, ULongToPtr(id)); if (!device) { - ERR("Failed to find device at index %i\n",index); + ERR("Failed to find device at index %i\n",id); return FALSE; } private = impl_from_DEVICE_OBJECT(device); @@ -814,11 +818,11 @@ static BOOL set_mapped_report_from_event(SDL_Event *event) DEVICE_OBJECT *device; struct platform_private *private; /* All the events coming in will have 'which' as a 3rd field */ - int index = ((SDL_ControllerButtonEvent*)event)->which; - device = bus_find_hid_device(&sdl_vtbl, ULongToPtr(index)); + SDL_JoystickID id = ((SDL_ControllerButtonEvent*)event)->which; + device = bus_enumerate_hid_devices(&sdl_vtbl, compare_joystick_id, ULongToPtr(id)); if (!device) { - ERR("Failed to find device at index %i\n",index); + ERR("Failed to find device at index %i\n",id); return FALSE; } private = impl_from_DEVICE_OBJECT(device); @@ -878,7 +882,7 @@ static BOOL set_mapped_report_from_event(SDL_Event *event) return FALSE; }
-static void try_remove_device(SDL_JoystickID index) +static void try_remove_device(SDL_JoystickID id) { DEVICE_OBJECT *device = NULL; struct platform_private *private; @@ -886,7 +890,7 @@ static void try_remove_device(SDL_JoystickID index) SDL_GameController *sdl_controller; SDL_Haptic *sdl_haptic;
- device = bus_find_hid_device(&sdl_vtbl, ULongToPtr(index)); + device = bus_enumerate_hid_devices(&sdl_vtbl, compare_joystick_id, ULongToPtr(id)); if (!device) return;
private = impl_from_DEVICE_OBJECT(device); @@ -905,7 +909,7 @@ static void try_remove_device(SDL_JoystickID index) pSDL_HapticClose(sdl_haptic); }
-static void try_add_device(SDL_JoystickID index) +static void try_add_device(unsigned int index) { DWORD vid = 0, pid = 0, version = 0; DEVICE_OBJECT *device = NULL; @@ -967,7 +971,7 @@ static void try_add_device(SDL_JoystickID index) input = 0;
device = bus_create_hid_device(sdl_busidW, vid, pid, - input, version, id, serial, is_xbox_gamepad, &GUID_DEVCLASS_SDL, + input, version, index, serial, is_xbox_gamepad, &GUID_DEVCLASS_SDL, &sdl_vtbl, sizeof(struct platform_private));
if (device) -- 2.23.0
Some games are checking the hid product string of connected gamepads in order to decide whether or not to activate rumble.
Wine usually delegates these queries to the backend driver, but they don't always report the same product strings as on Windows. This will allow to override backend strings with the actual strings as reported by native drivers.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winebus.sys/main.c | 102 +++++++++++++++++++++++++++++++++------- 1 file changed, 85 insertions(+), 17 deletions(-)
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 89ea65bba67..d1f95218b30 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -49,22 +49,39 @@ WINE_DECLARE_DEBUG_CHANNEL(hid_report);
static const WCHAR backslashW[] = {'\',0};
+struct product_desc +{ + WORD vid; + WORD pid; + const WCHAR* manufacturer; + const WCHAR* product; + const WCHAR* serialnumber; +}; + #define VID_MICROSOFT 0x045e
-static const WORD PID_XBOX_CONTROLLERS[] = { - 0x0202, /* Xbox Controller */ - 0x0285, /* Xbox Controller S */ - 0x0289, /* Xbox Controller S */ - 0x028e, /* Xbox360 Controller */ - 0x028f, /* Xbox360 Wireless Controller */ - 0x02d1, /* Xbox One Controller */ - 0x02dd, /* Xbox One Controller (Covert Forces/Firmware 2015) */ - 0x02e0, /* Xbox One X Controller */ - 0x02e3, /* Xbox One Elite Controller */ - 0x02e6, /* Wireless XBox Controller Dongle */ - 0x02ea, /* Xbox One S Controller */ - 0x02fd, /* Xbox One S Controller (Firmware 2017) */ - 0x0719, /* Xbox 360 Wireless Adapter */ +static const WCHAR xbox360_product_string[] = { + 'C','o','n','t','r','o','l','l','e','r',' ','(','X','B','O','X',' ','3','6','0',' ','F','o','r',' ','W','i','n','d','o','w','s',')',0 +}; + +static const WCHAR xboxone_product_string[] = { + 'C','o','n','t','r','o','l','l','e','r',' ','(','X','B','O','X',' ','O','n','e',' ','F','o','r',' ','W','i','n','d','o','w','s',')',0 +}; + +static const struct product_desc XBOX_CONTROLLERS[] = { + {VID_MICROSOFT, 0x0202, NULL, NULL, NULL}, /* Xbox Controller */ + {VID_MICROSOFT, 0x0285, NULL, NULL, NULL}, /* Xbox Controller S */ + {VID_MICROSOFT, 0x0289, NULL, NULL, NULL}, /* Xbox Controller S */ + {VID_MICROSOFT, 0x028e, NULL, xbox360_product_string, NULL}, /* Xbox360 Controller */ + {VID_MICROSOFT, 0x028f, NULL, xbox360_product_string, NULL}, /* Xbox360 Wireless Controller */ + {VID_MICROSOFT, 0x02d1, NULL, xboxone_product_string, NULL}, /* Xbox One Controller */ + {VID_MICROSOFT, 0x02dd, NULL, xboxone_product_string, NULL}, /* Xbox One Controller (Covert Forces/Firmware 2015) */ + {VID_MICROSOFT, 0x02e0, NULL, NULL, NULL}, /* Xbox One X Controller */ + {VID_MICROSOFT, 0x02e3, NULL, xboxone_product_string, NULL}, /* Xbox One Elite Controller */ + {VID_MICROSOFT, 0x02e6, NULL, NULL, NULL}, /* Wireless XBox Controller Dongle */ + {VID_MICROSOFT, 0x02ea, NULL, xboxone_product_string, NULL}, /* Xbox One S Controller */ + {VID_MICROSOFT, 0x02fd, NULL, xboxone_product_string, NULL}, /* Xbox One S Controller (Firmware 2017) */ + {VID_MICROSOFT, 0x0719, NULL, xbox360_product_string, NULL}, /* Xbox 360 Wireless Adapter */ };
static DRIVER_OBJECT *driver_obj; @@ -514,6 +531,55 @@ static NTSTATUS deliver_last_report(struct device_extension *ext, DWORD buffer_l } }
+static NTSTATUS hid_get_native_string(DEVICE_OBJECT *device, DWORD index, WCHAR *buffer, DWORD length) +{ + struct device_extension *ext = (struct device_extension *)device->DeviceExtension; + const struct product_desc *vendor_products; + unsigned int i, vendor_products_size = 0; + + if (ext->vid == VID_MICROSOFT) + { + vendor_products = XBOX_CONTROLLERS; + vendor_products_size = ARRAY_SIZE(XBOX_CONTROLLERS); + } + + for (i = 0; i < vendor_products_size; i++) + { + if (ext->pid == vendor_products[i].pid) + break; + } + + if (i >= vendor_products_size) + return STATUS_UNSUCCESSFUL; + + switch (index) + { + case HID_STRING_ID_IPRODUCT: + if (vendor_products[i].product) + { + strcpyW(buffer, vendor_products[i].product); + return STATUS_SUCCESS; + } + break; + case HID_STRING_ID_IMANUFACTURER: + if (vendor_products[i].manufacturer) + { + strcpyW(buffer, vendor_products[i].manufacturer); + return STATUS_SUCCESS; + } + break; + case HID_STRING_ID_ISERIALNUMBER: + if (vendor_products[i].serialnumber) + { + strcpyW(buffer, vendor_products[i].serialnumber); + return STATUS_SUCCESS; + } + break; + } + + return STATUS_UNSUCCESSFUL; +} + static NTSTATUS WINAPI hid_internal_dispatch(DEVICE_OBJECT *device, IRP *irp) { NTSTATUS status = irp->IoStatus.u.Status; @@ -593,7 +659,9 @@ static NTSTATUS WINAPI hid_internal_dispatch(DEVICE_OBJECT *device, IRP *irp) DWORD index = (ULONG_PTR)irpsp->Parameters.DeviceIoControl.Type3InputBuffer; TRACE("IOCTL_HID_GET_STRING[%08x]\n", index);
- irp->IoStatus.u.Status = status = ext->vtbl->get_string(device, index, (WCHAR *)irp->UserBuffer, length); + irp->IoStatus.u.Status = status = hid_get_native_string(device, index, (WCHAR *)irp->UserBuffer, length); + if (status != STATUS_SUCCESS) + irp->IoStatus.u.Status = status = ext->vtbl->get_string(device, index, (WCHAR *)irp->UserBuffer, length); if (status == STATUS_SUCCESS) irp->IoStatus.Information = (strlenW((WCHAR *)irp->UserBuffer) + 1) * sizeof(WCHAR); break; @@ -758,8 +826,8 @@ BOOL is_xbox_gamepad(WORD vid, WORD pid) if (vid != VID_MICROSOFT) return FALSE;
- for (i = 0; i < ARRAY_SIZE(PID_XBOX_CONTROLLERS); i++) - if (pid == PID_XBOX_CONTROLLERS[i]) return TRUE; + for (i = 0; i < ARRAY_SIZE(XBOX_CONTROLLERS); i++) + if (pid == XBOX_CONTROLLERS[i].pid) return TRUE;
return FALSE; } -- 2.23.0