These patches are prerequisites for getting DualShock 4 controllers to work via USB in Tekken 8.
-- v2: winebus: Override device instance enumerator string if bus type is known. winebus: Generate unique container IDs when adding devices. winebus: Generate unique serial numbers when adding devices.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winebus.sys/bus_sdl.c | 13 +------------ dlls/winebus.sys/main.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 91cb785fdff..3cf34b000d5 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -941,7 +941,7 @@ static void sdl_add_device(unsigned int index) SDL_JoystickType joystick_type; SDL_GameController *controller = NULL; const char *product, *sdl_serial; - char guid_str[33], buffer[ARRAY_SIZE(desc.product)]; + char buffer[ARRAY_SIZE(desc.product)]; int axis_count, axis_offset;
if ((joystick = pSDL_JoystickOpen(index)) == NULL) @@ -975,18 +975,7 @@ static void sdl_add_device(unsigned int index) }
if (pSDL_JoystickGetSerial && (sdl_serial = pSDL_JoystickGetSerial(joystick))) - { ntdll_umbstowcs(sdl_serial, strlen(sdl_serial) + 1, desc.serialnumber, ARRAY_SIZE(desc.serialnumber)); - } - else - { - /* Overcooked! All You Can Eat only adds controllers with unique serial numbers - * Prefer keeping serial numbers unique over keeping them consistent across runs */ - pSDL_JoystickGetGUIDString(pSDL_JoystickGetGUID(joystick), guid_str, sizeof(guid_str)); - snprintf(buffer, sizeof(buffer), "%s.%d", guid_str, index); - TRACE("Making up serial number for %s: %s\n", product, buffer); - ntdll_umbstowcs(buffer, strlen(buffer) + 1, desc.serialnumber, ARRAY_SIZE(desc.serialnumber)); - }
if (controller) { diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index ba8603204d4..0a871269fa9 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -289,6 +289,18 @@ static void remove_pending_irps(DEVICE_OBJECT *device) } }
+static void make_unique_serial(struct device_extension *device) +{ + struct device_extension *ext; + + LIST_FOR_EACH_ENTRY(ext, &device_list, struct device_extension, entry) + if (!wcscmp(device->desc.serialnumber, ext->desc.serialnumber)) break; + if (&ext->entry == &device_list && *device->desc.serialnumber) return; + + swprintf(device->desc.serialnumber, ARRAY_SIZE(device->desc.serialnumber), L"%04x%08x%04x%04x", + device->index, device->desc.input, device->desc.pid, device->desc.vid); +} + static DEVICE_OBJECT *bus_create_hid_device(struct device_desc *desc, UINT64 unix_device) { struct device_extension *ext; @@ -333,6 +345,10 @@ static DEVICE_OBJECT *bus_create_hid_device(struct device_desc *desc, UINT64 uni InitializeCriticalSectionEx(&ext->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); ext->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
+ /* Overcooked! All You Can Eat only adds controllers with unique serial numbers + * Prefer keeping serial numbers unique over keeping them consistent across runs */ + make_unique_serial(ext); + /* add to list of pnp devices */ if (before) list_add_before(before, &ext->entry);
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/winebus.sys/main.c | 49 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+)
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 0a871269fa9..be3405e81cd 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -41,6 +41,9 @@
#include "unixlib.h"
+#include "initguid.h" +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); + WINE_DEFAULT_DEBUG_CHANNEL(hid);
static DRIVER_OBJECT *driver_obj; @@ -81,6 +84,7 @@ struct device_extension enum device_state state;
struct device_desc desc; + GUID container_id; DWORD index;
BYTE *report_desc; @@ -264,6 +268,24 @@ static WCHAR *get_compatible_ids(DEVICE_OBJECT *device) return dst; }
+#define GUID_STRING_LENGTH 39 +static WCHAR *get_container_id(DEVICE_OBJECT *device) +{ + struct device_extension *ext = (struct device_extension *)device->DeviceExtension; + GUID *guid = &ext->container_id; + WCHAR *dst; + + if ((dst = ExAllocatePool(PagedPool, GUID_STRING_LENGTH * sizeof(WCHAR)))) + { + swprintf(dst, GUID_STRING_LENGTH, L"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + } + + TRACE("Returning container ID %s.\n", debugstr_w(dst)); + return dst; +} + static IRP *pop_pending_read(struct device_extension *ext) { IRP *pending; @@ -301,6 +323,22 @@ static void make_unique_serial(struct device_extension *device) device->index, device->desc.input, device->desc.pid, device->desc.vid); }
+static void make_unique_container_id(struct device_extension *device) +{ + struct device_extension *ext; + LARGE_INTEGER ticks; + + LIST_FOR_EACH_ENTRY(ext, &device_list, struct device_extension, entry) + if (IsEqualGUID(&device->container_id, &ext->container_id)) break; + if (&ext->entry == &device_list && !IsEqualGUID(&device->container_id, &GUID_NULL)) return; + + device->container_id.Data1 = MAKELONG(device->desc.vid, device->desc.pid); + device->container_id.Data2 = device->index; + device->container_id.Data3 = device->desc.input; + QueryPerformanceCounter(&ticks); + memcpy(device->container_id.Data4, &ticks.QuadPart, sizeof(device->container_id.Data4)); +} + static DEVICE_OBJECT *bus_create_hid_device(struct device_desc *desc, UINT64 unix_device) { struct device_extension *ext; @@ -349,6 +387,13 @@ static DEVICE_OBJECT *bus_create_hid_device(struct device_desc *desc, UINT64 uni * Prefer keeping serial numbers unique over keeping them consistent across runs */ make_unique_serial(ext);
+ /* + * Some games use container ID to match the bus device to the HID + * device in order to get things like DEVPKEY_Device_BusReportedDeviceDesc. + * Create a unique container ID to facilitate this. + */ + make_unique_container_id(ext); + /* add to list of pnp devices */ if (before) list_add_before(before, &ext->entry); @@ -707,6 +752,10 @@ static NTSTATUS handle_IRP_MN_QUERY_ID(DEVICE_OBJECT *device, IRP *irp) TRACE("BusQueryInstanceID\n"); irp->IoStatus.Information = (ULONG_PTR)get_instance_id(device); break; + case BusQueryContainerID: + TRACE("BusQueryContainerID\n"); + irp->IoStatus.Information = (ULONG_PTR)get_container_id(device); + break; default: WARN("Unhandled type %08x\n", type); return status;
From: Connor McAdams cmcadams@codeweavers.com
Some games use the bus device instance to query properties of a HID device. Tekken 8 does this to get a string for the device to display in the UI. It queries all present devices for their container IDs, and when it finds one with the same container ID as the HID device, it checks the device instance string for a "BTHENUM" or "USB" enumerator.
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/winebus.sys/bus_iohid.c | 9 +++++++-- dlls/winebus.sys/bus_udev.c | 3 ++- dlls/winebus.sys/main.c | 22 ++++++++++++++++------ dlls/winebus.sys/unixlib.h | 14 +++++++++++--- 4 files changed, 36 insertions(+), 12 deletions(-)
diff --git a/dlls/winebus.sys/bus_iohid.c b/dlls/winebus.sys/bus_iohid.c index 648d55dadb8..0b9a0c52c46 100644 --- a/dlls/winebus.sys/bus_iohid.c +++ b/dlls/winebus.sys/bus_iohid.c @@ -287,8 +287,13 @@ static void handle_DeviceMatchingCallback(void *context, IOReturn result, void * desc.uid = CFNumberToDWORD(IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDLocationIDKey)));
if ((str = IOHIDDeviceGetProperty(IOHIDDevice, CFSTR(kIOHIDTransportKey)))) - desc.is_bluetooth = !CFStringCompare(str, CFSTR(kIOHIDTransportBluetoothValue), 0) || - !CFStringCompare(str, CFSTR(kIOHIDTransportBluetoothLowEnergyValue), 0); + { + if (!CFStringCompare(str, CFSTR(kIOHIDTransportBluetoothValue), 0) || + !CFStringCompare(str, CFSTR(kIOHIDTransportBluetoothLowEnergyValue), 0)) + desc.bus_type = BUS_TYPE_BLUETOOTH; + else if (!CFStringCompare(str, CFSTR(kIOHIDTransportUSBValue), 0)) + desc.bus_type = BUS_TYPE_USB; + }
if (usages.UsagePage != HID_USAGE_PAGE_GENERIC || !(usages.Usage == HID_USAGE_GENERIC_JOYSTICK || usages.Usage == HID_USAGE_GENERIC_GAMEPAD)) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 4f929d0cb45..fec7a74f989 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1362,7 +1362,8 @@ static void udev_add_device(struct udev_device *dev, int fd) get_device_subsystem_info(dev, "hid", NULL, &desc, &bus); get_device_subsystem_info(dev, "input", NULL, &desc, &bus); get_device_subsystem_info(dev, "usb", "usb_device", &desc, &bus); - if (bus == BUS_BLUETOOTH) desc.is_bluetooth = TRUE; + if (bus == BUS_BLUETOOTH) desc.bus_type = BUS_TYPE_BLUETOOTH; + else if (bus == BUS_USB) desc.bus_type = BUS_TYPE_USB;
if (!(subsystem = udev_device_get_subsystem(dev))) { diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index be3405e81cd..c8b2db4ed96 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -204,21 +204,31 @@ static WCHAR *get_instance_id(DEVICE_OBJECT *device) return dst; }
+static const WCHAR *bus_type_str[] = +{ + L"WINEBUS", /* BUS_TYPE_UNKNOWN */ + L"USB", /* BUS_TYPE_USB */ + L"BTHENUM", /* BUS_TYPE_BLUETOOTH */ +}; + static WCHAR *get_device_id(DEVICE_OBJECT *device) { static const WCHAR input_format[] = L"&MI_%02u"; - static const WCHAR winebus_format[] = L"WINEBUS\VID_%04X&PID_%04X"; + static const WCHAR winebus_format[] = L"%s\VID_%04X&PID_%04X"; struct device_extension *ext = (struct device_extension *)device->DeviceExtension; - DWORD pos = 0, len = 0, input_len = 0, winebus_len = 25; + DWORD pos = 0, len = 0, input_len = 0, winebus_len = 18; + const WCHAR *bus_str; WCHAR *dst;
+ assert(ext->desc.bus_type < BUS_TYPE_COUNT); + bus_str = bus_type_str[ext->desc.bus_type]; if (ext->desc.input != -1) input_len = 14;
- len += winebus_len + input_len + 1; + len += winebus_len + input_len + wcslen(bus_str) + 1;
if ((dst = ExAllocatePool(PagedPool, len * sizeof(WCHAR)))) { - pos += swprintf(dst + pos, len - pos, winebus_format, ext->desc.vid, ext->desc.pid); + pos += swprintf(dst + pos, len - pos, winebus_format, bus_str, ext->desc.vid, ext->desc.pid); if (input_len) pos += swprintf(dst + pos, len - pos, input_format, ext->desc.input); }
@@ -369,12 +379,12 @@ static DEVICE_OBJECT *bus_create_hid_device(struct device_desc *desc, UINT64 uni ext->unix_device = unix_device; list_init(&ext->reports);
- if (desc->is_hidraw && desc->is_bluetooth && is_dualshock4_gamepad(desc->vid, desc->pid)) + if (desc->is_hidraw && (desc->bus_type == BUS_TYPE_BLUETOOTH) && is_dualshock4_gamepad(desc->vid, desc->pid)) { TRACE("Enabling report fixup for Bluetooth DualShock4 device %p\n", device); ext->report_fixups |= HIDRAW_FIXUP_DUALSHOCK_BT; } - if (desc->is_hidraw && desc->is_bluetooth && is_dualsense_gamepad(desc->vid, desc->pid)) + if (desc->is_hidraw && (desc->bus_type == BUS_TYPE_BLUETOOTH) && is_dualsense_gamepad(desc->vid, desc->pid)) { TRACE("Enabling report fixup for Bluetooth DualSense device %p\n", device); ext->report_fixups |= HIDRAW_FIXUP_DUALSENSE_BT; diff --git a/dlls/winebus.sys/unixlib.h b/dlls/winebus.sys/unixlib.h index 8dab8af0d57..d2b17f4c6d3 100644 --- a/dlls/winebus.sys/unixlib.h +++ b/dlls/winebus.sys/unixlib.h @@ -38,9 +38,9 @@ struct device_desc UINT version; UINT input; UINT uid; + UINT bus_type; BOOL is_gamepad; BOOL is_hidraw; - BOOL is_bluetooth;
WCHAR manufacturer[MAX_PATH]; WCHAR product[MAX_PATH]; @@ -76,6 +76,14 @@ enum bus_event_type BUS_EVENT_TYPE_INPUT_REPORT, };
+enum bus_type +{ + BUS_TYPE_UNKNOWN, + BUS_TYPE_USB, + BUS_TYPE_BLUETOOTH, + BUS_TYPE_COUNT, +}; + struct bus_event { UINT type; @@ -151,9 +159,9 @@ enum unix_funcs static inline const char *debugstr_device_desc(struct device_desc *desc) { if (!desc) return "(null)"; - return wine_dbg_sprintf("{vid %04x, pid %04x, version %04x, input %d, uid %08x, is_gamepad %u, is_hidraw %u, is_bluetooth %u}", + return wine_dbg_sprintf("{vid %04x, pid %04x, version %04x, input %d, uid %08x, is_gamepad %u, is_hidraw %u, bus_type %u}", desc->vid, desc->pid, desc->version, desc->input, desc->uid, - desc->is_gamepad, desc->is_hidraw, desc->is_bluetooth); + desc->is_gamepad, desc->is_hidraw, desc->bus_type); }
static inline BOOL is_xbox_gamepad(WORD vid, WORD pid)
LGTM but you have to resolve the conflicts with the other MR.
This merge request was approved by Rémi Bernon.