mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-31 19:49:50 +00:00
wineusb.sys: Create separate unix devices for each interface.
This commit is contained in:
parent
c698dc6e36
commit
b41fe10fd4
3 changed files with 72 additions and 83 deletions
|
@ -40,6 +40,15 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(wineusb);
|
WINE_DEFAULT_DEBUG_CHANNEL(wineusb);
|
||||||
|
|
||||||
|
struct unix_device
|
||||||
|
{
|
||||||
|
struct list entry;
|
||||||
|
|
||||||
|
libusb_device_handle *handle;
|
||||||
|
|
||||||
|
bool interface;
|
||||||
|
};
|
||||||
|
|
||||||
static libusb_hotplug_callback_handle hotplug_cb_handle;
|
static libusb_hotplug_callback_handle hotplug_cb_handle;
|
||||||
|
|
||||||
static bool thread_shutdown;
|
static bool thread_shutdown;
|
||||||
|
@ -109,6 +118,7 @@ static NTSTATUS usb_get_event(void *args)
|
||||||
|
|
||||||
static void add_usb_device(libusb_device *libusb_device)
|
static void add_usb_device(libusb_device *libusb_device)
|
||||||
{
|
{
|
||||||
|
struct libusb_config_descriptor *config_desc;
|
||||||
struct libusb_device_descriptor device_desc;
|
struct libusb_device_descriptor device_desc;
|
||||||
struct unix_device *unix_device;
|
struct unix_device *unix_device;
|
||||||
struct usb_event usb_event;
|
struct usb_event usb_event;
|
||||||
|
@ -128,6 +138,8 @@ static void add_usb_device(libusb_device *libusb_device)
|
||||||
free(unix_device);
|
free(unix_device);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
unix_device->interface = false;
|
||||||
|
|
||||||
pthread_mutex_lock(&device_mutex);
|
pthread_mutex_lock(&device_mutex);
|
||||||
list_add_tail(&device_list, &unix_device->entry);
|
list_add_tail(&device_list, &unix_device->entry);
|
||||||
pthread_mutex_unlock(&device_mutex);
|
pthread_mutex_unlock(&device_mutex);
|
||||||
|
@ -140,7 +152,60 @@ static void add_usb_device(libusb_device *libusb_device)
|
||||||
usb_event.u.added_device.class = device_desc.bDeviceClass;
|
usb_event.u.added_device.class = device_desc.bDeviceClass;
|
||||||
usb_event.u.added_device.subclass = device_desc.bDeviceSubClass;
|
usb_event.u.added_device.subclass = device_desc.bDeviceSubClass;
|
||||||
usb_event.u.added_device.protocol = device_desc.bDeviceProtocol;
|
usb_event.u.added_device.protocol = device_desc.bDeviceProtocol;
|
||||||
|
usb_event.u.added_device.interface = false;
|
||||||
queue_event(&usb_event);
|
queue_event(&usb_event);
|
||||||
|
|
||||||
|
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];
|
||||||
|
const struct libusb_interface_descriptor *iface_desc;
|
||||||
|
struct unix_device *unix_iface;
|
||||||
|
|
||||||
|
if (interface->num_altsetting != 1)
|
||||||
|
FIXME("Interface %u has %u alternate settings; using the first one.\n",
|
||||||
|
i, interface->num_altsetting);
|
||||||
|
iface_desc = &interface->altsetting[0];
|
||||||
|
|
||||||
|
if (!(unix_iface = calloc(1, sizeof(*unix_iface))))
|
||||||
|
return;
|
||||||
|
|
||||||
|
unix_iface->handle = unix_device->handle;
|
||||||
|
unix_iface->interface = true;
|
||||||
|
pthread_mutex_lock(&device_mutex);
|
||||||
|
list_add_tail(&device_list, &unix_iface->entry);
|
||||||
|
pthread_mutex_unlock(&device_mutex);
|
||||||
|
|
||||||
|
usb_event.u.added_device.device = unix_iface;
|
||||||
|
usb_event.u.added_device.class = iface_desc->bInterfaceClass;
|
||||||
|
usb_event.u.added_device.subclass = iface_desc->bInterfaceSubClass;
|
||||||
|
usb_event.u.added_device.protocol = iface_desc->bInterfaceProtocol;
|
||||||
|
usb_event.u.added_device.interface = true;
|
||||||
|
usb_event.u.added_device.interface_index = iface_desc->bInterfaceNumber;
|
||||||
|
queue_event(&usb_event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
libusb_free_config_descriptor(config_desc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERR("Failed to get configuration descriptor: %s\n", libusb_strerror(ret));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_usb_device(libusb_device *libusb_device)
|
static void remove_usb_device(libusb_device *libusb_device)
|
||||||
|
|
|
@ -26,13 +26,6 @@
|
||||||
#include "ddk/wdm.h"
|
#include "ddk/wdm.h"
|
||||||
#include "wine/unixlib.h"
|
#include "wine/unixlib.h"
|
||||||
|
|
||||||
struct unix_device
|
|
||||||
{
|
|
||||||
struct list entry;
|
|
||||||
|
|
||||||
libusb_device_handle *handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum usb_event_type
|
enum usb_event_type
|
||||||
{
|
{
|
||||||
USB_EVENT_ADD_DEVICE,
|
USB_EVENT_ADD_DEVICE,
|
||||||
|
@ -52,6 +45,8 @@ struct usb_event
|
||||||
struct unix_device *device;
|
struct unix_device *device;
|
||||||
UINT16 vendor, product, revision;
|
UINT16 vendor, product, revision;
|
||||||
UINT8 class, subclass, protocol;
|
UINT8 class, subclass, protocol;
|
||||||
|
bool interface;
|
||||||
|
UINT8 interface_index;
|
||||||
} added_device;
|
} added_device;
|
||||||
struct unix_device *removed_device;
|
struct unix_device *removed_device;
|
||||||
IRP *completed_irp;
|
IRP *completed_irp;
|
||||||
|
|
|
@ -79,9 +79,7 @@ struct usb_device
|
||||||
|
|
||||||
DEVICE_OBJECT *device_obj;
|
DEVICE_OBJECT *device_obj;
|
||||||
|
|
||||||
/* Points to the parent USB device if this is a USB interface; otherwise
|
bool interface;
|
||||||
* NULL. */
|
|
||||||
struct usb_device *parent;
|
|
||||||
uint8_t interface_index;
|
uint8_t interface_index;
|
||||||
|
|
||||||
uint8_t class, subclass, protocol;
|
uint8_t class, subclass, protocol;
|
||||||
|
@ -106,49 +104,15 @@ static void destroy_unix_device(struct unix_device *unix_device)
|
||||||
__wine_unix_call(unix_handle, unix_usb_destroy_device, ¶ms);
|
__wine_unix_call(unix_handle, unix_usb_destroy_device, ¶ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
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->unix_device = parent->unix_device;
|
|
||||||
device->interface_index = desc->bInterfaceNumber;
|
|
||||||
device->class = desc->bInterfaceClass;
|
|
||||||
device->subclass = desc->bInterfaceSubClass;
|
|
||||||
device->protocol = desc->bInterfaceProtocol;
|
|
||||||
device->vendor = parent->vendor;
|
|
||||||
device->product = parent->product;
|
|
||||||
device->revision = parent->revision;
|
|
||||||
InitializeListHead(&device->irp_list);
|
|
||||||
|
|
||||||
EnterCriticalSection(&wineusb_cs);
|
|
||||||
list_add_tail(&device_list, &device->entry);
|
|
||||||
LeaveCriticalSection(&wineusb_cs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_unix_device(const struct usb_add_device_event *event)
|
static void add_unix_device(const struct usb_add_device_event *event)
|
||||||
{
|
{
|
||||||
static const WCHAR formatW[] = {'\\','D','e','v','i','c','e','\\','U','S','B','P','D','O','-','%','u',0};
|
static const WCHAR formatW[] = {'\\','D','e','v','i','c','e','\\','U','S','B','P','D','O','-','%','u',0};
|
||||||
libusb_device *libusb_device = libusb_get_device(event->device->handle);
|
|
||||||
struct libusb_config_descriptor *config_desc;
|
|
||||||
static unsigned int name_index;
|
static unsigned int name_index;
|
||||||
struct usb_device *device;
|
struct usb_device *device;
|
||||||
DEVICE_OBJECT *device_obj;
|
DEVICE_OBJECT *device_obj;
|
||||||
UNICODE_STRING string;
|
UNICODE_STRING string;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
WCHAR name[26];
|
WCHAR name[26];
|
||||||
int ret;
|
|
||||||
|
|
||||||
TRACE("Adding new device %p, vendor %04x, product %04x.\n", event->device,
|
TRACE("Adding new device %p, vendor %04x, product %04x.\n", event->device,
|
||||||
event->vendor, event->product);
|
event->vendor, event->product);
|
||||||
|
@ -179,39 +143,6 @@ static void add_unix_device(const struct usb_add_device_event *event)
|
||||||
list_add_tail(&device_list, &device->entry);
|
list_add_tail(&device_list, &device->entry);
|
||||||
LeaveCriticalSection(&wineusb_cs);
|
LeaveCriticalSection(&wineusb_cs);
|
||||||
|
|
||||||
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);
|
IoInvalidateDeviceRelations(bus_pdo, BusRelations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,8 +310,7 @@ static NTSTATUS fdo_pnp(IRP *irp)
|
||||||
LIST_FOR_EACH_ENTRY_SAFE(device, cursor, &device_list, struct usb_device, entry)
|
LIST_FOR_EACH_ENTRY_SAFE(device, cursor, &device_list, struct usb_device, entry)
|
||||||
{
|
{
|
||||||
assert(!device->removed);
|
assert(!device->removed);
|
||||||
if (!device->parent)
|
destroy_unix_device(device->unix_device);
|
||||||
destroy_unix_device(device->unix_device);
|
|
||||||
list_remove(&device->entry);
|
list_remove(&device->entry);
|
||||||
IoDeleteDevice(device->device_obj);
|
IoDeleteDevice(device->device_obj);
|
||||||
}
|
}
|
||||||
|
@ -445,7 +375,7 @@ static void get_device_id(const struct usb_device *device, struct string_buffer
|
||||||
static const WCHAR formatW[] = {'U','S','B','\\','V','I','D','_','%','0','4','X',
|
static const WCHAR formatW[] = {'U','S','B','\\','V','I','D','_','%','0','4','X',
|
||||||
'&','P','I','D','_','%','0','4','X',0};
|
'&','P','I','D','_','%','0','4','X',0};
|
||||||
|
|
||||||
if (device->parent)
|
if (device->interface)
|
||||||
append_id(buffer, interface_formatW, device->vendor, device->product, device->interface_index);
|
append_id(buffer, interface_formatW, device->vendor, device->product, device->interface_index);
|
||||||
else
|
else
|
||||||
append_id(buffer, formatW, device->vendor, device->product);
|
append_id(buffer, formatW, device->vendor, device->product);
|
||||||
|
@ -458,7 +388,7 @@ static void get_hardware_ids(const struct usb_device *device, struct string_buff
|
||||||
static const WCHAR formatW[] = {'U','S','B','\\','V','I','D','_','%','0','4','X',
|
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};
|
'&','P','I','D','_','%','0','4','X','&','R','E','V','_','%','0','4','X',0};
|
||||||
|
|
||||||
if (device->parent)
|
if (device->interface)
|
||||||
append_id(buffer, interface_formatW, device->vendor, device->product, device->revision, device->interface_index);
|
append_id(buffer, interface_formatW, device->vendor, device->product, device->revision, device->interface_index);
|
||||||
else
|
else
|
||||||
append_id(buffer, formatW, device->vendor, device->product, device->revision);
|
append_id(buffer, formatW, device->vendor, device->product, device->revision);
|
||||||
|
@ -576,8 +506,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp)
|
||||||
assert(device->removed);
|
assert(device->removed);
|
||||||
remove_pending_irps(device);
|
remove_pending_irps(device);
|
||||||
|
|
||||||
if (!device->parent)
|
destroy_unix_device(device->unix_device);
|
||||||
destroy_unix_device(device->unix_device);
|
|
||||||
|
|
||||||
IoDeleteDevice(device->device_obj);
|
IoDeleteDevice(device->device_obj);
|
||||||
ret = STATUS_SUCCESS;
|
ret = STATUS_SUCCESS;
|
||||||
|
|
Loading…
Reference in a new issue