[PATCH 0/4] MR11745: hidclass.sys: Include the device id in the hardware ids list.
query_hardware_ids() builds the hardware ids list from vid/pid, usage and HID_DEVICE strings, but never includes the PDO's own device id. For composite USB devices this id carries the &MI_xx interface index, which is how Windows lets applications identify which interface of a multi-interface device a given HID device object belongs to. Add it as the most specific (first) entry. Signed-off-by: Sanskar Jaiswal <phoenix2810@protonmail.com> -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11745
From: Sanskar Jaiswal <phoenix2810@protonmail.com> query_hardware_ids() builds the hardware ids list from vid/pid, usage and HID_DEVICE strings, but never includes the PDO's own device id. For composite USB devices this id carries the &MI_xx interface index, which is how Windows lets applications identify which interface of a multi-interface device a given HID device object belongs to. Add it as the most specific (first) entry. Signed-off-by: Sanskar Jaiswal <phoenix2810@protonmail.com> --- dlls/hidclass.sys/pnp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 87531104354..585f04a7992 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -430,7 +430,8 @@ static WCHAR *query_hardware_ids(DEVICE_OBJECT *device) WCHAR *dst; DWORD size; - size = sizeof(vid_pid_format); + size = (wcslen(pdo->base.device_id) + 1) * sizeof(WCHAR); + size += sizeof(vid_pid_format); size += sizeof(vid_usage_format); size += sizeof(usage_format); size += sizeof(hid_format); @@ -438,6 +439,7 @@ static WCHAR *query_hardware_ids(DEVICE_OBJECT *device) if ((dst = ExAllocatePool(PagedPool, size + sizeof(WCHAR)))) { DWORD len = size / sizeof(WCHAR), pos = 0; + pos += swprintf( dst + pos, len - pos, L"%s", pdo->base.device_id ) + 1; pos += swprintf( dst + pos, len - pos, vid_pid_format, info->VendorID, info->ProductID ) + 1; pos += swprintf( dst + pos, len - pos, vid_usage_format, info->VendorID, desc->UsagePage, desc->Usage ) + 1; pos += swprintf( dst + pos, len - pos, usage_format, desc->UsagePage, desc->Usage ) + 1; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11745
From: Sanskar Jaiswal <phoenix2810@protonmail.com> get_compatible_ids() only ever returns WINEBUS\WINE_COMP_HID (plus WINE_COMP_XINPUT for gamepads). hidapi looks for a "USB" compatible id on the parent PDO to recover a device's USB interface number, and without it treats every Wine-enumerated device as interface -1. Add the standard USB\VID_xxxx&PID_yyyy compatible id for devices on the USB bus, matching what Windows exposes. Signed-off-by: Sanskar Jaiswal <phoenix2810@protonmail.com> --- dlls/winebus.sys/main.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 0132297a4a6..a9dcc9fc86c 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -261,17 +261,34 @@ static WCHAR *get_compatible_ids(DEVICE_OBJECT *device) { static const WCHAR xinput_compat[] = L"WINEBUS\\WINE_COMP_XINPUT"; static const WCHAR hid_compat[] = L"WINEBUS\\WINE_COMP_HID"; + static const WCHAR usb_compat_format[] = L"USB\\VID_%04X&PID_%04X"; struct device_extension *ext = (struct device_extension *)device->DeviceExtension; - DWORD size = sizeof(hid_compat); + WCHAR usb_compat[24]; + DWORD usb_len = 0, size, pos = 0; WCHAR *dst; + if (ext->desc.bus_type == BUS_TYPE_USB) + usb_len = (swprintf(usb_compat, ARRAY_SIZE(usb_compat), usb_compat_format, + ext->desc.vid, ext->desc.pid) + 1) * sizeof(WCHAR); + + size = sizeof(hid_compat) + usb_len; if (ext->desc.is_gamepad) size += sizeof(xinput_compat); if ((dst = ExAllocatePool(PagedPool, size + sizeof(WCHAR)))) { - if (ext->desc.is_gamepad) memcpy(dst, xinput_compat, sizeof(xinput_compat)); - memcpy((char *)dst + size - sizeof(hid_compat), hid_compat, sizeof(hid_compat)); - dst[size / sizeof(WCHAR)] = 0; + if (ext->desc.is_gamepad) + { + memcpy(dst + pos, xinput_compat, sizeof(xinput_compat)); + pos += ARRAY_SIZE(xinput_compat); + } + memcpy(dst + pos, hid_compat, sizeof(hid_compat)); + pos += ARRAY_SIZE(hid_compat); + if (usb_len) + { + memcpy(dst + pos, usb_compat, usb_len); + pos += usb_len / sizeof(WCHAR); + } + dst[pos] = 0; } return dst; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11745
From: Sanskar Jaiswal <phoenix2810@protonmail.com> make_unique_serial() synthesizes a new serial number on any collision with an already-registered device, including the expected collision between two HID interfaces of the same composite device. Windows keeps the real, shared serial number across such sibling interfaces, and applications may rely on that to pair them together. Skip the rewrite when the collision is with a sibling interface of the same device (same VID/PID, different interface index); other collisions still get a synthesized unique serial. Signed-off-by: Sanskar Jaiswal <phoenix2810@protonmail.com> --- dlls/winebus.sys/main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index a9dcc9fc86c..3efc17baf21 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -360,6 +360,18 @@ static void make_unique_serial(struct device_extension *device) if (!wcscmp(device->desc.serialnumber, ext->desc.serialnumber)) break; if (&ext->entry == &device_list && *device->desc.serialnumber) return; + /* + * A collision with a sibling HID interface of the same physical device + * (same VID/PID, different interface index) is expected and should not + * be rewritten, since applications may rely on the shared serial number + * to pair a device's interfaces together. + */ + if (&ext->entry != &device_list && + ext->desc.vid == device->desc.vid && + ext->desc.pid == device->desc.pid && + ext->desc.input != device->desc.input) + 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); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11745
From: Sanskar Jaiswal <phoenix2810@protonmail.com> On Windows the container id identifies the physical device, and applications use it to group a composite device's HID interfaces together. winebus.sys currently assigns each interface its own container id. Reuse the container id already assigned to a sibling interface of the same physical device (matched by VID/PID and shared serial number, see previous commit) instead of generating a new one. Signed-off-by: Sanskar Jaiswal <phoenix2810@protonmail.com> --- dlls/winebus.sys/main.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 3efc17baf21..7988374e48f 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -381,6 +381,24 @@ static void make_unique_container_id(struct device_extension *device) struct device_extension *ext; LARGE_INTEGER ticks; + /* + * If a sibling interface of the same physical device (same VID/PID and + * serial number, different interface index) was already added, reuse its + * container id instead of generating a new one. + */ + if (*device->desc.serialnumber) + { + LIST_FOR_EACH_ENTRY(ext, &device_list, struct device_extension, entry) + if (ext->desc.vid == device->desc.vid && ext->desc.pid == device->desc.pid && + ext->desc.input != device->desc.input && + !wcscmp(ext->desc.serialnumber, device->desc.serialnumber) && + !IsEqualGUID(&ext->container_id, &GUID_NULL)) + { + device->container_id = ext->container_id; + return; + } + } + 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; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11745
participants (2)
-
Sanskar Jaiswal -
Sanskar Jaiswal (@sanskarjaiswal2001)