Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/wineusb.sys/wineusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index 976aa9ca189..e816e0d8c6b 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -486,7 +486,7 @@ static NTSTATUS usbd_status_from_libusb(enum libusb_transfer_status status) } }
-static void transfer_cb(struct libusb_transfer *transfer) +static void LIBUSB_CALL transfer_cb(struct libusb_transfer *transfer) { IRP *irp = transfer->user_data; URB *urb = IoGetCurrentIrpStackLocation(irp)->Parameters.Others.Argument1;
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/wineusb.sys/wineusb.c | 83 ++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 25 deletions(-)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index e816e0d8c6b..3c98c2eb92c 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -303,30 +303,66 @@ static NTSTATUS fdo_pnp(IRP *irp) return IoCallDriver(bus_pdo, irp); }
-static void get_device_id(const struct usb_device *device, WCHAR *buffer) +struct string_buffer +{ + WCHAR *string; + size_t len; +}; + +static void WINAPIV append_id(struct string_buffer *buffer, const WCHAR *format, ...) +{ + __ms_va_list args; + WCHAR *string; + int len; + + __ms_va_start(args, format); + + len = _vsnwprintf(NULL, 0, format, args) + 1; + if (!(string = ExAllocatePool(PagedPool, (buffer->len + len) * sizeof(WCHAR)))) + { + if (buffer->string) + ExFreePool(buffer->string); + buffer->string = NULL; + return; + } + if (buffer->string) + { + memcpy(string, buffer->string, buffer->len * sizeof(WCHAR)); + ExFreePool(buffer->string); + } + _vsnwprintf(string + buffer->len, len, format, args); + buffer->string = string; + buffer->len += len; + + __ms_va_end(args); +} + +static const WCHAR emptyW[] = {0}; + +static void get_device_id(const struct usb_device *device, struct string_buffer *buffer) { static const WCHAR formatW[] = {'U','S','B','\','V','I','D','_','%','0','4','X', '&','P','I','D','_','%','0','4','X',0}; struct libusb_device_descriptor desc;
libusb_get_device_descriptor(device->libusb_device, &desc); - sprintfW(buffer, formatW, desc.idVendor, desc.idProduct); + append_id(buffer, formatW, desc.idVendor, desc.idProduct); }
-static void get_hardware_ids(const struct usb_device *device, WCHAR *buffer) +static void get_hardware_ids(const struct usb_device *device, struct string_buffer *buffer) { static const WCHAR formatW[] = {'U','S','B','\','V','I','D','_','%','0','4','X', '&','P','I','D','_','%','0','4','X','&','R','E','V','_','%','0','4','X',0}; struct libusb_device_descriptor desc;
libusb_get_device_descriptor(device->libusb_device, &desc); - buffer += sprintfW(buffer, formatW, desc.idVendor, desc.idProduct, desc.bcdDevice) + 1; + + append_id(buffer, formatW, desc.idVendor, desc.idProduct, desc.bcdDevice); get_device_id(device, buffer); - buffer += strlenW(buffer) + 1; - *buffer = 0; + append_id(buffer, emptyW); }
-static void get_compatible_ids(const struct usb_device *device, WCHAR *buffer) +static void get_compatible_ids(const struct usb_device *device, struct string_buffer *buffer) { static const WCHAR prot_format[] = {'U','S','B','\','C','l','a','s','s','_','%','0','2','x', '&','S','u','b','C','l','a','s','s','_','%','0','2','x', @@ -339,40 +375,34 @@ static void get_compatible_ids(const struct usb_device *device, WCHAR *buffer)
libusb_get_device_descriptor(device->libusb_device, &device_desc);
- buffer += sprintfW(buffer, prot_format, device_desc.bDeviceClass, device_desc.bDeviceSubClass, - device_desc.bDeviceProtocol) + 1; - buffer += sprintfW(buffer, subclass_format, device_desc.bDeviceClass, device_desc.bDeviceSubClass) + 1; - buffer += sprintfW(buffer, class_format, device_desc.bDeviceClass) + 1; - *buffer = 0; + append_id(buffer, prot_format, device_desc.bDeviceClass, + device_desc.bDeviceSubClass, device_desc.bDeviceProtocol); + append_id(buffer, subclass_format, device_desc.bDeviceClass, device_desc.bDeviceSubClass); + append_id(buffer, class_format, device_desc.bDeviceClass); + append_id(buffer, emptyW); }
static NTSTATUS query_id(const struct usb_device *device, IRP *irp, BUS_QUERY_ID_TYPE type) { - WCHAR *id = NULL; + static const WCHAR instance_idW[] = {'0',0}; + struct string_buffer buffer = {0};
switch (type) { case BusQueryDeviceID: - if ((id = ExAllocatePool(PagedPool, 28 * sizeof(WCHAR)))) - get_device_id(device, id); + get_device_id(device, &buffer); break;
case BusQueryInstanceID: - if ((id = ExAllocatePool(PagedPool, 2 * sizeof(WCHAR)))) - { - id[0] = '0'; - id[1] = 0; - } + append_id(&buffer, instance_idW); break;
case BusQueryHardwareIDs: - if ((id = ExAllocatePool(PagedPool, (28 + 37 + 1) * sizeof(WCHAR)))) - get_hardware_ids(device, id); + get_hardware_ids(device, &buffer); break;
case BusQueryCompatibleIDs: - if ((id = ExAllocatePool(PagedPool, (33 + 25 + 13 + 1) * sizeof(WCHAR)))) - get_compatible_ids(device, id); + get_compatible_ids(device, &buffer); break;
default: @@ -380,7 +410,10 @@ static NTSTATUS query_id(const struct usb_device *device, IRP *irp, BUS_QUERY_ID return irp->IoStatus.Status; }
- irp->IoStatus.Information = (ULONG_PTR)id; + if (!buffer.string) + return STATUS_NO_MEMORY; + + irp->IoStatus.Information = (ULONG_PTR)buffer.string; return STATUS_SUCCESS; }
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/wineusb.sys/wineusb.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index 3c98c2eb92c..53b62c50c60 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -387,6 +387,8 @@ static NTSTATUS query_id(const struct usb_device *device, IRP *irp, BUS_QUERY_ID static const WCHAR instance_idW[] = {'0',0}; struct string_buffer buffer = {0};
+ TRACE("type %#x.\n", type); + switch (type) { case BusQueryDeviceID:
From: Zebediah Figura z.figura12@gmail.com
On Windows this is the job of usbccgp.sys, a separate driver that layers on top of the base USB driver. While we could take this approach as well, implementing usbccgp is a lot more work, whereas interface support is effectively built into libusb.
This patch helps us get closer to installing and running the Hauppauge cx231xx drivers.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/wineusb.sys/wineusb.c | 115 ++++++++++++++++++++++++++++++++----- 1 file changed, 100 insertions(+), 15 deletions(-)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index 53b62c50c60..30e2309c4eb 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -73,6 +73,13 @@ struct usb_device
DEVICE_OBJECT *device_obj;
+ /* Points to the parent USB device if this is a USB interface; otherwise + * NULL. */ + struct usb_device *parent; + uint8_t interface_index; + + uint8_t class, subclass, protocol; + libusb_device *libusb_device; libusb_device_handle *handle;
@@ -84,9 +91,39 @@ static DEVICE_OBJECT *bus_fdo, *bus_pdo;
static libusb_hotplug_callback_handle hotplug_cb_handle;
+static void add_usb_interface(struct usb_device *parent, const struct libusb_interface_descriptor *desc) +{ + struct usb_device *device; + DEVICE_OBJECT *device_obj; + NTSTATUS status; + + if ((status = IoCreateDevice(driver_obj, sizeof(*device), NULL, + FILE_DEVICE_USB, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &device_obj))) + { + ERR("Failed to create device, status %#x.\n", status); + return; + } + + device = device_obj->DeviceExtension; + device->device_obj = device_obj; + device->parent = parent; + device->handle = parent->handle; + device->libusb_device = parent->libusb_device; + device->interface_index = desc->bInterfaceNumber; + device->class = desc->bInterfaceClass; + device->subclass = desc->bInterfaceSubClass; + device->protocol = desc->bInterfaceProtocol; + InitializeListHead(&device->irp_list); + + EnterCriticalSection(&wineusb_cs); + list_add_tail(&device_list, &device->entry); + LeaveCriticalSection(&wineusb_cs); +} + static void add_usb_device(libusb_device *libusb_device) { static const WCHAR formatW[] = {'\','D','e','v','i','c','e','\','U','S','B','P','D','O','-','%','u',0}; + struct libusb_config_descriptor *config_desc; struct libusb_device_descriptor device_desc; static unsigned int name_index; libusb_device_handle *handle; @@ -132,6 +169,43 @@ static void add_usb_device(libusb_device *libusb_device) device->removed = FALSE; LeaveCriticalSection(&wineusb_cs);
+ device->class = device_desc.bDeviceClass; + device->subclass = device_desc.bDeviceSubClass; + device->protocol = device_desc.bDeviceProtocol; + + if (!(ret = libusb_get_active_config_descriptor(libusb_device, &config_desc))) + { + /* Create new devices for interfaces of composite devices. + * + * On Windows this is the job of usbccgp.sys, a separate driver that + * layers on top of the base USB driver. While we could take this + * approach as well, implementing usbccgp is a lot more work, whereas + * interface support is effectively built into libusb. + * + * FIXME: usbccgp does not create separate interfaces in some cases, + * e.g. when there is an interface association descriptor available. + */ + if (config_desc->bNumInterfaces > 1) + { + uint8_t i; + + for (i = 0; i < config_desc->bNumInterfaces; ++i) + { + const struct libusb_interface *interface = &config_desc->interface[i]; + + if (interface->num_altsetting != 1) + FIXME("Interface %u has %u alternate settings; using the first one.\n", + i, interface->num_altsetting); + add_usb_interface(device, &interface->altsetting[0]); + } + } + libusb_free_config_descriptor(config_desc); + } + else + { + ERR("Failed to get configuration descriptor: %s\n", libusb_strerror(ret)); + } + IoInvalidateDeviceRelations(bus_pdo, BusRelations); }
@@ -280,8 +354,11 @@ static NTSTATUS fdo_pnp(IRP *irp) LIST_FOR_EACH_ENTRY_SAFE(device, cursor, &device_list, struct usb_device, entry) { assert(!device->removed); - libusb_unref_device(device->libusb_device); - libusb_close(device->handle); + if (!device->parent) + { + libusb_unref_device(device->libusb_device); + libusb_close(device->handle); + } list_remove(&device->entry); IoDeleteDevice(device->device_obj); } @@ -341,23 +418,33 @@ static const WCHAR emptyW[] = {0};
static void get_device_id(const struct usb_device *device, struct string_buffer *buffer) { + static const WCHAR interface_formatW[] = {'U','S','B','\','V','I','D','_','%','0','4','X', + '&','P','I','D','_','%','0','4','X','&','M','I','_','%','0','2','X',0}; static const WCHAR formatW[] = {'U','S','B','\','V','I','D','_','%','0','4','X', '&','P','I','D','_','%','0','4','X',0}; struct libusb_device_descriptor desc;
libusb_get_device_descriptor(device->libusb_device, &desc); - append_id(buffer, formatW, desc.idVendor, desc.idProduct); + if (device->parent) + append_id(buffer, interface_formatW, desc.idVendor, desc.idProduct, device->interface_index); + else + append_id(buffer, formatW, desc.idVendor, desc.idProduct); }
static void get_hardware_ids(const struct usb_device *device, struct string_buffer *buffer) { + static const WCHAR interface_formatW[] = {'U','S','B','\','V','I','D','_','%','0','4','X', + '&','P','I','D','_','%','0','4','X','&','R','E','V','_','%','0','4','X','&','M','I','_','%','0','2','X',0}; static const WCHAR formatW[] = {'U','S','B','\','V','I','D','_','%','0','4','X', '&','P','I','D','_','%','0','4','X','&','R','E','V','_','%','0','4','X',0}; struct libusb_device_descriptor desc;
libusb_get_device_descriptor(device->libusb_device, &desc);
- append_id(buffer, formatW, desc.idVendor, desc.idProduct, desc.bcdDevice); + if (device->parent) + append_id(buffer, interface_formatW, desc.idVendor, desc.idProduct, desc.bcdDevice, device->interface_index); + else + append_id(buffer, formatW, desc.idVendor, desc.idProduct, desc.bcdDevice); get_device_id(device, buffer); append_id(buffer, emptyW); } @@ -371,18 +458,13 @@ static void get_compatible_ids(const struct usb_device *device, struct string_bu '&','S','u','b','C','l','a','s','s','_','%','0','2','x',0}; static const WCHAR class_format[] = {'U','S','B','\','C','l','a','s','s','_','%','0','2','x',0};
- struct libusb_device_descriptor device_desc; - - libusb_get_device_descriptor(device->libusb_device, &device_desc); - - append_id(buffer, prot_format, device_desc.bDeviceClass, - device_desc.bDeviceSubClass, device_desc.bDeviceProtocol); - append_id(buffer, subclass_format, device_desc.bDeviceClass, device_desc.bDeviceSubClass); - append_id(buffer, class_format, device_desc.bDeviceClass); + append_id(buffer, prot_format, device->class, device->subclass, device->protocol); + append_id(buffer, subclass_format, device->class, device->subclass); + append_id(buffer, class_format, device->class); append_id(buffer, emptyW); }
-static NTSTATUS query_id(const struct usb_device *device, IRP *irp, BUS_QUERY_ID_TYPE type) +static NTSTATUS query_id(struct usb_device *device, IRP *irp, BUS_QUERY_ID_TYPE type) { static const WCHAR instance_idW[] = {'0',0}; struct string_buffer buffer = {0}; @@ -477,8 +559,11 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp) assert(device->removed); remove_pending_irps(device);
- libusb_unref_device(device->libusb_device); - libusb_close(device->handle); + if (!device->parent) + { + libusb_unref_device(device->libusb_device); + libusb_close(device->handle); + }
IoDeleteDevice(device->device_obj); ret = STATUS_SUCCESS;