diff options
Diffstat (limited to 'libusb/os/windows_winusb.c')
-rw-r--r-- | libusb/os/windows_winusb.c | 475 |
1 files changed, 294 insertions, 181 deletions
diff --git a/libusb/os/windows_winusb.c b/libusb/os/windows_winusb.c index f291b8e..ffc1612 100644 --- a/libusb/os/windows_winusb.c +++ b/libusb/os/windows_winusb.c @@ -28,14 +28,9 @@ #include <windows.h> #include <setupapi.h> #include <ctype.h> -#include <fcntl.h> -#include <process.h> #include <stdio.h> -#include <objbase.h> -#include <winioctl.h> #include "libusbi.h" -#include "windows_common.h" #include "windows_winusb.h" #define HANDLE_VALID(h) (((h) != NULL) && ((h) != INVALID_HANDLE_VALUE)) @@ -109,12 +104,12 @@ static struct winusb_interface WinUSBX[SUB_API_MAX]; } while (0) #if defined(ENABLE_LOGGING) -static const char *guid_to_string(const GUID *guid) +static const char *guid_to_string(const GUID *guid, char guid_string[MAX_GUID_STRING_LENGTH]) { - static char guid_string[MAX_GUID_STRING_LENGTH]; - - if (guid == NULL) - return ""; + if (guid == NULL) { + guid_string[0] = '\0'; + return guid_string; + } sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", (unsigned int)guid->Data1, guid->Data2, guid->Data3, @@ -125,6 +120,37 @@ static const char *guid_to_string(const GUID *guid) } #endif +static bool string_to_guid(const char guid_string[MAX_GUID_STRING_LENGTH], GUID *guid) +{ + unsigned short tmp[4]; + int num_chars = -1; + char extra; + int r; + + // Unfortunately MinGW complains that '%hhx' is not a valid format specifier, + // even though Visual Studio 2013 and later support it. Rather than complicating + // the logic in this function with '#ifdef's, use a temporary array on the stack + // to store the conversions. + r = sscanf(guid_string, "{%8x-%4hx-%4hx-%4hx-%4hx%4hx%4hx}%n%c", + (unsigned int *)&guid->Data1, &guid->Data2, &guid->Data3, + &tmp[0], &tmp[1], &tmp[2], &tmp[3], &num_chars, &extra); + + if ((r != 7) || (num_chars != 38)) + return false; + + // Extract the bytes from the 2-byte shorts + guid->Data4[0] = (unsigned char)((tmp[0] >> 8) & 0xFF); + guid->Data4[1] = (unsigned char)(tmp[0] & 0xFF); + guid->Data4[2] = (unsigned char)((tmp[1] >> 8) & 0xFF); + guid->Data4[3] = (unsigned char)(tmp[1] & 0xFF); + guid->Data4[4] = (unsigned char)((tmp[2] >> 8) & 0xFF); + guid->Data4[5] = (unsigned char)(tmp[2] & 0xFF); + guid->Data4[6] = (unsigned char)((tmp[3] >> 8) & 0xFF); + guid->Data4[7] = (unsigned char)(tmp[3] & 0xFF); + + return true; +} + /* * Normalize Microsoft's paths: return a duplicate of the given path * with all characters converted to uppercase @@ -154,12 +180,9 @@ static bool init_dlls(struct libusb_context *ctx) // Prefixed to avoid conflict with header files DLL_GET_HANDLE(ctx, AdvAPI32); - DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExW, true); + DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExA, true); DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, true); - DLL_GET_HANDLE(ctx, OLE32); - DLL_LOAD_FUNC_PREFIXED(OLE32, p, IIDFromString, true); - DLL_GET_HANDLE(ctx, SetupAPI); DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, true); DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, true); @@ -177,7 +200,6 @@ static bool init_dlls(struct libusb_context *ctx) static void exit_dlls(void) { DLL_FREE_HANDLE(SetupAPI); - DLL_FREE_HANDLE(OLE32); DLL_FREE_HANDLE(AdvAPI32); DLL_FREE_HANDLE(Cfgmgr32); } @@ -238,6 +260,7 @@ static int get_interface_details(struct libusb_context *ctx, HDEVINFO dev_info, { SP_DEVICE_INTERFACE_DATA dev_interface_data; PSP_DEVICE_INTERFACE_DETAIL_DATA_A dev_interface_details; + char guid_string[MAX_GUID_STRING_LENGTH]; DWORD size; dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); @@ -246,7 +269,7 @@ static int get_interface_details(struct libusb_context *ctx, HDEVINFO dev_info, if (!pSetupDiEnumDeviceInfo(dev_info, *_index, dev_info_data)) { if (GetLastError() != ERROR_NO_MORE_ITEMS) { usbi_err(ctx, "Could not obtain device info data for %s index %lu: %s", - guid_to_string(guid), ULONG_CAST(*_index), windows_error_str(0)); + guid_to_string(guid, guid_string), ULONG_CAST(*_index), windows_error_str(0)); return LIBUSB_ERROR_OTHER; } @@ -262,7 +285,7 @@ static int get_interface_details(struct libusb_context *ctx, HDEVINFO dev_info, if (GetLastError() != ERROR_NO_MORE_ITEMS) { usbi_err(ctx, "Could not obtain interface data for %s devInst %lX: %s", - guid_to_string(guid), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0)); + guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0)); return LIBUSB_ERROR_OTHER; } @@ -274,7 +297,7 @@ static int get_interface_details(struct libusb_context *ctx, HDEVINFO dev_info, // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { usbi_err(ctx, "could not access interface data (dummy) for %s devInst %lX: %s", - guid_to_string(guid), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0)); + guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0)); return LIBUSB_ERROR_OTHER; } } else { @@ -285,7 +308,7 @@ static int get_interface_details(struct libusb_context *ctx, HDEVINFO dev_info, dev_interface_details = malloc(size); if (dev_interface_details == NULL) { usbi_err(ctx, "could not allocate interface data for %s devInst %lX", - guid_to_string(guid), ULONG_CAST(dev_info_data->DevInst)); + guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst)); return LIBUSB_ERROR_NO_MEM; } @@ -293,7 +316,7 @@ static int get_interface_details(struct libusb_context *ctx, HDEVINFO dev_info, if (!pSetupDiGetDeviceInterfaceDetailA(dev_info, &dev_interface_data, dev_interface_details, size, NULL, NULL)) { usbi_err(ctx, "could not access interface data (actual) for %s devInst %lX: %s", - guid_to_string(guid), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0)); + guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0)); free(dev_interface_details); return LIBUSB_ERROR_OTHER; } @@ -303,7 +326,7 @@ static int get_interface_details(struct libusb_context *ctx, HDEVINFO dev_info, if (*dev_interface_path == NULL) { usbi_err(ctx, "could not allocate interface path for %s devInst %lX", - guid_to_string(guid), ULONG_CAST(dev_info_data->DevInst)); + guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst)); return LIBUSB_ERROR_NO_MEM; } @@ -386,14 +409,14 @@ static int get_interface_details_filter(struct libusb_context *ctx, HDEVINFO *de DWORD value_length = sizeof(DWORD); LONG status; - status = pRegQueryValueExW(hkey_dev_interface, L"LUsb0", NULL, NULL, + status = pRegQueryValueExA(hkey_dev_interface, "LUsb0", NULL, NULL, (LPBYTE)&libusb0_symboliclink_index, &value_length); if (status == ERROR_SUCCESS) { if (libusb0_symboliclink_index < 256) { // libusb0.sys is connected to this device instance. // If the the device interface guid is {F9F3FF14-AE21-48A0-8A25-8011A7A931D9} then it's a filter. sprintf(filter_path, "\\\\.\\libusb0-%04u", (unsigned int)libusb0_symboliclink_index); - usbi_dbg("assigned libusb0 symbolic link %s", filter_path); + usbi_dbg(ctx, "assigned libusb0 symbolic link %s", filter_path); } else { // libusb0.sys was connected to this device instance at one time; but not anymore. } @@ -451,23 +474,23 @@ static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc, intf_desc = &intf->altsetting[j]; for (k = 0; k < intf_desc->bNumEndpoints; k++) { if (intf_desc->endpoint[k].bEndpointAddress == ep) { - usbi_dbg("found endpoint %02X on interface %d", intf_desc->bInterfaceNumber, i); + usbi_dbg(NULL, "found endpoint %02X on interface %d", intf_desc->bInterfaceNumber, i); return intf_desc->bInterfaceNumber; } } } } - usbi_dbg("endpoint %02X not found on any interface", ep); + usbi_dbg(NULL, "endpoint %02X not found on any interface", ep); return LIBUSB_ERROR_NOT_FOUND; } /* * Open a device and associate the HANDLE with the context's I/O completion port */ -static HANDLE windows_open(struct libusb_device *dev, const char *path, DWORD access) +static HANDLE windows_open(struct libusb_device_handle *dev_handle, const char *path, DWORD access) { - struct libusb_context *ctx = DEVICE_CTX(dev); + struct libusb_context *ctx = HANDLE_CTX(dev_handle); struct windows_context_priv *priv = usbi_get_context_priv(ctx); HANDLE handle; @@ -475,7 +498,7 @@ static HANDLE windows_open(struct libusb_device *dev, const char *path, DWORD ac if (handle == INVALID_HANDLE_VALUE) return handle; - if (CreateIoCompletionPort(handle, priv->completion_port, 0, 0) == NULL) { + if (CreateIoCompletionPort(handle, priv->completion_port, (ULONG_PTR)dev_handle, 0) == NULL) { usbi_err(ctx, "failed to associate handle to I/O completion port: %s", windows_error_str(0)); CloseHandle(handle); return INVALID_HANDLE_VALUE; @@ -500,26 +523,26 @@ static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, uin return r; } + if (iface >= conf_desc->bNumInterfaces) { + usbi_err(HANDLE_CTX(dev_handle), "interface %d out of range for device", iface); + return LIBUSB_ERROR_NOT_FOUND; + } if_desc = &conf_desc->interface[iface].altsetting[altsetting]; safe_free(priv->usb_interface[iface].endpoint); if (if_desc->bNumEndpoints == 0) { - usbi_dbg("no endpoints found for interface %u", iface); - libusb_free_config_descriptor(conf_desc); - priv->usb_interface[iface].current_altsetting = altsetting; - return LIBUSB_SUCCESS; - } - - priv->usb_interface[iface].endpoint = malloc(if_desc->bNumEndpoints); - if (priv->usb_interface[iface].endpoint == NULL) { - libusb_free_config_descriptor(conf_desc); - return LIBUSB_ERROR_NO_MEM; - } - - priv->usb_interface[iface].nb_endpoints = if_desc->bNumEndpoints; - for (i = 0; i < if_desc->bNumEndpoints; i++) { - priv->usb_interface[iface].endpoint[i] = if_desc->endpoint[i].bEndpointAddress; - usbi_dbg("(re)assigned endpoint %02X to interface %u", priv->usb_interface[iface].endpoint[i], iface); + usbi_dbg(HANDLE_CTX(dev_handle), "no endpoints found for interface %u", iface); + } else { + priv->usb_interface[iface].endpoint = malloc(if_desc->bNumEndpoints); + if (priv->usb_interface[iface].endpoint == NULL) { + libusb_free_config_descriptor(conf_desc); + return LIBUSB_ERROR_NO_MEM; + } + priv->usb_interface[iface].nb_endpoints = if_desc->bNumEndpoints; + for (i = 0; i < if_desc->bNumEndpoints; i++) { + priv->usb_interface[iface].endpoint[i] = if_desc->endpoint[i].bEndpointAddress; + usbi_dbg(HANDLE_CTX(dev_handle), "(re)assigned endpoint %02X to interface %u", priv->usb_interface[iface].endpoint[i], iface); + } } libusb_free_config_descriptor(conf_desc); @@ -570,7 +593,7 @@ static int get_sub_api(char *driver, int api) static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type) { struct winusb_device_handle_priv *handle_priv = - usbi_get_device_handle_priv(transfer->dev_handle); + get_winusb_device_handle_priv(transfer->dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev); int current_interface = *interface_number; int r = LIBUSB_SUCCESS; @@ -589,7 +612,7 @@ static int auto_claim(struct libusb_transfer *transfer, int *interface_number, i // Must claim an interface of the same API type if ((priv->usb_interface[current_interface].apib->id == api_type) && (libusb_claim_interface(transfer->dev_handle, current_interface) == LIBUSB_SUCCESS)) { - usbi_dbg("auto-claimed interface %d for control request", current_interface); + usbi_dbg(TRANSFER_CTX(transfer), "auto-claimed interface %d for control request", current_interface); if (handle_priv->autoclaim_count[current_interface] != 0) usbi_err(TRANSFER_CTX(transfer), "program assertion failed - autoclaim_count was nonzero"); handle_priv->autoclaim_count[current_interface]++; @@ -617,7 +640,7 @@ static void auto_release(struct usbi_transfer *itransfer) struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); libusb_device_handle *dev_handle = transfer->dev_handle; - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); int r; usbi_mutex_lock(&autoclaim_lock); @@ -626,9 +649,9 @@ static void auto_release(struct usbi_transfer *itransfer) if (handle_priv->autoclaim_count[transfer_priv->interface_number] == 0) { r = libusb_release_interface(dev_handle, transfer_priv->interface_number); if (r == LIBUSB_SUCCESS) - usbi_dbg("auto-released interface %d", transfer_priv->interface_number); + usbi_dbg(ITRANSFER_CTX(itransfer), "auto-released interface %d", transfer_priv->interface_number); else - usbi_dbg("failed to auto-release interface %d (%s)", + usbi_dbg(ITRANSFER_CTX(itransfer), "failed to auto-release interface %d (%s)", transfer_priv->interface_number, libusb_error_name((enum libusb_error)r)); } } @@ -769,7 +792,7 @@ static void cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handl continue; } - usbi_dbg("cached config descriptor %u (bConfigurationValue=%u, %u bytes)", + usbi_dbg(ctx, "cached config descriptor %u (bConfigurationValue=%u, %u bytes)", i, cd_data->bConfigurationValue, cd_data->wTotalLength); // Cache the descriptor @@ -886,7 +909,7 @@ static int init_root_hub(struct libusb_device *dev) } num_ports = hub_info.u.HubInformation.HubDescriptor.bNumberOfPorts; - usbi_dbg("root hub '%s' reports %lu ports", priv->dev_id, ULONG_CAST(num_ports)); + usbi_dbg(ctx, "root hub '%s' reports %lu ports", priv->dev_id, ULONG_CAST(num_ports)); if (windows_version >= WINDOWS_8) { // Windows 8 and later is better at reporting the speed capabilities of the root hub, @@ -1021,7 +1044,7 @@ make_descriptors: static int init_device(struct libusb_device *dev, struct libusb_device *parent_dev, uint8_t port_number, DEVINST devinst) { - struct libusb_context *ctx; + struct libusb_context *ctx = NULL; struct libusb_device *tmp_dev; struct winusb_device_priv *priv, *parent_priv, *tmp_priv; USB_NODE_CONNECTION_INFORMATION_EX conn_info; @@ -1120,7 +1143,7 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d priv->active_config = conn_info.CurrentConfigurationValue; if (priv->active_config == 0) { - usbi_dbg("0x%x:0x%x found %u configurations (not configured)", + usbi_dbg(ctx, "0x%x:0x%x found %u configurations (not configured)", dev->device_descriptor.idVendor, dev->device_descriptor.idProduct, dev->device_descriptor.bNumConfigurations); @@ -1143,7 +1166,7 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d dev->device_descriptor.bNumConfigurations); priv->active_config = 1; } else { - usbi_dbg("found %u configurations (current config: %u)", dev->device_descriptor.bNumConfigurations, priv->active_config); + usbi_dbg(ctx, "found %u configurations (current config: %u)", dev->device_descriptor.bNumConfigurations, priv->active_config); } // Cache as many config descriptors as we can @@ -1194,12 +1217,53 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d priv->initialized = true; - usbi_dbg("(bus: %u, addr: %u, depth: %u, port: %u): '%s'", + usbi_dbg(ctx, "(bus: %u, addr: %u, depth: %u, port: %u): '%s'", dev->bus_number, dev->device_address, priv->depth, dev->port_number, priv->dev_id); return LIBUSB_SUCCESS; } +static bool get_dev_port_number(HDEVINFO dev_info, SP_DEVINFO_DATA *dev_info_data, DWORD *port_nr) +{ + char buffer[MAX_KEY_LENGTH]; + DWORD size; + + // First try SPDRP_LOCATION_INFORMATION, which returns a REG_SZ. The string *may* have a format + // similar to "Port_#0002.Hub_#000D", in which case we can extract the port number. However, we + // cannot extract the port if the returned string does not follow this format. + if (pSetupDiGetDeviceRegistryPropertyA(dev_info, dev_info_data, SPDRP_LOCATION_INFORMATION, + NULL, (PBYTE)buffer, sizeof(buffer), NULL)) { + // Check for the required format. + if (strncmp(buffer, "Port_#", 6) == 0) { + *port_nr = atoi(buffer + 6); + return true; + } + } + + // Next try SPDRP_LOCATION_PATHS, which returns a REG_MULTI_SZ (but we only examine the first + // string in it). Each path has a format similar to, + // "PCIROOT(B2)#PCI(0300)#PCI(0000)#USBROOT(0)#USB(1)#USB(2)#USBMI(3)", and the port number is + // the number within the last "USB(x)" token. + if (pSetupDiGetDeviceRegistryPropertyA(dev_info, dev_info_data, SPDRP_LOCATION_PATHS, + NULL, (PBYTE)buffer, sizeof(buffer), NULL)) { + // Find the last "#USB(x)" substring + for (char *token = strrchr(buffer, '#'); token != NULL; token = strrchr(buffer, '#')) { + if (strncmp(token, "#USB(", 5) == 0) { + *port_nr = atoi(token + 5); + return true; + } + // Shorten the string and try again. + *token = '\0'; + } + } + + // Lastly, try SPDRP_ADDRESS, which returns a REG_DWORD. The address *may* be the port number, + // which is true for the Microsoft driver but may not be true for other drivers. However, we + // have no other options here but to accept what it returns. + return pSetupDiGetDeviceRegistryPropertyA(dev_info, dev_info_data, SPDRP_ADDRESS, + NULL, (PBYTE)port_nr, sizeof(*port_nr), &size) && (size == sizeof(*port_nr)); +} + static int enumerate_hcd_root_hub(struct libusb_context *ctx, const char *dev_id, uint8_t bus_number, DEVINST devinst) { @@ -1222,7 +1286,7 @@ static int enumerate_hcd_root_hub(struct libusb_context *ctx, const char *dev_id if (dev->bus_number == 0) { // Only do this once - usbi_dbg("assigning HCD '%s' bus number %u", dev_id, bus_number); + usbi_dbg(ctx, "assigning HCD '%s' bus number %u", dev_id, bus_number); dev->bus_number = bus_number; if (sscanf(dev_id, "PCI\\VEN_%04hx&DEV_%04hx%*s", &dev->device_descriptor.idVendor, &dev->device_descriptor.idProduct) != 2) @@ -1266,10 +1330,10 @@ static void get_api_type(HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, if (lookup[k].list[l] == 0) lookup[k].list[l] = LIST_SEPARATOR; } - usbi_dbg("%s(s): %s", lookup[k].designation, lookup[k].list); + usbi_dbg(NULL, "%s(s): %s", lookup[k].designation, lookup[k].list); } else { if (GetLastError() != ERROR_INVALID_DATA) - usbi_dbg("could not access %s: %s", lookup[k].designation, windows_error_str(0)); + usbi_dbg(NULL, "could not access %s: %s", lookup[k].designation, windows_error_str(0)); lookup[k].list[0] = 0; } } @@ -1278,7 +1342,7 @@ static void get_api_type(HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, for (k = 0; k < 3; k++) { j = get_sub_api(lookup[k].list, i); if (j >= 0) { - usbi_dbg("matched %s name against %s", lookup[k].designation, + usbi_dbg(NULL, "matched %s name against %s", lookup[k].designation, (i != USB_API_WINUSBX) ? usb_api_backend[i].designation : usb_api_backend[i].driver_name_list[j]); *api = i; *sub_api = j; @@ -1314,7 +1378,7 @@ static int set_composite_interface(struct libusb_context *ctx, struct libusb_dev if (priv->usb_interface[interface_number].path != NULL) { if (api == USB_API_HID) { // HID devices can have multiple collections (COL##) for each MI_## interface - usbi_dbg("interface[%d] already set - ignoring HID collection: %s", + usbi_dbg(ctx, "interface[%d] already set - ignoring HID collection: %s", interface_number, device_id); return LIBUSB_ERROR_ACCESS; } @@ -1322,7 +1386,7 @@ static int set_composite_interface(struct libusb_context *ctx, struct libusb_dev safe_free(priv->usb_interface[interface_number].path); } - usbi_dbg("interface[%d] = %s", interface_number, dev_interface_path); + usbi_dbg(ctx, "interface[%d] = %s", interface_number, dev_interface_path); priv->usb_interface[interface_number].path = dev_interface_path; priv->usb_interface[interface_number].apib = &usb_api_backend[api]; priv->usb_interface[interface_number].sub_api = sub_api; @@ -1351,14 +1415,14 @@ static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *d for (i = 0; i < priv->hid->nb_interfaces; i++) { if ((priv->usb_interface[i].path != NULL) && strcmp(priv->usb_interface[i].path, dev_interface_path) == 0) { - usbi_dbg("interface[%u] already set to %s", i, dev_interface_path); + usbi_dbg(ctx, "interface[%u] already set to %s", i, dev_interface_path); return LIBUSB_ERROR_ACCESS; } } priv->usb_interface[priv->hid->nb_interfaces].path = dev_interface_path; priv->usb_interface[priv->hid->nb_interfaces].apib = &usb_api_backend[USB_API_HID]; - usbi_dbg("interface[%u] = %s", priv->hid->nb_interfaces, dev_interface_path); + usbi_dbg(ctx, "interface[%u] = %s", priv->hid->nb_interfaces, dev_interface_path); priv->hid->nb_interfaces++; return LIBUSB_SUCCESS; } @@ -1384,7 +1448,7 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ unsigned long session_id; DWORD size, port_nr, reg_type, install_state; HKEY key; - WCHAR guid_string_w[MAX_GUID_STRING_LENGTH]; + char guid_string[MAX_GUID_STRING_LENGTH]; GUID *if_guid; LONG s; #define HUB_PASS 0 @@ -1454,7 +1518,7 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ //#define ENUM_DEBUG #if defined(ENABLE_LOGGING) && defined(ENUM_DEBUG) const char * const passname[] = {"HUB", "DEV", "HCD", "GEN", "HID", "EXT"}; - usbi_dbg("#### PROCESSING %ss %s", passname[MIN(pass, EXT_PASS)], guid_to_string(guid_list[pass])); + usbi_dbg(ctx, "#### PROCESSING %ss %s", passname[MIN(pass, EXT_PASS)], guid_to_string(guid_list[pass], guid_string)); #endif if ((pass == HID_PASS) && (guid_list[HID_PASS] == NULL)) continue; @@ -1506,7 +1570,7 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ } #ifdef ENUM_DEBUG - usbi_dbg("PRO: %s", dev_id); + usbi_dbg(ctx, "PRO: %s", dev_id); #endif // Set API to use or get additional data from generic pass @@ -1529,7 +1593,7 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ break; } if (j == nb_usb_enumerators) { - usbi_dbg("found new PnP enumerator string '%s'", enumerator); + usbi_dbg(ctx, "found new PnP enumerator string '%s'", enumerator); if (nb_usb_enumerators < ARRAYSIZE(usb_enumerator)) { usb_enumerator[nb_usb_enumerators] = _strdup(enumerator); if (usb_enumerator[nb_usb_enumerators] != NULL) { @@ -1555,16 +1619,25 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ if (key == INVALID_HANDLE_VALUE) break; // Look for both DeviceInterfaceGUIDs *and* DeviceInterfaceGUID, in that order - size = sizeof(guid_string_w); - s = pRegQueryValueExW(key, L"DeviceInterfaceGUIDs", NULL, ®_type, - (LPBYTE)guid_string_w, &size); + // If multiple GUIDs just process the first and ignore the others + size = sizeof(guid_string); + s = pRegQueryValueExA(key, "DeviceInterfaceGUIDs", NULL, ®_type, + (LPBYTE)guid_string, &size); if (s == ERROR_FILE_NOT_FOUND) - s = pRegQueryValueExW(key, L"DeviceInterfaceGUID", NULL, ®_type, - (LPBYTE)guid_string_w, &size); + s = pRegQueryValueExA(key, "DeviceInterfaceGUID", NULL, ®_type, + (LPBYTE)guid_string, &size); pRegCloseKey(key); - if ((s == ERROR_SUCCESS) && - (((reg_type == REG_SZ) && (size == (sizeof(guid_string_w) - sizeof(WCHAR)))) || - ((reg_type == REG_MULTI_SZ) && (size == sizeof(guid_string_w))))) { + if (s == ERROR_FILE_NOT_FOUND) { + break; /* no DeviceInterfaceGUID registered */ + } else if (s != ERROR_SUCCESS && s != ERROR_MORE_DATA) { + usbi_warn(ctx, "unexpected error from pRegQueryValueExA for '%s'", dev_id); + break; + } + // https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexa#remarks + // - "string may not have been stored with the proper terminating null characters" + // - "Note that REG_MULTI_SZ strings could have two terminating null characters" + if ((reg_type == REG_SZ && size >= sizeof(guid_string) - sizeof(char)) + || (reg_type == REG_MULTI_SZ && size >= sizeof(guid_string) - 2 * sizeof(char))) { if (nb_guids == guid_size) { new_guid_list = realloc((void *)guid_list, (guid_size + GUID_SIZE_STEP) * sizeof(void *)); if (new_guid_list == NULL) { @@ -1579,8 +1652,8 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ usbi_err(ctx, "failed to alloc if_guid"); LOOP_BREAK(LIBUSB_ERROR_NO_MEM); } - if (pIIDFromString(guid_string_w, if_guid) != 0) { - usbi_warn(ctx, "device '%s' has malformed DeviceInterfaceGUID string, skipping", dev_id); + if (!string_to_guid(guid_string, if_guid)) { + usbi_warn(ctx, "device '%s' has malformed DeviceInterfaceGUID string '%s', skipping", dev_id, guid_string); free(if_guid); } else { // Check if we've already seen this GUID @@ -1589,14 +1662,14 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ break; } if (j == nb_guids) { - usbi_dbg("extra GUID: %s", guid_to_string(if_guid)); + usbi_dbg(ctx, "extra GUID: %s", guid_string); guid_list[nb_guids++] = if_guid; } else { // Duplicate, ignore free(if_guid); } } - } else if (s == ERROR_SUCCESS) { + } else { usbi_warn(ctx, "unexpected type/size of DeviceInterfaceGUID for '%s'", dev_id); } break; @@ -1631,7 +1704,7 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ libusb_unref_device(dev); } - usbi_dbg("unlisted ancestor for '%s' (non USB HID, newly connected, etc.) - ignoring", dev_id); + usbi_dbg(ctx, "unlisted ancestor for '%s' (non USB HID, newly connected, etc.) - ignoring", dev_id); continue; } @@ -1650,23 +1723,30 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ dev = usbi_get_device_by_session_id(ctx, session_id); if (dev == NULL) { alloc_device: - usbi_dbg("allocating new device for session [%lX]", session_id); + usbi_dbg(ctx, "allocating new device for session [%lX]", session_id); dev = usbi_alloc_device(ctx, session_id); if (dev == NULL) LOOP_BREAK(LIBUSB_ERROR_NO_MEM); priv = winusb_device_priv_init(dev); priv->dev_id = _strdup(dev_id); + priv->class_guid = dev_info_data.ClassGuid; if (priv->dev_id == NULL) { libusb_unref_device(dev); LOOP_BREAK(LIBUSB_ERROR_NO_MEM); } } else { - usbi_dbg("found existing device for session [%lX]", session_id); + usbi_dbg(ctx, "found existing device for session [%lX]", session_id); priv = usbi_get_device_priv(dev); if (strcmp(priv->dev_id, dev_id) != 0) { - usbi_dbg("device instance ID for session [%lX] changed", session_id); + usbi_dbg(ctx, "device instance ID for session [%lX] changed", session_id); + usbi_disconnect_device(dev); + libusb_unref_device(dev); + goto alloc_device; + } + if (!IsEqualGUID(&priv->class_guid, &dev_info_data.ClassGuid)) { + usbi_dbg(ctx, "device class GUID for session [%lX] changed", session_id); usbi_disconnect_device(dev); libusb_unref_device(dev); goto alloc_device; @@ -1724,10 +1804,8 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ r = enumerate_hcd_root_hub(ctx, dev_id, (uint8_t)(i + 1), dev_info_data.DevInst); break; case GEN_PASS: - // The SPDRP_ADDRESS for USB devices is the device port number on the hub port_nr = 0; - if (!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_ADDRESS, - NULL, (PBYTE)&port_nr, sizeof(port_nr), &size) || (size != sizeof(port_nr))) + if (!get_dev_port_number(*dev_info, &dev_info_data, &port_nr)) usbi_warn(ctx, "could not retrieve port number for device '%s': %s", dev_id, windows_error_str(0)); r = init_device(dev, parent_dev, (uint8_t)port_nr, dev_info_data.DevInst); if (r == LIBUSB_SUCCESS) { @@ -1747,10 +1825,10 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_ default: // HID_PASS and later if (parent_priv->apib->id == USB_API_HID || parent_priv->apib->id == USB_API_COMPOSITE) { if (parent_priv->apib->id == USB_API_HID) { - usbi_dbg("setting HID interface for [%lX]:", parent_dev->session_data); + usbi_dbg(ctx, "setting HID interface for [%lX]:", parent_dev->session_data); r = set_hid_interface(ctx, parent_dev, dev_interface_path); } else { - usbi_dbg("setting composite interface for [%lX]:", parent_dev->session_data); + usbi_dbg(ctx, "setting composite interface for [%lX]:", parent_dev->session_data); r = set_composite_interface(ctx, parent_dev, dev_interface_path, dev_id, api, sub_api); } switch (r) { @@ -2001,8 +2079,6 @@ static int winusb_submit_transfer(struct usbi_transfer *itransfer) break; case LIBUSB_TRANSFER_TYPE_BULK: case LIBUSB_TRANSFER_TYPE_INTERRUPT: - if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)) - return LIBUSB_ERROR_NOT_SUPPORTED; transfer_fn = priv->apib->submit_bulk_transfer; break; case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: @@ -2263,10 +2339,10 @@ cleanup_winusb: KLIB_VERSION LibK_Version; pLibK_GetVersion(&LibK_Version); - usbi_dbg("libusbK DLL found, version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor, + usbi_dbg(ctx, "libusbK DLL found, version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor, LibK_Version.Micro, LibK_Version.Nano); } else { - usbi_dbg("libusbK DLL found, version unknown"); + usbi_dbg(ctx, "libusbK DLL found, version unknown"); } pLibK_GetProcAddress = (LibK_GetProcAddress_t)GetProcAddress(hlibusbK, "LibK_GetProcAddress"); @@ -2352,7 +2428,7 @@ static void winusbx_exit(void) static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle) { struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); HANDLE file_handle; int i; @@ -2362,7 +2438,7 @@ static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle) for (i = 0; i < USB_MAXINTERFACES; i++) { if ((priv->usb_interface[i].path != NULL) && (priv->usb_interface[i].apib->id == USB_API_WINUSBX)) { - file_handle = windows_open(dev_handle->dev, priv->usb_interface[i].path, GENERIC_READ | GENERIC_WRITE); + file_handle = windows_open(dev_handle, priv->usb_interface[i].path, GENERIC_READ | GENERIC_WRITE); if (file_handle == INVALID_HANDLE_VALUE) { usbi_err(HANDLE_CTX(dev_handle), "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0)); switch (GetLastError()) { @@ -2384,7 +2460,7 @@ static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle) static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle) { - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); HANDLE handle; int i; @@ -2429,7 +2505,7 @@ static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle) static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface) { - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); HANDLE winusb_handle = handle_priv->interface_handle[iface].api_handle; UCHAR policy; @@ -2445,35 +2521,36 @@ static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle endpoint_address = (i == -1) ? 0 : priv->usb_interface[iface].endpoint[i]; if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout)) - usbi_dbg("failed to set PIPE_TRANSFER_TIMEOUT for control endpoint %02X", endpoint_address); + usbi_dbg(HANDLE_CTX(dev_handle), "failed to set PIPE_TRANSFER_TIMEOUT for control endpoint %02X", endpoint_address); if ((i == -1) || (sub_api == SUB_API_LIBUSB0)) continue; // Other policies don't apply to control endpoint or libusb0 policy = false; + handle_priv->interface_handle[iface].zlp[endpoint_address] = WINUSB_ZLP_UNSET; if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy)) - usbi_dbg("failed to disable SHORT_PACKET_TERMINATE for endpoint %02X", endpoint_address); + usbi_dbg(HANDLE_CTX(dev_handle), "failed to disable SHORT_PACKET_TERMINATE for endpoint %02X", endpoint_address); if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, IGNORE_SHORT_PACKETS, sizeof(UCHAR), &policy)) - usbi_dbg("failed to disable IGNORE_SHORT_PACKETS for endpoint %02X", endpoint_address); + usbi_dbg(HANDLE_CTX(dev_handle), "failed to disable IGNORE_SHORT_PACKETS for endpoint %02X", endpoint_address); policy = true; /* ALLOW_PARTIAL_READS must be enabled due to likely libusbK bug. See: https://sourceforge.net/mailarchive/message.php?msg_id=29736015 */ if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, ALLOW_PARTIAL_READS, sizeof(UCHAR), &policy)) - usbi_dbg("failed to enable ALLOW_PARTIAL_READS for endpoint %02X", endpoint_address); + usbi_dbg(HANDLE_CTX(dev_handle), "failed to enable ALLOW_PARTIAL_READS for endpoint %02X", endpoint_address); if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, AUTO_CLEAR_STALL, sizeof(UCHAR), &policy)) - usbi_dbg("failed to enable AUTO_CLEAR_STALL for endpoint %02X", endpoint_address); + usbi_dbg(HANDLE_CTX(dev_handle), "failed to enable AUTO_CLEAR_STALL for endpoint %02X", endpoint_address); if (sub_api == SUB_API_LIBUSBK) { if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, ISO_ALWAYS_START_ASAP, sizeof(UCHAR), &policy)) - usbi_dbg("failed to enable ISO_ALWAYS_START_ASAP for endpoint %02X", endpoint_address); + usbi_dbg(HANDLE_CTX(dev_handle), "failed to enable ISO_ALWAYS_START_ASAP for endpoint %02X", endpoint_address); } } @@ -2483,7 +2560,7 @@ static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface) { struct libusb_context *ctx = HANDLE_CTX(dev_handle); - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE); HDEVINFO dev_info; @@ -2534,7 +2611,7 @@ static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev *dev_interface_path_guid_start = '\0'; if (strncmp(dev_interface_path, priv->usb_interface[iface].path, strlen(dev_interface_path)) == 0) { - file_handle = windows_open(dev_handle->dev, filter_path, GENERIC_READ | GENERIC_WRITE); + file_handle = windows_open(dev_handle, filter_path, GENERIC_READ | GENERIC_WRITE); if (file_handle != INVALID_HANDLE_VALUE) { if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) { // Replace the existing file handle with the working one @@ -2591,7 +2668,7 @@ static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev } handle_priv->interface_handle[iface].dev_handle = handle_priv->interface_handle[0].dev_handle; } - usbi_dbg("claimed interface %u", iface); + usbi_dbg(ctx, "claimed interface %u", iface); handle_priv->active_interface = iface; return LIBUSB_SUCCESS; @@ -2599,7 +2676,7 @@ static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface) { - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); HANDLE winusb_handle; @@ -2620,12 +2697,12 @@ static int winusbx_release_interface(int sub_api, struct libusb_device_handle *d */ static int get_valid_interface(struct libusb_device_handle *dev_handle, int api_id) { - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); int i; if ((api_id < USB_API_WINUSBX) || (api_id > USB_API_HID)) { - usbi_dbg("unsupported API ID"); + usbi_dbg(HANDLE_CTX(dev_handle), "unsupported API ID"); return -1; } @@ -2644,14 +2721,14 @@ static int get_valid_interface(struct libusb_device_handle *dev_handle, int api_ */ static int check_valid_interface(struct libusb_device_handle *dev_handle, unsigned short interface, int api_id) { - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); if (interface >= USB_MAXINTERFACES) return -1; if ((api_id < USB_API_WINUSBX) || (api_id > USB_API_HID)) { - usbi_dbg("unsupported API ID"); + usbi_dbg(HANDLE_CTX(dev_handle), "unsupported API ID"); return -1; } @@ -2691,9 +2768,9 @@ static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *it struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev); struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(transfer->dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle); PWINUSB_SETUP_PACKET setup = (PWINUSB_SETUP_PACKET)transfer->buffer; - ULONG size; + ULONG size, transferred; HANDLE winusb_handle; OVERLAPPED *overlapped; int current_interface; @@ -2703,7 +2780,7 @@ static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *it size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE; // Windows places upper limits on the control transfer size - // See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff538112.aspx + // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-bandwidth-allocation#maximum-transfer-size if (size > MAX_CTRL_BUFFER_LENGTH) return LIBUSB_ERROR_INVALID_PARAM; @@ -2716,8 +2793,9 @@ static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *it return LIBUSB_ERROR_NOT_FOUND; } - usbi_dbg("will use interface %d", current_interface); + usbi_dbg(ITRANSFER_CTX(itransfer), "will use interface %d", current_interface); + transfer_priv->interface_number = (uint8_t)current_interface; winusb_handle = handle_priv->interface_handle[current_interface].api_handle; set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle); overlapped = get_transfer_priv_overlapped(itransfer); @@ -2732,22 +2810,22 @@ static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *it } windows_force_sync_completion(itransfer, 0); } else { - if (!WinUSBX[sub_api].ControlTransfer(winusb_handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, overlapped)) { + if (!WinUSBX[sub_api].ControlTransfer(winusb_handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, &transferred, overlapped)) { if (GetLastError() != ERROR_IO_PENDING) { usbi_warn(TRANSFER_CTX(transfer), "ControlTransfer failed: %s", windows_error_str(0)); return LIBUSB_ERROR_IO; } + } else { + windows_force_sync_completion(itransfer, transferred); } } - transfer_priv->interface_number = (uint8_t)current_interface; - return LIBUSB_SUCCESS; } static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting) { - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); HANDLE winusb_handle; @@ -2803,7 +2881,7 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(transfer->dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev); HANDLE winusb_handle; OVERLAPPED *overlapped; @@ -2818,8 +2896,9 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans return LIBUSB_ERROR_NOT_FOUND; } - usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); + usbi_dbg(TRANSFER_CTX(transfer), "matched endpoint %02X with interface %d", transfer->endpoint, current_interface); + transfer_priv->interface_number = (uint8_t)current_interface; winusb_handle = handle_priv->interface_handle[current_interface].api_handle; set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle); overlapped = get_transfer_priv_overlapped(itransfer); @@ -2852,10 +2931,10 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans } if (IS_XFERIN(transfer)) { - usbi_dbg("reading %d iso packets", transfer->num_iso_packets); + usbi_dbg(TRANSFER_CTX(transfer), "reading %d iso packets", transfer->num_iso_packets); ret = WinUSBX[sub_api].IsoReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, overlapped, iso_context); } else { - usbi_dbg("writing %d iso packets", transfer->num_iso_packets); + usbi_dbg(TRANSFER_CTX(transfer), "writing %d iso packets", transfer->num_iso_packets); ret = WinUSBX[sub_api].IsoWritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, overlapped, iso_context); } @@ -2864,8 +2943,6 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans return LIBUSB_ERROR_IO; } - transfer_priv->interface_number = (uint8_t)current_interface; - return LIBUSB_SUCCESS; } else if (sub_api == SUB_API_WINUSB) { WINUSB_PIPE_INFORMATION_EX pipe_info_ex = { 0 }; @@ -2913,7 +2990,11 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans // WinUSB only supports isoch transfers spanning a full USB frames. Later, we might be smarter about this // and allocate a temporary buffer. However, this is harder than it seems as its destruction would depend on overlapped // IO... - iso_transfer_size_multiple = (pipe_info_ex.MaximumBytesPerInterval * 8) / interval; + if (transfer->dev_handle->dev->speed >= LIBUSB_SPEED_HIGH) // Microframes (125us) + iso_transfer_size_multiple = (pipe_info_ex.MaximumBytesPerInterval * 8) / interval; + else // Normal Frames (1ms) + iso_transfer_size_multiple = pipe_info_ex.MaximumBytesPerInterval / interval; + if (transfer->length % iso_transfer_size_multiple != 0) { usbi_err(TRANSFER_CTX(transfer), "length of isoch buffer must be a multiple of the MaximumBytesPerInterval * 8 / Interval"); return LIBUSB_ERROR_INVALID_PARAM; @@ -2980,8 +3061,6 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans transfer_priv->isoch_buffer_handle = buffer_handle; - transfer_priv->interface_number = (uint8_t)current_interface; - return LIBUSB_SUCCESS; } else { PRINT_UNSUPPORTED_API(winusbx_submit_iso_transfer); @@ -2993,7 +3072,7 @@ static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itran { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(transfer->dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev); HANDLE winusb_handle; OVERLAPPED *overlapped; @@ -3008,17 +3087,35 @@ static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itran return LIBUSB_ERROR_NOT_FOUND; } - usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); + usbi_dbg(TRANSFER_CTX(transfer), "matched endpoint %02X with interface %d", transfer->endpoint, current_interface); + transfer_priv->interface_number = (uint8_t)current_interface; winusb_handle = handle_priv->interface_handle[current_interface].api_handle; set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle); overlapped = get_transfer_priv_overlapped(itransfer); if (IS_XFERIN(transfer)) { - usbi_dbg("reading %d bytes", transfer->length); + usbi_dbg(TRANSFER_CTX(transfer), "reading %d bytes", transfer->length); ret = WinUSBX[sub_api].ReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped); } else { - usbi_dbg("writing %d bytes", transfer->length); + // Set SHORT_PACKET_TERMINATE if ZLP requested. + // Changing this can be a problem with packets in flight, so only allow on the first transfer. + UCHAR policy = (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) != 0; + uint8_t* current_zlp = &handle_priv->interface_handle[current_interface].zlp[transfer->endpoint]; + if (*current_zlp == WINUSB_ZLP_UNSET) { + if (policy && + !WinUSBX[sub_api].SetPipePolicy(winusb_handle, transfer->endpoint, + SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy)) { + usbi_err(TRANSFER_CTX(transfer), "failed to set SHORT_PACKET_TERMINATE for endpoint %02X", transfer->endpoint); + return LIBUSB_ERROR_NOT_SUPPORTED; + } + *current_zlp = policy ? WINUSB_ZLP_ON : WINUSB_ZLP_OFF; + } else if (policy != (*current_zlp == WINUSB_ZLP_ON)) { + usbi_err(TRANSFER_CTX(transfer), "cannot change ZERO_PACKET for endpoint %02X on Windows", transfer->endpoint); + return LIBUSB_ERROR_NOT_SUPPORTED; + } + + usbi_dbg(TRANSFER_CTX(transfer), "writing %d bytes", transfer->length); ret = WinUSBX[sub_api].WritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped); } @@ -3027,14 +3124,12 @@ static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itran return LIBUSB_ERROR_IO; } - transfer_priv->interface_number = (uint8_t)current_interface; - return LIBUSB_SUCCESS; } static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) { - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); HANDLE winusb_handle; int current_interface; @@ -3047,7 +3142,7 @@ static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_hand return LIBUSB_ERROR_NOT_FOUND; } - usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface); + usbi_dbg(HANDLE_CTX(dev_handle), "matched endpoint %02X with interface %d", endpoint, current_interface); winusb_handle = handle_priv->interface_handle[current_interface].api_handle; if (!WinUSBX[sub_api].ResetPipe(winusb_handle, endpoint)) { @@ -3061,7 +3156,7 @@ static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_hand static int winusbx_cancel_transfer(int sub_api, struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(transfer->dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle); struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev); int current_interface = transfer_priv->interface_number; @@ -3069,7 +3164,7 @@ static int winusbx_cancel_transfer(int sub_api, struct usbi_transfer *itransfer) CHECK_WINUSBX_AVAILABLE(sub_api); - usbi_dbg("will use interface %d", current_interface); + usbi_dbg(TRANSFER_CTX(transfer), "will use interface %d", current_interface); handle = handle_priv->interface_handle[current_interface].api_handle; if (!WinUSBX[sub_api].AbortPipe(handle, transfer->endpoint)) { @@ -3091,7 +3186,7 @@ static int winusbx_cancel_transfer(int sub_api, struct usbi_transfer *itransfer) // TODO: (post hotplug): see if we can force eject the device and redetect it (reuse hotplug?) static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle) { - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); HANDLE winusb_handle; int i, j; @@ -3103,7 +3198,7 @@ static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_ha winusb_handle = handle_priv->interface_handle[i].api_handle; if (HANDLE_VALID(winusb_handle)) { for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) { - usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]); + usbi_dbg(HANDLE_CTX(dev_handle), "resetting ep %02X", priv->usb_interface[i].endpoint[j]); if (!WinUSBX[sub_api].AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) usbi_err(HANDLE_CTX(dev_handle), "AbortPipe (pipe address %02X) failed: %s", priv->usb_interface[i].endpoint[j], windows_error_str(0)); @@ -3138,12 +3233,25 @@ static enum libusb_transfer_status winusbx_copy_transfer_data(int sub_api, struc int i; if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { + struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev); + + if (sub_api == SUB_API_NOTSET) + sub_api = priv->sub_api; + if (WinUSBX[sub_api].hDll == NULL) + return LIBUSB_TRANSFER_ERROR; + // for isochronous, need to copy the individual iso packet actual_lengths and statuses if ((sub_api == SUB_API_LIBUSBK) || (sub_api == SUB_API_LIBUSB0)) { // iso only supported on libusbk-based backends for now PKISO_CONTEXT iso_context = transfer_priv->iso_context; for (i = 0; i < transfer->num_iso_packets; i++) { - transfer->iso_packet_desc[i].actual_length = iso_context->IsoPackets[i].actual_length; + if (IS_XFERIN(transfer)) { + transfer->iso_packet_desc[i].actual_length = iso_context->IsoPackets[i].actual_length; + } else { + // On Windows the usbd Length field is not used for OUT transfers. + // Copy the requested value back for consistency with other platforms. + transfer->iso_packet_desc[i].actual_length = transfer->iso_packet_desc[i].length; + } // TODO translate USDB_STATUS codes http://msdn.microsoft.com/en-us/library/ff539136(VS.85).aspx to libusb_transfer_status //transfer->iso_packet_desc[i].status = transfer_priv->iso_context->IsoPackets[i].status; } @@ -3164,6 +3272,9 @@ static enum libusb_transfer_status winusbx_copy_transfer_data(int sub_api, struc } else { for (i = 0; i < transfer->num_iso_packets; i++) { transfer->iso_packet_desc[i].status = LIBUSB_TRANSFER_COMPLETED; + // On Windows the usbd Length field is not used for OUT transfers. + // Copy the requested value back for consistency with other platforms. + transfer->iso_packet_desc[i].actual_length = transfer->iso_packet_desc[i].length; } } } else { @@ -3439,28 +3550,28 @@ static int _hid_get_descriptor(struct libusb_device *dev, HANDLE hid_handle, int switch (type) { case LIBUSB_DT_DEVICE: - usbi_dbg("LIBUSB_DT_DEVICE"); + usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_DEVICE"); return _hid_get_device_descriptor(priv->hid, data, size); case LIBUSB_DT_CONFIG: - usbi_dbg("LIBUSB_DT_CONFIG"); + usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_CONFIG"); if (!_index) return _hid_get_config_descriptor(priv->hid, data, size); return LIBUSB_ERROR_INVALID_PARAM; case LIBUSB_DT_STRING: - usbi_dbg("LIBUSB_DT_STRING"); + usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_STRING"); return _hid_get_string_descriptor(priv->hid, _index, data, size, hid_handle); case LIBUSB_DT_HID: - usbi_dbg("LIBUSB_DT_HID"); + usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_HID"); if (!_index) return _hid_get_hid_descriptor(priv->hid, data, size); return LIBUSB_ERROR_INVALID_PARAM; case LIBUSB_DT_REPORT: - usbi_dbg("LIBUSB_DT_REPORT"); + usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_REPORT"); if (!_index) return _hid_get_report_descriptor(priv->hid, data, size); return LIBUSB_ERROR_INVALID_PARAM; case LIBUSB_DT_PHYSICAL: - usbi_dbg("LIBUSB_DT_PHYSICAL"); + usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_PHYSICAL"); if (HidD_GetPhysicalDescriptor(hid_handle, data, (ULONG)*size)) return LIBUSB_COMPLETED; return LIBUSB_ERROR_OTHER; @@ -3502,7 +3613,7 @@ static int _hid_get_report(struct libusb_device *dev, HANDLE hid_handle, int id, return LIBUSB_ERROR_NO_MEM; buf[0] = (uint8_t)id; // Must be set always - usbi_dbg("report ID: 0x%02X", buf[0]); + usbi_dbg(DEVICE_CTX(dev), "report ID: 0x%02X", buf[0]); // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0) if (!DeviceIoControl(hid_handle, ioctl_code, buf, expected_size + 1, @@ -3550,7 +3661,7 @@ static int _hid_set_report(struct libusb_device *dev, HANDLE hid_handle, int id, return LIBUSB_ERROR_INVALID_PARAM; } - usbi_dbg("report ID: 0x%02X", id); + usbi_dbg(DEVICE_CTX(dev), "report ID: 0x%02X", id); // When report IDs are not used (i.e. when id == 0), we must add // a null report ID. Otherwise, we just use original data buffer if (id == 0) @@ -3644,7 +3755,7 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) { struct libusb_device *dev = dev_handle->dev; struct winusb_device_priv *priv = usbi_get_device_priv(dev); - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); HIDD_ATTRIBUTES hid_attributes; PHIDP_PREPARSED_DATA preparsed_data = NULL; HIDP_CAPS capabilities; @@ -3669,7 +3780,7 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) for (i = 0; i < USB_MAXINTERFACES; i++) { if ((priv->usb_interface[i].path != NULL) && (priv->usb_interface[i].apib->id == USB_API_HID)) { - hid_handle = windows_open(dev, priv->usb_interface[i].path, GENERIC_READ | GENERIC_WRITE); + hid_handle = windows_open(dev_handle, priv->usb_interface[i].path, GENERIC_READ | GENERIC_WRITE); /* * http://www.lvr.com/hidfaq.htm: Why do I receive "Access denied" when attempting to access my HID? * "Windows 2000 and later have exclusive read/write access to HIDs that are configured as a system @@ -3679,7 +3790,7 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) */ if (hid_handle == INVALID_HANDLE_VALUE) { usbi_warn(HANDLE_CTX(dev_handle), "could not open HID device in R/W mode (keyboard or mouse?) - trying without"); - hid_handle = windows_open(dev, priv->usb_interface[i].path, 0); + hid_handle = windows_open(dev_handle, priv->usb_interface[i].path, 0); if (hid_handle == INVALID_HANDLE_VALUE) { usbi_err(HANDLE_CTX(dev_handle), "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0)); switch (GetLastError()) { @@ -3709,7 +3820,7 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) // Set the maximum available input buffer size for (i = 32; HidD_SetNumInputBuffers(hid_handle, i); i *= 2); - usbi_dbg("set maximum input buffer size to %d", i / 2); + usbi_dbg(HANDLE_CTX(dev_handle), "set maximum input buffer size to %d", i / 2); // Get the maximum input and output report size if (!HidD_GetPreparsedData(hid_handle, &preparsed_data) || !preparsed_data) { @@ -3726,7 +3837,7 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) size[1] = capabilities.NumberOutputValueCaps; size[2] = capabilities.NumberFeatureValueCaps; for (j = HidP_Input; j <= HidP_Feature; j++) { - usbi_dbg("%lu HID %s report value(s) found", ULONG_CAST(size[j]), type[j]); + usbi_dbg(HANDLE_CTX(dev_handle), "%lu HID %s report value(s) found", ULONG_CAST(size[j]), type[j]); priv->hid->uses_report_ids[j] = false; if (size[j] > 0) { value_caps = calloc(size[j], sizeof(HIDP_VALUE_CAPS)); @@ -3736,7 +3847,7 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) nb_ids[0] = 0; nb_ids[1] = 0; for (i = 0; i < (int)size[j]; i++) { - usbi_dbg(" Report ID: 0x%02X", value_caps[i].ReportID); + usbi_dbg(HANDLE_CTX(dev_handle), " Report ID: 0x%02X", value_caps[i].ReportID); if (value_caps[i].ReportID != 0) nb_ids[1]++; else @@ -3773,7 +3884,10 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) priv->hid->string_index[1] = dev->device_descriptor.iProduct; if (priv->hid->string_index[1] != 0) - HidD_GetProductString(hid_handle, priv->hid->string[1], sizeof(priv->hid->string[1])); + // Using HidD_GetIndexedString() instead of HidD_GetProductString(), as the latter would otherwise return the name + // of the interface instead of the iProduct string whenever the iInterface member of the USB_INTERFACE_DESCRIPTOR + // structure for the interface is nonzero (see Remarks section in the documentation of the HID API routines) + HidD_GetIndexedString(hid_handle, priv->hid->string_index[1], priv->hid->string[1], sizeof(priv->hid->string[1])); else priv->hid->string[1][0] = 0; @@ -3793,7 +3907,7 @@ static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) static void hid_close(int sub_api, struct libusb_device_handle *dev_handle) { struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); HANDLE file_handle; int i; @@ -3813,7 +3927,7 @@ static void hid_close(int sub_api, struct libusb_device_handle *dev_handle) static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface) { - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); UNUSED(sub_api); @@ -3829,7 +3943,7 @@ static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_han handle_priv->interface_handle[iface].dev_handle = INTERFACE_CLAIMED; - usbi_dbg("claimed interface %u", iface); + usbi_dbg(HANDLE_CTX(dev_handle), "claimed interface %u", iface); handle_priv->active_interface = iface; return LIBUSB_SUCCESS; @@ -3837,7 +3951,7 @@ static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_han static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface) { - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); UNUSED(sub_api); @@ -3874,7 +3988,7 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); struct libusb_device_handle *dev_handle = transfer->dev_handle; - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev); WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer; HANDLE hid_handle; @@ -3900,8 +4014,9 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans return LIBUSB_ERROR_NOT_FOUND; } - usbi_dbg("will use interface %d", current_interface); + usbi_dbg(ITRANSFER_CTX(itransfer), "will use interface %d", current_interface); + transfer_priv->interface_number = (uint8_t)current_interface; hid_handle = handle_priv->interface_handle[current_interface].api_handle; set_transfer_priv_handle(itransfer, hid_handle); overlapped = get_transfer_priv_overlapped(itransfer); @@ -3963,8 +4078,6 @@ static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itrans r = LIBUSB_SUCCESS; } - transfer_priv->interface_number = (uint8_t)current_interface; - return LIBUSB_SUCCESS; } @@ -3972,7 +4085,7 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer); - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(transfer->dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev); HANDLE hid_handle; OVERLAPPED *overlapped; @@ -3983,6 +4096,9 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer UNUSED(sub_api); CHECK_HID_AVAILABLE; + if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)) + return LIBUSB_ERROR_NOT_SUPPORTED; + transfer_priv->hid_dest = NULL; safe_free(transfer_priv->hid_buffer); @@ -3992,8 +4108,9 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer return LIBUSB_ERROR_NOT_FOUND; } - usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); + usbi_dbg(TRANSFER_CTX(transfer), "matched endpoint %02X with interface %d", transfer->endpoint, current_interface); + transfer_priv->interface_number = (uint8_t)current_interface; hid_handle = handle_priv->interface_handle[current_interface].api_handle; set_transfer_priv_handle(itransfer, hid_handle); overlapped = get_transfer_priv_overlapped(itransfer); @@ -4015,7 +4132,7 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer if (direction_in) { transfer_priv->hid_dest = transfer->buffer; - usbi_dbg("reading %d bytes (report ID: 0x00)", length); + usbi_dbg(TRANSFER_CTX(transfer), "reading %d bytes (report ID: 0x00)", length); ret = ReadFile(hid_handle, transfer_priv->hid_buffer, length + 1, NULL, overlapped); } else { if (!priv->hid->uses_report_ids[1]) @@ -4024,7 +4141,7 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer // We could actually do without the calloc and memcpy in this case memcpy(transfer_priv->hid_buffer, transfer->buffer, transfer->length); - usbi_dbg("writing %d bytes (report ID: 0x%02X)", length, transfer_priv->hid_buffer[0]); + usbi_dbg(TRANSFER_CTX(transfer), "writing %d bytes (report ID: 0x%02X)", length, transfer_priv->hid_buffer[0]); ret = WriteFile(hid_handle, transfer_priv->hid_buffer, length, NULL, overlapped); } @@ -4034,14 +4151,12 @@ static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer return LIBUSB_ERROR_IO; } - transfer_priv->interface_number = (uint8_t)current_interface; - return LIBUSB_SUCCESS; } static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle) { - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); HANDLE hid_handle; int current_interface; @@ -4060,7 +4175,7 @@ static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) { - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); HANDLE hid_handle; int current_interface; @@ -4074,7 +4189,7 @@ static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, return LIBUSB_ERROR_NOT_FOUND; } - usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface); + usbi_dbg(HANDLE_CTX(dev_handle), "matched endpoint %02X with interface %d", endpoint, current_interface); hid_handle = handle_priv->interface_handle[current_interface].api_handle; // No endpoint selection with Microsoft's implementation, so we try to flush the @@ -4109,8 +4224,6 @@ static enum libusb_transfer_status hid_copy_transfer_data(int sub_api, struct us } if (transfer_priv->hid_buffer[0] == 0) { - // Discard the 1 byte report ID prefix - length--; memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer + 1, length); } else { memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer, length); @@ -4171,7 +4284,7 @@ static int composite_open(int sub_api, struct libusb_device_handle *dev_handle) // open HID devices with a U2F usage unless running as administrator. We ignore this // failure and proceed without the HID device opened. if (r == LIBUSB_ERROR_ACCESS) { - usbi_dbg("ignoring access denied error while opening HID interface of composite device"); + usbi_dbg(HANDLE_CTX(dev_handle), "ignoring access denied error while opening HID interface of composite device"); r = LIBUSB_SUCCESS; } } @@ -4280,7 +4393,7 @@ static int composite_submit_control_transfer(int sub_api, struct usbi_transfer * // Try and target a specific interface if the control setup indicates such if ((iface >= 0) && (iface < USB_MAXINTERFACES)) { - usbi_dbg("attempting control transfer targeted to interface %d", iface); + usbi_dbg(TRANSFER_CTX(transfer), "attempting control transfer targeted to interface %d", iface); if ((priv->usb_interface[iface].path != NULL) && (priv->usb_interface[iface].apib->submit_control_transfer != NULL)) { r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer); @@ -4296,10 +4409,10 @@ static int composite_submit_control_transfer(int sub_api, struct usbi_transfer * if ((priv->usb_interface[iface].path != NULL) && (priv->usb_interface[iface].apib->submit_control_transfer != NULL)) { if ((pass == 0) && (priv->usb_interface[iface].restricted_functionality)) { - usbi_dbg("trying to skip restricted interface #%d (HID keyboard or mouse?)", iface); + usbi_dbg(TRANSFER_CTX(transfer), "trying to skip restricted interface #%d (HID keyboard or mouse?)", iface); continue; } - usbi_dbg("using interface %d", iface); + usbi_dbg(TRANSFER_CTX(transfer), "using interface %d", iface); r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer); // If not supported on this API, it may be supported on another, so don't give up yet!! if (r == LIBUSB_ERROR_NOT_SUPPORTED) @@ -4316,7 +4429,7 @@ static int composite_submit_control_transfer(int sub_api, struct usbi_transfer * static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(transfer->dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev); int current_interface; @@ -4337,7 +4450,7 @@ static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itr static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer) { struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(transfer->dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev); int current_interface; @@ -4357,7 +4470,7 @@ static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itra static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) { - struct winusb_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle); + struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle); struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev); int current_interface; |