[PATCH v2 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> -- v2: winebus.sys: Share the container id across a composite device's interfaces. winebus.sys: Do not rewrite the serial number of sibling HID interfaces. winebus.sys: Advertise a USB compatible id for USB devices. hidclass.sys: Include the device id in the hardware ids list. 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 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index c5d47994d3f..6edf15ef2be 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -258,8 +258,9 @@ 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; - WCHAR usb_compat[71]; + WCHAR usb_compat[93]; DWORD usb_len = 0, size; WCHAR *dst, *pos; @@ -281,6 +282,10 @@ static WCHAR *get_compatible_ids(DEVICE_OBJECT *device) L"USB\\Class_%02x", class) + 1; } + if (ext->desc.bus_type == BUS_TYPE_USB) + usb_len += swprintf(usb_compat + usb_len, ARRAY_SIZE(usb_compat) - usb_len, + usb_compat_format, ext->desc.vid, ext->desc.pid) + 1; + size = sizeof(hid_compat) + usb_len * sizeof(WCHAR); if (ext->desc.is_gamepad) size += sizeof(xinput_compat); -- 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 6edf15ef2be..d63de44f1ce 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -373,6 +373,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 d63de44f1ce..91fbdd987db 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -394,6 +394,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)