From 4ee3179ae1e0adefc6c5d19c036c297856ebdef9 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 8 Mar 2010 12:36:26 +0000 Subject: libusb0.sys backend integration - part 1 (Graeme Gill) --- libusb/os/poll_windows.h | 1 + libusb/os/windows_usb.c | 971 +++++++++++++++++++++++++++++++++++++++++++++-- libusb/os/windows_usb.h | 43 ++- 3 files changed, 978 insertions(+), 37 deletions(-) diff --git a/libusb/os/poll_windows.h b/libusb/os/poll_windows.h index 996ff48..3c0f6c4 100644 --- a/libusb/os/poll_windows.h +++ b/libusb/os/poll_windows.h @@ -36,6 +36,7 @@ enum windows_version { WINDOWS_UNSUPPORTED, + WINDOWS_2K, WINDOWS_XP, WINDOWS_VISTA_AND_LATER, }; diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c index d6e9f9d..bf5a1e5 100644 --- a/libusb/os/windows_usb.c +++ b/libusb/os/windows_usb.c @@ -77,6 +77,22 @@ static int winusb_abort_transfers(struct usbi_transfer *itransfer); static int winusb_abort_control(struct usbi_transfer *itransfer); static int winusb_reset_device(struct libusb_device_handle *dev_handle); static int winusb_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size); +// libusb0 API prototypes +static int libusb0_init(struct libusb_context *ctx); +static int libusb0_exit(void); +static int libusb0_open(struct libusb_device_handle *dev_handle); +static void libusb0_close(struct libusb_device_handle *dev_handle); +static int libusb0_claim_interface(struct libusb_device_handle *dev_handle, int iface); +static int libusb0_release_interface(struct libusb_device_handle *dev_handle, int iface); +static int libusb0_submit_control_transfer(struct usbi_transfer *itransfer); +static int libusb0_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting); +static int libusb0_submit_bulk_transfer(struct usbi_transfer *itransfer); +static int libusb0_submit_iso_transfer(struct usbi_transfer *itransfer); +static int libusb0_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint); +static int libusb0_abort_transfers(struct usbi_transfer *itransfer); +static int libusb0_abort_control(struct usbi_transfer *itransfer); +static int libusb0_reset_device(struct libusb_device_handle *dev_handle); +static int libusb0_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size); // HID API prototypes static int hid_init(struct libusb_context *ctx); static int hid_exit(void); @@ -112,7 +128,7 @@ static int composite_copy_transfer_data(struct usbi_transfer *itransfer, uint32_ // Global variables struct windows_hcd_priv* hcd_root = NULL; uint64_t hires_frequency, hires_ticks_to_ps; -const uint64_t epoch_time = 116444736000000000; // 1970.01.01 00:00:000 in MS Filetime +const uint64_t epoch_time = UINT64_C(116444736000000000); // 1970.01.01 00:00:000 in MS Filetime enum windows_version windows_version = WINDOWS_UNSUPPORTED; // Concurrency static int concurrent_usage = -1; @@ -127,6 +143,8 @@ HANDLE timer_response = NULL; // API globals bool api_winusb_available = false; #define CHECK_WINUSB_AVAILABLE do { if (!api_winusb_available) return LIBUSB_ERROR_ACCESS; } while (0) +bool api_libusb0_available = false; +#define CHECK_LIBUSB0_AVAILABLE do { if (!api_libusb0_available) return LIBUSB_ERROR_ACCESS; } while (0) bool api_hid_available = false; #define CHECK_HID_AVAILABLE do { if (!api_hid_available) return LIBUSB_ERROR_ACCESS; } while (0) @@ -404,11 +422,6 @@ static int windows_init(struct libusb_context *ctx) struct windows_hcd_priv** _hcd_cur; TCHAR sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID) - if (Cfgmgr32_init() != LIBUSB_SUCCESS) { - usbi_err(ctx, "could not resolve Cfgmgr32.dll functions"); - return LIBUSB_ERROR_OTHER; - } - sprintf(sem_name, "libusb_init%08X", (unsigned int)GetCurrentProcessId()&0xFFFFFFFF); semaphore = CreateSemaphore(NULL, 1, 1, sem_name); if (semaphore == NULL) { @@ -427,6 +440,8 @@ static int windows_init(struct libusb_context *ctx) // NB: concurrent usage supposes that init calls are equally balanced with // exit calls. If init is called more than exit, we will not exit properly if ( ++concurrent_usage == 0 ) { // First init? + int hcnum; + _hcd_cur = &hcd_root; // Detect OS version @@ -434,7 +449,9 @@ static int windows_init(struct libusb_context *ctx) os_version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); windows_version = WINDOWS_UNSUPPORTED; if ((GetVersionEx(&os_version) != 0) && (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT)) { - if ((os_version.dwMajorVersion == 5) && (os_version.dwMinorVersion == 1)) { + if ((os_version.dwMajorVersion == 5) && (os_version.dwMinorVersion == 0)) { + windows_version = WINDOWS_2K; + } else if ((os_version.dwMajorVersion == 5) && (os_version.dwMinorVersion == 1)) { windows_version = WINDOWS_XP; } else if (os_version.dwMajorVersion >= 6) { windows_version = WINDOWS_VISTA_AND_LATER; @@ -449,10 +466,19 @@ static int windows_init(struct libusb_context *ctx) // Initialize pollable file descriptors init_polling(); + // Load missing CFGMGR32.DLL imports + if (Cfgmgr32_init() != LIBUSB_SUCCESS) { + usbi_err(ctx, "could not resolve Cfgmgr32.dll functions"); + return LIBUSB_ERROR_OTHER; + } + // Initialize the low level APIs for (i=0; i= HCNUM_TO_CHECK) + break; + + handle = CreateFile(HCName, GENERIC_WRITE, FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + + if (handle != INVALID_HANDLE_VALUE) { + // Allocate and init a new priv structure to hold our data + if ((*_hcd_cur = malloc(sizeof(struct windows_hcd_priv))) == NULL) { + usbi_err(ctx, "could not allocate private structure for HCD%d. aborting.", + hcnum); + LOOP_BREAK(LIBUSB_ERROR_NO_MEM); + } + windows_hcd_priv_init(*_hcd_cur); + (*_hcd_cur)->path = sanitize_path(HCName); + + _hcd_cur = &((*_hcd_cur)->next); + CloseHandle(handle); + } + } + } + guid = GUID_DEVINTERFACE_USB_HOST_CONTROLLER; - r = LIBUSB_SUCCESS; for (bus = 0; ; bus++) { // safe loop: free up any (unprotected) dynamic resource @@ -497,8 +561,9 @@ static int windows_init(struct libusb_context *ctx) dev_interface_details = get_interface_details(ctx, &dev_info, NULL, guid, bus); // safe loop: end of loop condition - if ((dev_interface_details == NULL) || (r != LIBUSB_SUCCESS)) + if ((dev_interface_details == NULL) || (r != LIBUSB_SUCCESS)) { break; + } // Will need to change storage and size of libusb_bus_t if this ever occurs if (bus == LIBUSB_BUS_MAX) { @@ -628,9 +693,11 @@ static int force_hcd_device_descriptor(struct libusb_device *dev, HANDLE handle) size, &hub_caps, size, &size, NULL)) { usbi_warn(ctx, "could not read hub capabilities (std) for hub %s: %s", priv->path, windows_error_str(0)); - return LIBUSB_ERROR_IO; + /* Hmm. */ + priv->dev_descriptor.idProduct = 0; + } else { + priv->dev_descriptor.idProduct = hub_caps.HubIs2xCapable?2:1; } - priv->dev_descriptor.idProduct = hub_caps.HubIs2xCapable?2:1; } return LIBUSB_SUCCESS; @@ -808,9 +875,8 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs continue; } - if (conn_info.ConnectionStatus == NoDeviceConnected) { + if (conn_info.ConnectionStatus == NoDeviceConnected) continue; - } if (conn_info.DeviceAddress == 0) { usbi_warn(ctx, "program assertion failed - device address is zero " @@ -869,7 +935,7 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs // Open Hub handle = CreateFileA(path_str, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_POSIX_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL); + FILE_FLAG_OVERLAPPED, NULL); if(handle == INVALID_HANDLE_VALUE) { usbi_warn(ctx, "could not open hub %s: %s", path_str, windows_error_str(0)); continue; @@ -1303,16 +1369,18 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs * || (r != LIBUSB_SUCCESS) ) break; - // Check that the driver installation is OK - if ( (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, SPDRP_INSTALL_STATE, - ®_type, (BYTE*)&install_state, 4, &size)) - && (size != 4) ){ - usbi_warn(ctx, "could not detect installation state of driver for %s: %s", - dev_interface_details->DevicePath, windows_error_str(0)); - } else if (install_state != 0) { - usbi_warn(ctx, "driver for device %s is reporting an issue (code: %d) - skipping", - dev_interface_details->DevicePath, install_state); - continue; + if (windows_version != WINDOWS_2K) { /* Win2K doesn't support SPDRP_INSTALL_STATE */ + // Check that the driver installation is OK + if ( (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, SPDRP_INSTALL_STATE, + ®_type, (BYTE*)&install_state, 4, &size)) + && (size != 4) ){ + usbi_warn(ctx, "could not detect installation state of driver for %s: %s", + dev_interface_details->DevicePath, windows_error_str(0)); + } else if (install_state != 0) { + usbi_warn(ctx, "driver for device %s is reporting an issue (code: %d) - skipping", + dev_interface_details->DevicePath, install_state); + continue; + } } // The SPDRP_ADDRESS for USB devices should be the device port number on the hub @@ -1354,7 +1422,6 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs * if (priv->parent_dev == NULL) { continue; // ignore HCDs } - parent_priv = __device_priv(priv->parent_dev); // NB: we compare strings of different lengths below => strncmp @@ -1419,6 +1486,82 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs * } } + /* The libusb0 driver has it's own device names for the PCI devices it drives. */ + /* There doesn't seem any simple way of matching these up to the names found above, */ + /* but we do the best we can. For each libusb0 device, locate the first */ + /* not substituted matching device in our discovered devices. */ + { + char dev_name[LIBUSB0_DEVICE_NAME_MAX]; + char filename[LIBUSB0_DEVICE_NAME_MAX]; + int ret; + HANDLE handle; + libusb0_request req; + USB_DEVICE_DESCRIPTOR dev_descriptor; + + for (i = 1; i < LIBUSB0_MAX_DEVICES; i++) { + ret = 0; + + _snprintf(dev_name, sizeof(dev_name) - 1,"%s%04d", + LIBUSB0_DEVICE_NAME, i); + + handle = CreateFile(dev_name, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, NULL); + + if (handle == INVALID_HANDLE_VALUE) { + continue; + } +//printf("~1 opened '%s' OK\n",dev_name); + + /* retrieve device descriptor */ + req.descriptor.type = LIBUSB_DT_DEVICE; + req.descriptor.recipient = LIBUSB_RECIPIENT_DEVICE; + req.descriptor.index = 0; + req.descriptor.language_id = 0; + req.timeout = LIBUSB0_DEFAULT_TIMEOUT; + + if (LIBUSB_DT_DEVICE_SIZE != sizeof(USB_DEVICE_DESCRIPTOR)) + usbi_err(ctx, "program assertion failed - Device Descripor structure is the wrong size"); + + if (libusb0_io_sync(handle, LIBUSB0_IOCTL_GET_DESCRIPTOR, + &req, sizeof(libusb0_request), + &dev_descriptor, LIBUSB_DT_DEVICE_SIZE, &ret) != LIBUSB_SUCCESS + || ret < LIBUSB_DT_DEVICE_SIZE) { + usbi_err(ctx,"set_device_paths: couldn't read device descriptor"); + CloseHandle(handle); + continue; + } + CloseHandle(handle); + + _snprintf(filename, LIBUSB0_DEVICE_NAME_MAX - 1, "%s--0x%04x-0x%04x", + dev_name, dev_descriptor.idVendor, dev_descriptor.idProduct); + + for (j=0; jlen; j++) { + priv = __device_priv(discdevs->devices[j]); + + if (priv->parent_dev == NULL) { + continue; // ignore HCDs + } + + // See if the descriports match + if (priv->usb_interface[0].apib->id == USB_API_LIBUSB0 + && priv->libusb0_matched == 0 + && memcmp(&dev_descriptor, &priv->dev_descriptor, + sizeof(USB_DEVICE_DESCRIPTOR)) == 0) { + + +//printf("~1 overwriting '%s' with '%s'\n",priv->path,filename); + free(priv->path); + priv->path = safe_strdup(filename); + priv->libusb0_matched = 1; + break; + } + } + if (j >= discdevs->len) { + usbi_warn(ctx, "could not match libusb0 device %s found devices.", filename); + } + } + } + return LIBUSB_SUCCESS; } @@ -1446,9 +1589,9 @@ static int windows_get_device_list(struct libusb_context *ctx, struct discovered } handle = CreateFileA(hcd->path, GENERIC_WRITE, FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_FLAG_POSIX_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL); + NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (handle == INVALID_HANDLE_VALUE) { - usbi_warn(ctx, "could not open bus %u, skipping: %s", bus, windows_error_str(0)); + usbi_warn(ctx, "could not open bus %u path %s, skipping: %s", bus, hcd->path, windows_error_str(0)); continue; } @@ -1955,7 +2098,7 @@ unsigned __stdcall windows_clock_gettime_threaded(void* param) hires_frequency = li_frequency.QuadPart; // The hires frequency can go as high as 4 GHz, so we'll use a conversion // to picoseconds to compute the tv_nsecs part in clock_gettime - hires_ticks_to_ps = 1000000000000 / hires_frequency; + hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency; usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency); } @@ -2148,10 +2291,12 @@ static int unsupported_copy_transfer_data(struct usbi_transfer *itransfer, uint3 const char* composite_driver_names[] = {"usbccgp"}; const char* winusb_driver_names[] = {"WinUSB"}; +const char* libusb0_driver_names[] = {"libusb0"}; const char* hid_driver_names[] = {"HidUsb", "mouhid", "kbdhid"}; const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { { USB_API_UNSUPPORTED, + "unsupported", &CLASS_GUID_UNSUPPORTED, NULL, 0, @@ -2172,6 +2317,7 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { unsupported_copy_transfer_data, }, { USB_API_COMPOSITE, + "composite", &CLASS_GUID_COMPOSITE, composite_driver_names, 1, @@ -2192,6 +2338,7 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { composite_copy_transfer_data, }, { USB_API_WINUSB, + "WinUSB", &CLASS_GUID_LIBUSB_WINUSB, winusb_driver_names, 1, @@ -2210,8 +2357,30 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { winusb_abort_control, winusb_abort_transfers, winusb_copy_transfer_data, + }, { + USB_API_LIBUSB0, + "libusb0", + &CLASS_GUID_LIBUSB_LIBUSB0, + libusb0_driver_names, + 1, + libusb0_init, + libusb0_exit, + libusb0_open, + libusb0_close, + libusb0_claim_interface, + libusb0_set_interface_altsetting, + libusb0_release_interface, + libusb0_clear_halt, + libusb0_reset_device, + libusb0_submit_bulk_transfer, + libusb0_submit_iso_transfer, + libusb0_submit_control_transfer, + libusb0_abort_control, + libusb0_abort_transfers, + libusb0_copy_transfer_data, }, { USB_API_HID, + "HID", &CLASS_GUID_HID, hid_driver_names, 3, @@ -2768,6 +2937,752 @@ static int winusb_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t i return LIBUSB_TRANSFER_COMPLETED; } +/* + * Internal libusb0 Support functions (from libusb-win32) + * Note that functions that complete data transfer synchronously must return + * LIBUSB_COMPLETED instead of LIBUSB_SUCCESS + */ + +static int libusb0_io_sync(HANDLE dev, unsigned int code, void *out, int out_size, + void *in, int in_size, int *ret) +{ + OVERLAPPED ol; + DWORD _ret; + + memset(&ol, 0, sizeof(ol)); + + if(ret) + *ret = 0; + + ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + if(!ol.hEvent) + return LIBUSB_ERROR_NO_MEM; + + if(!DeviceIoControl(dev, code, out, out_size, in, in_size, NULL, &ol)) { + if(GetLastError() != ERROR_IO_PENDING) { + CloseHandle(ol.hEvent); + return LIBUSB_ERROR_IO; + } + } + + if(GetOverlappedResult(dev, &ol, &_ret, TRUE)) { + if(ret) + *ret = (int)_ret; + CloseHandle(ol.hEvent); + return LIBUSB_SUCCESS; + } + + CloseHandle(ol.hEvent); + return LIBUSB_ERROR_IO; +} + +/* + * libusb0 API functions + */ +static int libusb0_init(struct libusb_context *ctx) +{ + api_libusb0_available = true; + return LIBUSB_SUCCESS; +} + +static int libusb0_exit(void) +{ + return LIBUSB_SUCCESS; +} + +// NB: open and close must ensure that they only handle interface of +// the right API type, as these functions can be called wholesale from +// composite_open(), with interfaces belonging to different APIs +static int libusb0_open(struct libusb_device_handle *dev_handle) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_priv *priv = __device_priv(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv; + + HANDLE libusb0_handle; + int i; + libusb0_request req; + int ret; + + CHECK_LIBUSB0_AVAILABLE; + + // libusb0 has a single handle for the device +//printf("~1 path '%s' apiid %d\n",priv->path,priv->apib->id); + if ( (priv->path != NULL) + && (priv->apib->id == USB_API_LIBUSB0) ) { + char dev_name[LIBUSB0_DEVICE_NAME_MAX], *p; + + /* build the Windows file name from the unique device name */ + strcpy(dev_name, priv->path); + p = strstr(dev_name, "--"); + + if (!p) { + usbi_err(ctx, "invalid device name '%s'", priv->path); + return LIBUSB_ERROR_OTHER; + } + *p = 0; + + libusb0_handle = CreateFileA(dev_name, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + if (libusb0_handle == INVALID_HANDLE_VALUE) { + + libusb0_handle = CreateFileA(dev_name, 0, FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + + if (libusb0_handle == INVALID_HANDLE_VALUE) { + usbi_err(ctx, "could not open device %s : %s", dev_name, windows_error_str(0)); + switch(GetLastError()) { + case ERROR_FILE_NOT_FOUND: // The device was disconnected + return LIBUSB_ERROR_NO_DEVICE; + case ERROR_ACCESS_DENIED: + return LIBUSB_ERROR_ACCESS; + default: + return LIBUSB_ERROR_IO; + } + } + } + handle_priv->interface_handle[0].dev_handle = libusb0_handle; + // api_handle isn't directly used by libusb0, but use it as a + // flag to indicate if the interface has been claimed. + for (i = 0; i < USB_MAXINTERFACES; i++) + handle_priv->interface_handle[i].api_handle = 0; + + libusb0_handle = handle_priv->interface_handle[0].dev_handle; + + /* Check the version number */ + if(libusb0_io_sync(libusb0_handle, LIBUSB0_IOCTL_GET_VERSION, + &req, sizeof(libusb0_request), + &req, sizeof(libusb0_request), &ret) != LIBUSB_SUCCESS + || (ret < sizeof(libusb0_request))) { + usbi_err(ctx,"getting driver version failed (got %d expected %d)",ret,sizeof(libusb0_request)); + } else { + usbi_info(ctx,"usb_os_init: driver version: %d.%d.%d.%d", + req.version.major, req.version.minor, + req.version.micro, req.version.nano); + /* set debug level */ + req.timeout = 0; + req.debug.level = ctx->debug; + + if(libusb0_io_sync(libusb0_handle, LIBUSB0_IOCTL_SET_DEBUG_LEVEL, + &req, sizeof(libusb0_request), + NULL, 0, NULL)) { + usbi_err(ctx,"usb_os_init: setting debug level failed"); + } else { + usbi_dbg("setting debug level %d succeeded", req.debug.level); + } + } + } + + return LIBUSB_SUCCESS; +} + +static void libusb0_close(struct libusb_device_handle *dev_handle) +{ + struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv; + struct windows_device_priv *priv = __device_priv(dev_handle->dev); + HANDLE libusb0_handle; + + if (!api_libusb0_available) + return; + + if (priv->usb_interface[0].apib->id == USB_API_WINUSB) { + libusb0_handle = handle_priv->interface_handle[0].dev_handle; + if ( (libusb0_handle != 0) && (libusb0_handle != INVALID_HANDLE_VALUE)) { + CloseHandle(libusb0_handle); + } + } +} + +static int libusb0_claim_interface(struct libusb_device_handle *dev_handle, int iface) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv; + struct windows_device_priv *priv = __device_priv(dev_handle->dev); + bool is_composite = (priv->apib->id == USB_API_COMPOSITE); + HANDLE libusb0_handle; + USB_INTERFACE_DESCRIPTOR if_desc; + UCHAR policy; + uint8_t endpoint_address; + int i; + libusb0_request req; + int ret; + + CHECK_LIBUSB0_AVAILABLE; + +//printf("~1 libusb0 claim_interface() called\n"); + // interfaces for composite devices are always independent, therefore + // "alt" interfaces are only found on non-composite + if ((!is_composite) && (iface != 0)) { + +//printf("~1 not composite\n"); + // It is a requirement on Windows that to claim an interface >= 1 + // on a non-composite WinUSB device, you must first have claimed interface 0 + if (handle_priv->interface_handle[0].api_handle == 0) { // Not claimed + +//printf("~1 inteface 0 hasn't been claimed, so claim it\n"); +#if defined(AUTO_CLAIM) + libusb0_handle = handle_priv->interface_handle[0].dev_handle; + memset(&req, 0, sizeof(req)); + req.interface.interface = 0; + + if ((ret = libusb0_io_sync(libusb0_handle, LIBUSB0_IOCTL_CLAIM_INTERFACE, + &req, sizeof(libusb0_request), NULL, 0, NULL)) != LIBUSB_SUCCESS) { + usbi_warn(ctx, "failed to auto-claim interface 0 (required to claim %d with libusb0)", iface); + return LIBUSB_ERROR_ACCESS; + } else { + handle_priv->interface_handle[0].api_handle = (HANDLE)1; + usbi_warn(ctx, "auto-claimed interface 0 (required to claim %d with libusb0)", iface); + } +#else + return LIBUSB_ERROR_ACCESS; +#endif + } +//printf("~1 claiming inteface %d\n",iface); + if (handle_priv->interface_handle[iface].api_handle == 0) { // Not claimed + memset(&req, 0, sizeof(req)); + req.interface.interface = iface; +//printf("~1 inteface %d hasn't been claimed, so claim it\n",iface); + + if ((ret = libusb0_io_sync(libusb0_handle, LIBUSB0_IOCTL_CLAIM_INTERFACE, + &req, sizeof(libusb0_request), NULL, 0, NULL)) != LIBUSB_SUCCESS) { + + usbi_err(ctx, "could not claim interface %d: %s", iface, libusb_strerror(ret)); + return ret; + } + handle_priv->interface_handle[iface].api_handle = (HANDLE)1; + } + } else { +//printf("~1 claiming composite inteface %d or iface 0\n",iface); + // composite device (independent interfaces) or interface 0 + if (handle_priv->interface_handle[iface].api_handle == 0) { +//printf("~1 inteface %d hasn't been claimed, so claim it\n",iface); + libusb0_handle = handle_priv->interface_handle[0].dev_handle; + memset(&req, 0, sizeof(req)); + req.interface.interface = iface; + + if ((ret = libusb0_io_sync(libusb0_handle, LIBUSB0_IOCTL_CLAIM_INTERFACE, + &req, sizeof(libusb0_request), NULL, 0, NULL)) != LIBUSB_SUCCESS) { + + usbi_err(ctx, "could not claim interface %d: %s", iface, libusb_strerror(ret)); + return ret; + } + handle_priv->interface_handle[iface].api_handle = (HANDLE)1; + } + } + usbi_dbg("claimed interface %d", iface); + handle_priv->active_interface = iface; + + return LIBUSB_SUCCESS; +} + +static int libusb0_release_interface(struct libusb_device_handle *dev_handle, int iface) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv; + HANDLE libusb0_handle; + libusb0_request req; + int ret; + + CHECK_LIBUSB0_AVAILABLE; + + libusb0_handle = handle_priv->interface_handle[0].dev_handle; + if ((libusb0_handle == 0) || (libusb0_handle == INVALID_HANDLE_VALUE)) { + return LIBUSB_ERROR_NOT_FOUND; + } + + req.interface.interface = iface; + req.timeout = LIBUSB0_DEFAULT_TIMEOUT; + + if ((ret = libusb0_io_sync(libusb0_handle, LIBUSB0_IOCTL_RELEASE_INTERFACE, &req, + sizeof(libusb0_request), NULL, 0, NULL)) != LIBUSB_SUCCESS) { + usbi_err(ctx, "libusb0_release_interface %d failed: %s", iface, libusb_strerror(ret)); + return ret; + } + handle_priv->interface_handle[0].api_handle = 0; + + return LIBUSB_SUCCESS; +} + + +static int libusb0_submit_iso_transfer(struct usbi_transfer *itransfer) { + struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)transfer->dev_handle->os_priv; + struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev); + int num_packets = transfer->num_iso_packets; + HANDLE libusb0_handle; + bool direction_in, ret; + int current_interface; + struct winfd wfd; + libusb0_request req; + int i; + + CHECK_LIBUSB0_AVAILABLE; + + transfer_priv->pollable_fd = INVALID_WINFD; + + current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); + return LIBUSB_ERROR_NOT_FOUND; + } + + usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); + + libusb0_handle = handle_priv->interface_handle[0].dev_handle; + direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN; + + wfd = usbi_create_fd(libusb0_handle, direction_in?_O_RDONLY:_O_WRONLY, ctx); + if (wfd.fd < 0) { + return LIBUSB_ERROR_NO_MEM; + } + + /* We'll take a simple minded approach here which should succeed if + * all the iso packets are the same length. If not we abort, + * but what we should do is to break the transfer up into multiple + * transfers of same sized packets, or fix the kernel driver + * to take a list of sizes. + */ + + for (i = 1; i < transfer->num_iso_packets; i++) { + if (transfer->iso_packet_desc[i].length + != transfer->iso_packet_desc[0].length) + return LIBUSB_ERROR_NOT_SUPPORTED; + } + + req.endpoint.endpoint = transfer->endpoint; + req.endpoint.packet_size = transfer->iso_packet_desc[0].length; + + if (direction_in) { + usbi_dbg("reading %d bytes of %d packet size", transfer->length,req.endpoint.packet_size); + ret = DeviceIoControl(libusb0_handle, + LIBUSB0_IOCTL_ISOCHRONOUS_READ, + &req, sizeof(libusb0_request), + transfer->buffer, + transfer->length, NULL, wfd.overlapped); + } else { + + usbi_dbg("reading %d bytes of %d packet size", transfer->length,req.endpoint.packet_size); + ret = DeviceIoControl(libusb0_handle, + LIBUSB0_IOCTL_ISOCHRONOUS_WRITE, + &req, sizeof(libusb0_request), + transfer->buffer, + transfer->length, NULL, wfd.overlapped); + } + + if (!ret) { + if(GetLastError() != ERROR_IO_PENDING) { + usbi_err(ctx, "WinUsb_Pipe Transfer failed: %s", windows_error_str(0)); + usbi_free_fd(wfd.fd); + return LIBUSB_ERROR_IO; + } + } else { + wfd.completed_synchronously = true; + wfd.overlapped->InternalHigh = (DWORD)transfer->length; + } + + transfer_priv->pollable_fd = wfd; + transfer_priv->interface_number = (uint8_t)current_interface; + + return LIBUSB_SUCCESS; +} + + +static int libusb0_submit_control_transfer(struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)transfer->dev_handle->os_priv; + WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *) transfer->buffer; + ULONG size, in_size; + HANDLE libusb0_handle; + int current_interface; + int request_type, request, value, index, code; + void *data; + int req_size; + libusb0_request *req; + struct winfd wfd; + int ret; + + CHECK_LIBUSB0_AVAILABLE; + + transfer_priv->pollable_fd = INVALID_WINFD; + in_size = size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE; + + if (size > MAX_CTRL_BUFFER_LENGTH) + return LIBUSB_ERROR_INVALID_PARAM; + + current_interface = get_valid_interface(transfer->dev_handle); + // Attempt to claim an interface if none was found + if (current_interface < 0) +#if defined(AUTO_CLAIM) + { + for (current_interface=0; current_interfacedev_handle, current_interface) == LIBUSB_SUCCESS) { + usbi_warn(ctx, "auto-claimed interface %d for control request", current_interface); + break; + } + } + } + if (current_interface == USB_MAXINTERFACES) { + usbi_err(ctx, "no active interface"); + return LIBUSB_ERROR_NOT_FOUND; + } +#else + return LIBUSB_ERROR_NOT_FOUND; +#endif + + /* Translate from setup to libusb0_request buffer format */ + request_type = setup->request_type; + request = setup->request; + value = setup->value, + index = setup->index; + data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; + + req_size = !(request_type & LIBUSB_ENDPOINT_IN) ? sizeof(libusb0_request) + size + : sizeof(libusb0_request); + + if (!(req = malloc(req_size))) + return LIBUSB_ERROR_NO_MEM; + + if (!(request_type & LIBUSB_ENDPOINT_IN)) + memcpy((char *)req + sizeof(libusb0_request), data, size); + + req->timeout = LIBUSB0_DEFAULT_TIMEOUT; + + switch(request_type & (0x03 << 5)) + { + case LIBUSB_REQUEST_TYPE_STANDARD: + switch(request) + { + case LIBUSB_REQUEST_GET_STATUS: + req->status.recipient = 0x1f & request_type; + req->status.index = index; + code = LIBUSB0_IOCTL_GET_STATUS; + break; + + case LIBUSB_REQUEST_CLEAR_FEATURE: + req->feature.recipient = 0x1f & request_type; + req->feature.feature = value; + req->feature.index = index; + code = LIBUSB0_IOCTL_CLEAR_FEATURE; + break; + + case LIBUSB_REQUEST_SET_FEATURE: + req->feature.recipient = 0x1f & request_type; + req->feature.feature = value; + req->feature.index = index; + code = LIBUSB0_IOCTL_SET_FEATURE; + break; + + case LIBUSB_REQUEST_GET_DESCRIPTOR: + req->descriptor.recipient = 0x1f & request_type; + req->descriptor.type = (value >> 8) & 0xFF; + req->descriptor.index = value & 0xFF; + req->descriptor.language_id = index; + code = LIBUSB0_IOCTL_GET_DESCRIPTOR; + break; + + case LIBUSB_REQUEST_SET_DESCRIPTOR: + req->descriptor.recipient = 0x1f & request_type; + req->descriptor.type = (value >> 8) & 0xFF; + req->descriptor.index = value & 0xFF; + req->descriptor.language_id = index; + code = LIBUSB0_IOCTL_SET_DESCRIPTOR; + break; + + case LIBUSB_REQUEST_GET_CONFIGURATION: + code = LIBUSB0_IOCTL_GET_CONFIGURATION; + break; + + case LIBUSB_REQUEST_SET_CONFIGURATION: + req->configuration.configuration = value; + code = LIBUSB0_IOCTL_SET_CONFIGURATION; + break; + + case LIBUSB_REQUEST_GET_INTERFACE: + req->interface.interface = index; + code = LIBUSB0_IOCTL_GET_INTERFACE; + break; + + case LIBUSB_REQUEST_SET_INTERFACE: + req->interface.interface = index; + req->interface.altsetting = value; + code = LIBUSB0_IOCTL_SET_INTERFACE; + break; + + default: + free(req); + return LIBUSB_ERROR_INVALID_PARAM; + } + break; + + case LIBUSB_REQUEST_TYPE_VENDOR: + case LIBUSB_REQUEST_TYPE_CLASS: + + req->vendor.type = (request_type >> 5) & 0x03; + req->vendor.recipient = 0x1f & request_type; + req->vendor.request = request; + req->vendor.value = value; + req->vendor.index = index; + + if (request_type & LIBUSB_ENDPOINT_IN) + code = LIBUSB0_IOCTL_VENDOR_READ; + else + code = LIBUSB0_IOCTL_VENDOR_WRITE; + break; + + default: + free(req); + return LIBUSB_ERROR_INVALID_PARAM; + } + + if (!(request_type & LIBUSB_ENDPOINT_IN)) { + data = NULL; + in_size = 0; + } + + usbi_dbg("will use interface %d", current_interface); + libusb0_handle = handle_priv->interface_handle[0].dev_handle; + + wfd = usbi_create_fd(libusb0_handle, _O_RDONLY, ctx); + if (wfd.fd < 0) { + return LIBUSB_ERROR_NO_MEM; + } + + if (!DeviceIoControl(wfd.handle, code, req, req_size, data, in_size, NULL, wfd.overlapped)) { + if(GetLastError() != ERROR_IO_PENDING) { + usbi_err(ctx, "DeviceIoControl failed: %s", windows_error_str(0)); + usbi_free_fd(wfd.fd); + free(req); + return LIBUSB_ERROR_IO; + } + } else { + wfd.completed_synchronously = true; + wfd.overlapped->InternalHigh = (DWORD)size; + } + + // Use priv_transfer to store data needed for async polling + transfer_priv->pollable_fd = wfd; + transfer_priv->interface_number = (uint8_t)current_interface; + + return LIBUSB_SUCCESS; +} + +static int libusb0_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv; + HANDLE libusb0_handle; + libusb0_request req; + int ret; + + CHECK_LIBUSB0_AVAILABLE; + + if (altsetting > 255) { + return LIBUSB_ERROR_INVALID_PARAM; + } + + libusb0_handle = handle_priv->interface_handle[0].dev_handle; + if (handle_priv->interface_handle[iface].api_handle == 0) { + usbi_err(ctx, "interface must be claimed first"); + return LIBUSB_ERROR_NOT_FOUND; + } + + req.interface.interface = iface; + req.interface.altsetting = altsetting; + req.timeout = LIBUSB0_DEFAULT_TIMEOUT; + + if ((ret = libusb0_io_sync(libusb0_handle, LIBUSB0_IOCTL_SET_INTERFACE, + &req, sizeof(libusb0_request), NULL, 0, NULL)) != LIBUSB_SUCCESS) { + usbi_err(ctx, "libusb0_set_interface_altsetting intfc %d alt %d failed: %s", iface, altsetting, libusb_strerror(ret)); + return ret; + } + + return LIBUSB_SUCCESS; +} + +static int libusb0_submit_bulk_transfer(struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)transfer->dev_handle->os_priv; + struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev); + HANDLE libusb0_handle; + bool direction_in, ret; + int current_interface; + struct winfd wfd; + libusb0_request req; + + CHECK_LIBUSB0_AVAILABLE; + + transfer_priv->pollable_fd = INVALID_WINFD; + + current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); + if (current_interface < 0) { + usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); + return LIBUSB_ERROR_NOT_FOUND; + } + + usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); + + libusb0_handle = handle_priv->interface_handle[0].dev_handle; + direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN; + + wfd = usbi_create_fd(libusb0_handle, direction_in?_O_RDONLY:_O_WRONLY, ctx); + if (wfd.fd < 0) { + return LIBUSB_ERROR_NO_MEM; + } + + req.endpoint.endpoint = transfer->endpoint; + req.endpoint.packet_size = 0; + + if (direction_in) { + usbi_dbg("reading bulk %d bytes from ep %02X", transfer->length, transfer->endpoint); + ret = DeviceIoControl(libusb0_handle, + LIBUSB0_IOCTL_INTERRUPT_OR_BULK_READ, + &req, sizeof(libusb0_request), + transfer->buffer, + transfer->length, NULL, wfd.overlapped); + } else { + + usbi_dbg("writing bulk %d bytes from ep %02X", transfer->length, transfer->endpoint); + ret = DeviceIoControl(libusb0_handle, + LIBUSB0_IOCTL_INTERRUPT_OR_BULK_WRITE, + &req, sizeof(libusb0_request), + transfer->buffer, + transfer->length, NULL, wfd.overlapped); + } + + if (!ret) { + if(GetLastError() != ERROR_IO_PENDING) { + usbi_err(ctx, "WinUsb_Pipe Transfer failed: %s", windows_error_str(0)); + usbi_free_fd(wfd.fd); + return LIBUSB_ERROR_IO; + } + } else { + wfd.completed_synchronously = true; + wfd.overlapped->InternalHigh = (DWORD)transfer->length; + } + + transfer_priv->pollable_fd = wfd; + transfer_priv->interface_number = (uint8_t)current_interface; + + return LIBUSB_SUCCESS; +} + +static int libusb0_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv; + struct windows_device_priv *priv = __device_priv(dev_handle->dev); + HANDLE libusb0_handle; + libusb0_request req; + int ret; + + CHECK_LIBUSB0_AVAILABLE; + + libusb0_handle = handle_priv->interface_handle[0].dev_handle; + + req.endpoint.endpoint = (int)endpoint; + req.timeout = LIBUSB0_DEFAULT_TIMEOUT; + + if ((ret = libusb0_io_sync(libusb0_handle, LIBUSB0_IOCTL_RESET_ENDPOINT, &req, + sizeof(libusb0_request), NULL, 0, NULL)) != LIBUSB_SUCCESS) { + usbi_err(ctx, "libus0 reset endpoint 0x%02x failed: %s", endpoint, libusb_strerror(ret)); + return ret; + } + + return LIBUSB_SUCCESS; +} + +static int libusb0_abort_control(struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)transfer->dev_handle->os_priv; + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + HANDLE libusb0_handle; + libusb0_request req; + int ret; + + CHECK_LIBUSB0_AVAILABLE; + + libusb0_handle = handle_priv->interface_handle[0].dev_handle; + + req.endpoint.endpoint = 0; + req.timeout = LIBUSB0_DEFAULT_TIMEOUT; + + if ((ret = libusb0_io_sync(libusb0_handle, LIBUSB0_IOCTL_ABORT_ENDPOINT, + &req, sizeof(libusb0_request), NULL, 0, NULL)) != LIBUSB_SUCCESS) { + usbi_err(ctx, "libusb0_abort_control failed: %s", libusb_strerror(ret)); + return ret; + } + + return LIBUSB_SUCCESS; +} + +static int libusb0_abort_transfers(struct usbi_transfer *itransfer) +{ + struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); + struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)transfer->dev_handle->os_priv; + struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); + HANDLE libusb0_handle; + libusb0_request req; + int ret; + + CHECK_LIBUSB0_AVAILABLE; + + libusb0_handle = handle_priv->interface_handle[0].dev_handle; + + req.endpoint.endpoint = (int)transfer->endpoint; + req.timeout = LIBUSB0_DEFAULT_TIMEOUT; + + if ((ret = libusb0_io_sync(libusb0_handle, LIBUSB0_IOCTL_ABORT_ENDPOINT, + &req, sizeof(libusb0_request), NULL, 0, NULL)) != LIBUSB_SUCCESS) { + usbi_err(ctx, "libusb0_abort_transfer endpoint 0x%02x failed: %s", transfer->endpoint, libusb_strerror(ret)); + return ret; + } + + return LIBUSB_SUCCESS; +} + +static int libusb0_reset_device(struct libusb_device_handle *dev_handle) +{ + struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); + struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv; + struct windows_device_priv *priv = __device_priv(dev_handle->dev); + HANDLE libusb0_handle; + libusb0_request req; + int ret; + + CHECK_LIBUSB0_AVAILABLE; + + libusb0_handle = handle_priv->interface_handle[0].dev_handle; + + req.timeout = LIBUSB0_DEFAULT_TIMEOUT; + + if ((ret = libusb0_io_sync(libusb0_handle, LIBUSB0_IOCTL_RESET_DEVICE, + &req, sizeof(libusb0_request), NULL, 0, NULL)) != LIBUSB_SUCCESS) { + usbi_err(ctx, "libusb0_reset_device failed: %s", libusb_strerror(ret)); + return ret; + } + + return LIBUSB_SUCCESS; +} + +static int libusb0_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) +{ + itransfer->transferred += io_size; + return LIBUSB_TRANSFER_COMPLETED; +} + + /* * Internal HID Support functions (from libusb-win32) * Note that functions that complete data transfer synchronously must return diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h index fdb8549..59dde57 100644 --- a/libusb/os/windows_usb.h +++ b/libusb/os/windows_usb.h @@ -85,6 +85,7 @@ inline void upperize(char* str) { str[i] = (char)toupper((int)str[i]); } +#define HCNUM_TO_CHECK 10 #define MAX_CTRL_BUFFER_LENGTH 4096 #define MAX_USB_DEVICES 256 #define MAX_USB_STRING_LENGTH 128 @@ -118,16 +119,19 @@ const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0 #define USB_API_UNSUPPORTED 0 #define USB_API_COMPOSITE 1 #define USB_API_WINUSB 2 -#define USB_API_HID 3 -#define USB_API_MAX 4 +#define USB_API_LIBUSB0 3 +#define USB_API_HID 4 +#define USB_API_MAX 5 -const GUID CLASS_GUID_UNSUPPORTED = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x57, 0xDA} }; -const GUID CLASS_GUID_HID = { 0x745A17A0, 0x74D3, 0x11D0, {0xB6, 0xFE, 0x00, 0xA0, 0xC9, 0x0F, 0x57, 0xDA} }; -const GUID CLASS_GUID_LIBUSB_WINUSB = { 0x78A1C341, 0x4539, 0x11D3, {0xB8, 0x8D, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71} }; -const GUID CLASS_GUID_COMPOSITE = { 0x36FC9E60, 0xC465, 0x11cF, {0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} }; +const GUID CLASS_GUID_UNSUPPORTED = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x57, 0xDA} }; +const GUID CLASS_GUID_HID = { 0x745A17A0, 0x74D3, 0x11D0, {0xB6, 0xFE, 0x00, 0xA0, 0xC9, 0x0F, 0x57, 0xDA} }; +const GUID CLASS_GUID_LIBUSB_WINUSB = { 0x78A1C341, 0x4539, 0x11D3, {0xB8, 0x8D, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71} }; +const GUID CLASS_GUID_LIBUSB_LIBUSB0 = { 0xEB781AAF, 0x9C70, 0x4523, {0xA5, 0xDF, 0x64, 0x2A, 0x87, 0xEC, 0xA5, 0x67} }; +const GUID CLASS_GUID_COMPOSITE = { 0x36FC9E60, 0xC465, 0x11cF, {0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} }; struct windows_usb_api_backend { const uint8_t id; + const char *backend_name; const GUID *class_guid; // The Class GUID (for fallback in case the driver name cannot be read) const char **driver_name_list; // Driver name, without .sys, e.g. "usbccgp" const uint8_t nb_driver_names; @@ -243,6 +247,7 @@ struct windows_device_priv { uint8_t active_config; USB_DEVICE_DESCRIPTOR dev_descriptor; unsigned char **config_descriptor; // list of pointers to the cached config descriptors + uint8_t libusb0_matched; // Flag indicating libusb0 driver has set the path }; static inline void windows_device_priv_init(struct windows_device_priv* p) { @@ -312,6 +317,7 @@ struct windows_transfer_priv { /* * API macros - from libusb-win32 1.x */ + #define DLL_DECLARE(api, ret, name, args) \ typedef ret (api * __dll_##name##_t)args; __dll_##name##_t name @@ -382,6 +388,12 @@ typedef RETURN_TYPE CONFIGRET; #ifndef METHOD_BUFFERED #define METHOD_BUFFERED 0 #endif +#ifndef METHOD_IN_DIRECT +#define METHOD_IN_DIRECT 1 +#endif +#ifndef METHOD_OUT_DIRECT +#define METHOD_OUT_DIRECT 2 +#endif #ifndef FILE_ANY_ACCESS #define FILE_ANY_ACCESS 0x00000000 #endif @@ -415,6 +427,7 @@ typedef enum _USB_HUB_NODE { } USB_HUB_NODE; /* Cfgmgr32.dll interface */ + DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG)); DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG)); DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Sibling, (PDEVINST, DEVINST, ULONG)); @@ -622,9 +635,9 @@ typedef struct _USB_HUB_CAPABILITIES_EX { #define AUTO_SUSPEND 0x81 #define SUSPEND_DELAY 0x83 #define DEVICE_SPEED 0x01 -#define LowSpeed 0x01 -#define FullSpeed 0x02 -#define HighSpeed 0x03 +#define wuLowSpeed 0x01 +#define wuFullSpeed 0x02 +#define wuHighSpeed 0x03 typedef enum _USBD_PIPE_TYPE { UsbdPipeTypeControl, @@ -670,6 +683,18 @@ DLL_DECLARE(WINAPI, BOOL, WinUsb_ResetPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); DLL_DECLARE(WINAPI, BOOL, WinUsb_AbortPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); DLL_DECLARE(WINAPI, BOOL, WinUsb_FlushPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); +/* + * libusb0 API definitions from libusb0-win32. + */ + +#include "driver/driver_api.h" + +#define LIBUSB0_DEFAULT_TIMEOUT 5000 +#define LIBUSB0_DEVICE_NAME "\\\\.\\libusb0-" +#define LIBUSB0_BUS_NAME "bus-0" +#define LIBUSB0_DEVICE_NAME_MAX 256 +#define LIBUSB0_MAX_DEVICES 256 + /* hid.dll interface */ #define HIDP_STATUS_SUCCESS 0x110000 -- cgit v1.2.1