File 0001-Partial-implementation-for-BusQueryContainerId.patch of Package wine
From 4ebba13fe53a9732dea2b0fb6ddb832196953861 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Br=C3=BCns?= <stefan.bruens@rwth-aachen.de>
Date: Tue, 7 Jan 2025 19:42:27 +0100
Subject: [PATCH 1/7] Partial implementation for BusQueryContainerId
For devices implementing the ContainerID BOS the returned value will
be correct, and matching the Windows implementation.
The remaining cases have some implementation issues:
- Non-removable devices (e.g. laptop internal or multifunction devices)
report distinct IDs instead of the ID of the containing parent
- Serial number based IDs are not hashed correctly, missing both the
actual hashing and the (unknown) USB namespace
- Random IDs are not random but deterministic, although they are likely
at least unique
---
dlls/wineusb.sys/unixlib.c | 35 +++++++++++++++++++++++++
dlls/wineusb.sys/unixlib.h | 2 ++
dlls/wineusb.sys/wineusb.c | 53 ++++++++++++++++++++++++++++++++++++++
3 files changed, 90 insertions(+)
diff --git a/dlls/wineusb.sys/unixlib.c b/dlls/wineusb.sys/unixlib.c
index a42482657b2..4c4e072c189 100644
--- a/dlls/wineusb.sys/unixlib.c
+++ b/dlls/wineusb.sys/unixlib.c
@@ -148,6 +148,41 @@ static void add_usb_device(libusb_device *libusb_device)
usb_event.u.added_device.interface = false;
usb_event.u.added_device.interface_index = -1;
+ memset(usb_event.u.added_device.container_id, 0, sizeof(usb_event.u.added_device.container_id));
+ if (device_desc.bcdUSB >= 0x201) {
+ struct libusb_bos_descriptor *bos_desc;
+ struct libusb_bos_dev_capability_descriptor *cid_cap = NULL;
+
+ if (libusb_get_bos_descriptor(unix_device->handle, &bos_desc) == LIBUSB_SUCCESS)
+ {
+ for (int i = 0; i < bos_desc->bNumDeviceCaps; i++)
+ {
+ if (bos_desc->dev_capability[i]->bDevCapabilityType == LIBUSB_BT_CONTAINER_ID)
+ {
+ cid_cap = bos_desc->dev_capability[i];
+ }
+ }
+ }
+
+ if (cid_cap)
+ {
+ struct libusb_container_id_descriptor *container_id = NULL;
+ libusb_get_container_id_descriptor(NULL, cid_cap, &container_id);
+ if (container_id)
+ {
+ memcpy(usb_event.u.added_device.container_id, container_id->ContainerID, sizeof(usb_event.u.added_device.container_id));
+ }
+ libusb_free_container_id_descriptor(container_id);
+ }
+ libusb_free_bos_descriptor(bos_desc);
+ }
+
+ usb_event.u.added_device.serial[0] = '\0';
+ if (device_desc.iSerialNumber > 0) {
+ libusb_get_string_descriptor_ascii(unix_device->handle, device_desc.iSerialNumber,
+ usb_event.u.added_device.serial, sizeof(usb_event.u.added_device.serial));
+ }
+
if (!(ret = libusb_get_active_config_descriptor(libusb_device, &config_desc)))
{
const struct libusb_interface *interface;
diff --git a/dlls/wineusb.sys/unixlib.h b/dlls/wineusb.sys/unixlib.h
index 33469f5a2b5..4b72c7afb94 100644
--- a/dlls/wineusb.sys/unixlib.h
+++ b/dlls/wineusb.sys/unixlib.h
@@ -46,6 +46,8 @@ struct usb_event
UINT8 class, subclass, protocol, busnum, portnum;
bool interface;
INT16 interface_index;
+ unsigned char serial[33];
+ unsigned char container_id[16];
} added_device;
struct unix_device *removed_device;
IRP *completed_irp;
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c
index 05603de1377..e2b0f65da8a 100644
--- a/dlls/wineusb.sys/wineusb.c
+++ b/dlls/wineusb.sys/wineusb.c
@@ -84,6 +84,10 @@ struct usb_device
struct unix_device *unix_device;
+ unsigned char serial[33];
+
+ unsigned char container_id[16];
+
LIST_ENTRY irp_list;
};
@@ -141,6 +145,9 @@ static void add_unix_device(const struct usb_add_device_event *event)
device->revision = event->revision;
device->usbver = event->usbver;
+ memcpy(device->serial, event->serial, sizeof(device->serial));
+ memcpy(device->container_id, event->container_id, sizeof(device->container_id));
+
EnterCriticalSection(&wineusb_cs);
list_add_tail(&device_list, &device->entry);
LeaveCriticalSection(&wineusb_cs);
@@ -403,6 +410,48 @@ static void get_compatible_ids(const struct usb_device *device, struct string_bu
append_id(buffer, L"");
}
+static void get_serial_number(const struct usb_device *device, struct string_buffer *buffer)
+{
+ if (device->serial[0] != '\0') {
+ append_id(buffer, L"%s", device->serial);
+ }
+}
+
+static void get_container_id(const struct usb_device *device, struct string_buffer *buffer, IRP *irp)
+{
+ GUID guid;
+
+ memset(&guid, 0, sizeof(guid));
+
+ if (memcmp(device->container_id, &guid, sizeof(guid)) != 0)
+ {
+ memcpy(&guid, device->container_id, sizeof(guid));
+ }
+ /* FIXME if the device is not removable, use the ContainerId of its parent */
+ else if (device->serial[0] != '\0')
+ {
+ /* Create temporary, unique string */
+ char s[45];
+ int len = snprintf(s, sizeof(s), "%0.32s%04%04X%04X", device->serial, device->vendor,
+ device->product, device->revision);
+ /* FIXME Should be UUIDv5 (SHA-1) hash, using a USB specific namespace */
+ memcpy(&guid, s, len > sizeof(guid) ? sizeof(guid) : len);
+ }
+ else
+ {
+ /* FIXME Should create a random ContainerId */
+ guid.Data1 = (device->vendor << 16) + device->product;
+ guid.Data2 = device->revision;
+ guid.Data4[0] = device->busnum;
+ guid.Data4[1] = device->portnum;
+ }
+
+ append_id(buffer, L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
+ (unsigned int)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] );
+}
+
static NTSTATUS query_id(struct usb_device *device, IRP *irp, BUS_QUERY_ID_TYPE type)
{
struct string_buffer buffer = {0};
@@ -427,6 +476,10 @@ static NTSTATUS query_id(struct usb_device *device, IRP *irp, BUS_QUERY_ID_TYPE
get_compatible_ids(device, &buffer);
break;
+ case BusQueryContainerID:
+ get_container_id(device, &buffer, irp);
+ break;
+
default:
FIXME("Unhandled ID query type %#x.\n", type);
return irp->IoStatus.Status;
--
2.49.0