Windows: Rework WinUSB enumeration process to fix issues on Win8+

As they sometimes do, Microsoft made changes to the way in which the
SetupAPI functions list the devices returned by SetupDiGetClassDevs().
In particular, composite devices started returning their interfaces
before the parent device, which caused some issues with the way the
enumeration logic was assigning things. For composite devices, it
appears that the first interface behaves much like the parent device in
some regards, so the library was creating a device specifically for the
first interface and then again when the actual parent device was
encountered. This caused composite devices to appear in the device list
twice, with the first instance being unusable for most operations.

This commit significantly changes the way in which the enumeration
process is done. Previously we would scan for HCDs, hubs, and generic
devices, in that order and in distinct passes (obtaining a new listing
of devices from SetupAPI). Now we will obtain a single snapshot at the
beginning of the enumeration process and iterate through this to scan
for each type of device.

With a single snapshot, we can be assured that the device instance
handle will not change between passes and thus we can use this as the
unique identifier. This completely removes the need to hash the device
instance ID to obtain a unique identifier and simplifies the process.

The previous enumeration process also created "dummy" libusb_device
instances for the HCDs that were never exposed to the user. This has
been removed in favor of identifying which of the encountered hubs are
actually root hubs.

Finally, the query for the port number has been moved to the GENeric
pass at the point where the devices are actually initialized. This query
operation has been relaxed to allow failure, since some virtual USB
devices don't properly implement this query in their drivers.

Closes #215, Closes #251, Closes #257, Closes #288

Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
This commit is contained in:
Chris Dickens
2018-01-04 16:37:09 -08:00
parent 839235a0b4
commit 71a779d078
3 changed files with 335 additions and 342 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -196,14 +196,17 @@ struct hid_device_priv {
}; };
struct windows_device_priv { struct windows_device_priv {
uint8_t depth; // distance to HCD bool initialized;
bool root_hub;
uint8_t active_config; uint8_t active_config;
struct windows_usb_api_backend const *apib; uint8_t depth;
const struct windows_usb_api_backend *apib;
char *dev_id;
char *path; // device interface path char *path; // device interface path
int sub_api; // for WinUSB-like APIs int sub_api; // for WinUSB-like APIs
struct { struct {
char *path; // each interface needs a device interface path, char *path; // each interface needs a device interface path,
struct windows_usb_api_backend const *apib; // an API backend (multiple drivers support), const struct windows_usb_api_backend *apib; // an API backend (multiple drivers support),
int sub_api; int sub_api;
int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS) int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
uint8_t *endpoint; uint8_t *endpoint;
@@ -212,7 +215,7 @@ struct windows_device_priv {
} usb_interface[USB_MAXINTERFACES]; } usb_interface[USB_MAXINTERFACES];
struct hid_device_priv *hid; struct hid_device_priv *hid;
USB_DEVICE_DESCRIPTOR dev_descriptor; USB_DEVICE_DESCRIPTOR dev_descriptor;
unsigned char **config_descriptor; // list of pointers to the cached config descriptors PUSB_CONFIGURATION_DESCRIPTOR *config_descriptor; // list of pointers to the cached config descriptors
}; };
static inline struct windows_device_priv *_device_priv(struct libusb_device *dev) static inline struct windows_device_priv *_device_priv(struct libusb_device *dev)
@@ -240,6 +243,7 @@ static inline void windows_device_priv_release(struct libusb_device *dev)
struct windows_device_priv *p = _device_priv(dev); struct windows_device_priv *p = _device_priv(dev);
int i; int i;
free(p->dev_id);
free(p->path); free(p->path);
if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) { if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) {
for (i = 0; i < dev->num_configurations; i++) for (i = 0; i < dev->num_configurations; i++)
@@ -296,11 +300,10 @@ typedef RETURN_TYPE CONFIGRET;
#define CR_SUCCESS 0x00000000 #define CR_SUCCESS 0x00000000
/* Cfgmgr32.dll interface */ /* Cfgmgr32 dependencies */
DLL_DECLARE_HANDLE(Cfgmgr32); DLL_DECLARE_HANDLE(Cfgmgr32);
DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG)); DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG));
DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG)); DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG));
DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG));
/* AdvAPI32 dependencies */ /* AdvAPI32 dependencies */
DLL_DECLARE_HANDLE(AdvAPI32); DLL_DECLARE_HANDLE(AdvAPI32);
@@ -322,6 +325,8 @@ DLL_DECLARE_FUNC_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (LPCGUID, P
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA)); DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA, DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA,
LPCGUID, DWORD, PSP_DEVICE_INTERFACE_DATA)); LPCGUID, DWORD, PSP_DEVICE_INTERFACE_DATA));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInstanceIdA, (HDEVINFO, PSP_DEVINFO_DATA,
PCSTR, DWORD, PDWORD));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA,
PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA)); PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA));
DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO, DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO,

View File

@@ -1 +1 @@
#define LIBUSB_NANO 11254 #define LIBUSB_NANO 11255