diff options
Diffstat (limited to 'include/libusb-1.0/os')
-rw-r--r-- | include/libusb-1.0/os/config.h | 105 | ||||
-rw-r--r-- | include/libusb-1.0/os/darwin_usb.c | 1545 | ||||
-rw-r--r-- | include/libusb-1.0/os/darwin_usb.h | 167 | ||||
-rw-r--r-- | include/libusb-1.0/os/libusb.h | 1322 | ||||
-rw-r--r-- | include/libusb-1.0/os/libusbi.h | 872 | ||||
-rw-r--r-- | include/libusb-1.0/os/linux_usbfs.c | 2220 | ||||
-rw-r--r-- | include/libusb-1.0/os/linux_usbfs.h | 138 | ||||
-rw-r--r-- | include/libusb-1.0/os/poll_posix.h | 12 | ||||
-rw-r--r-- | include/libusb-1.0/os/poll_windows.c | 860 | ||||
-rw-r--r-- | include/libusb-1.0/os/poll_windows.h | 120 | ||||
-rw-r--r-- | include/libusb-1.0/os/threads_posix.h | 46 | ||||
-rw-r--r-- | include/libusb-1.0/os/threads_windows.c | 208 | ||||
-rw-r--r-- | include/libusb-1.0/os/threads_windows.h | 84 | ||||
-rw-r--r-- | include/libusb-1.0/os/windows_usb.c | 4185 | ||||
-rw-r--r-- | include/libusb-1.0/os/windows_usb.h | 784 |
15 files changed, 0 insertions, 12668 deletions
diff --git a/include/libusb-1.0/os/config.h b/include/libusb-1.0/os/config.h deleted file mode 100644 index 643d4af..0000000 --- a/include/libusb-1.0/os/config.h +++ /dev/null @@ -1,105 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Default visibility */ -#define DEFAULT_VISIBILITY __attribute__((visibility("default"))) - -/* Debug message logging */ -/* #undef ENABLE_DEBUG_LOGGING */ - -/* Message logging */ -#define ENABLE_LOGGING 1 - -/* Define to 1 if you have the <dlfcn.h> header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the <inttypes.h> header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the <memory.h> header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the <stdint.h> header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the <strings.h> header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the <string.h> header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if the system has the type `struct timespec'. */ -#define HAVE_STRUCT_TIMESPEC 1 - -/* Define to 1 if you have the <sys/stat.h> header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the <sys/time.h> header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the <sys/types.h> header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the <unistd.h> header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#define LT_OBJDIR ".libs/" - -/* Define to 1 if your C compiler doesn't accept -c and -o together. */ -/* #undef NO_MINUS_C_MINUS_O */ - -/* Darwin backend */ -#define OS_DARWIN - -/* Linux backend */ -/* #undef OS_LINUX */ - -/* Windows backend */ -/* #undef OS_WINDOWS */ - -/* Name of package */ -#define PACKAGE "libusb" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "libusb-devel@lists.sourceforge.net" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "libusb" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libusb 1.0.8" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libusb" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "1.0.8" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Use Posix Threads */ -#define THREADS_POSIX - -/* Backend handles timeout */ -#define USBI_OS_HANDLES_TIMEOUT - -/* timerfd headers available */ -/* #undef USBI_TIMERFD_AVAILABLE */ - -/* Version number of package */ -#define VERSION "1.0.8" - -/* Use GNU extensions */ -#define _GNU_SOURCE - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif diff --git a/include/libusb-1.0/os/darwin_usb.c b/include/libusb-1.0/os/darwin_usb.c deleted file mode 100644 index 646c938..0000000 --- a/include/libusb-1.0/os/darwin_usb.c +++ /dev/null @@ -1,1545 +0,0 @@ -/* - * darwin backend for libusb 1.0 - * Copyright (C) 2008-2010 Nathan Hjelm <hjelmn@users.sourceforge.net> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <config.h> -#include <ctype.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include <mach/clock.h> -#include <mach/clock_types.h> -#include <mach/mach_host.h> - -#include <mach/mach_port.h> -#include <IOKit/IOCFBundle.h> -#include <IOKit/usb/IOUSBLib.h> -#include <IOKit/IOCFPlugIn.h> - -#include "darwin_usb.h" - -static mach_port_t libusb_darwin_mp = 0; /* master port */ -static CFRunLoopRef libusb_darwin_acfl = NULL; /* async cf loop */ -static int initCount = 0; - -/* async event thread */ -static pthread_t libusb_darwin_at; - -static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian); -static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface); -static int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface); -static int darwin_reset_device(struct libusb_device_handle *dev_handle); -static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0); - -static const char *darwin_error_str (int result) { - switch (result) { - case kIOReturnSuccess: - return "no error"; - case kIOReturnNotOpen: - return "device not opened for exclusive access"; - case kIOReturnNoDevice: - return "no connection to an IOService"; - case kIOUSBNoAsyncPortErr: - return "no async port has been opened for interface"; - case kIOReturnExclusiveAccess: - return "another process has device opened for exclusive access"; - case kIOUSBPipeStalled: - return "pipe is stalled"; - case kIOReturnError: - return "could not establish a connection to the Darwin kernel"; - case kIOUSBTransactionTimeout: - return "transaction timed out"; - case kIOReturnBadArgument: - return "invalid argument"; - case kIOReturnAborted: - return "transaction aborted"; - case kIOReturnNotResponding: - return "device not responding"; - case kIOReturnOverrun: - return "data overrun"; - case kIOReturnCannotWire: - return "physical memory can not be wired down"; - default: - return "unknown error"; - } -} - -static int darwin_to_libusb (int result) { - switch (result) { - case kIOReturnUnderrun: - case kIOReturnSuccess: - return LIBUSB_SUCCESS; - case kIOReturnNotOpen: - case kIOReturnNoDevice: - return LIBUSB_ERROR_NO_DEVICE; - case kIOReturnExclusiveAccess: - return LIBUSB_ERROR_ACCESS; - case kIOUSBPipeStalled: - return LIBUSB_ERROR_PIPE; - case kIOReturnBadArgument: - return LIBUSB_ERROR_INVALID_PARAM; - case kIOUSBTransactionTimeout: - return LIBUSB_ERROR_TIMEOUT; - case kIOReturnNotResponding: - case kIOReturnAborted: - case kIOReturnError: - case kIOUSBNoAsyncPortErr: - default: - return LIBUSB_ERROR_OTHER; - } -} - - -static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, uint8_t *pipep, uint8_t *ifcp) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - - /* current interface */ - struct __darwin_interface *cInterface; - - int8_t i, iface; - - usbi_info (HANDLE_CTX(dev_handle), "converting ep address 0x%02x to pipeRef and interface", ep); - - for (iface = 0 ; iface < USB_MAXINTERFACES ; iface++) { - cInterface = &priv->interfaces[iface]; - - if (dev_handle->claimed_interfaces & (1 << iface)) { - for (i = 0 ; i < cInterface->num_endpoints ; i++) { - if (cInterface->endpoint_addrs[i] == ep) { - *pipep = i + 1; - *ifcp = iface; - usbi_info (HANDLE_CTX(dev_handle), "pipe %d on interface %d matches", *pipep, *ifcp); - return 0; - } - } - } - } - - /* No pipe found with the correct endpoint address */ - usbi_warn (HANDLE_CTX(dev_handle), "no pipeRef found with endpoint address 0x%02x.", ep); - - return -1; -} - -static int usb_setup_device_iterator (io_iterator_t *deviceIterator) { - return IOServiceGetMatchingServices(libusb_darwin_mp, IOServiceMatching(kIOUSBDeviceClassName), deviceIterator); -} - -static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator, UInt32 *locationp) { - io_cf_plugin_ref_t *plugInInterface = NULL; - usb_device_t **device; - io_service_t usbDevice; - long result; - SInt32 score; - - if (!IOIteratorIsValid (deviceIterator)) - return NULL; - - - while ((usbDevice = IOIteratorNext(deviceIterator))) { - result = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, - kIOCFPlugInInterfaceID, &plugInInterface, - &score); - if (kIOReturnSuccess == result && plugInInterface) - break; - - usbi_dbg ("libusb/darwin.c usb_get_next_device: could not set up plugin for service: %s\n", darwin_error_str (result)); - } - - if (!usbDevice) - return NULL; - - (void)IOObjectRelease(usbDevice); - (void)(*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID), - (LPVOID)&device); - - (*plugInInterface)->Stop(plugInInterface); - IODestroyPlugInInterface (plugInInterface); - - /* get the location from the device */ - if (locationp) - (*(device))->GetLocationID(device, locationp); - - return device; -} - -static kern_return_t darwin_get_device (uint32_t dev_location, usb_device_t ***darwin_device) { - kern_return_t kresult; - UInt32 location; - io_iterator_t deviceIterator; - - kresult = usb_setup_device_iterator (&deviceIterator); - if (kresult) - return kresult; - - /* This port of libusb uses locations to keep track of devices. */ - while ((*darwin_device = usb_get_next_device (deviceIterator, &location)) != NULL) { - if (location == dev_location) - break; - - (**darwin_device)->Release(*darwin_device); - } - - IOObjectRelease (deviceIterator); - - if (!(*darwin_device)) - return kIOReturnNoDevice; - - return kIOReturnSuccess; -} - - - -static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) { - struct libusb_context *ctx = (struct libusb_context *)ptr; - struct libusb_device_handle *handle; - struct darwin_device_priv *dpriv; - struct darwin_device_handle_priv *priv; - - io_service_t device; - long location; - CFTypeRef locationCF; - UInt32 message; - - usbi_info (ctx, "a device has been detached"); - - while ((device = IOIteratorNext (rem_devices)) != 0) { - /* get the location from the i/o registry */ - locationCF = IORegistryEntryCreateCFProperty (device, CFSTR(kUSBDevicePropertyLocationID), kCFAllocatorDefault, 0); - - CFNumberGetValue(locationCF, kCFNumberLongType, &location); - CFRelease (locationCF); - IOObjectRelease (device); - - usbi_mutex_lock(&ctx->open_devs_lock); - list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) { - dpriv = (struct darwin_device_priv *)handle->dev->os_priv; - - /* the device may have been opened several times. write to each handle's event descriptor */ - if (dpriv->location == location && handle->os_priv) { - priv = (struct darwin_device_handle_priv *)handle->os_priv; - - message = MESSAGE_DEVICE_GONE; - write (priv->fds[1], &message, sizeof (message)); - } - } - - usbi_mutex_unlock(&ctx->open_devs_lock); - } -} - -static void darwin_clear_iterator (io_iterator_t iter) { - io_service_t device; - - while ((device = IOIteratorNext (iter)) != 0) - IOObjectRelease (device); -} - -static void *event_thread_main (void *arg0) { - IOReturn kresult; - struct libusb_context *ctx = (struct libusb_context *)arg0; - - /* hotplug (device removal) source */ - CFRunLoopSourceRef libusb_notification_cfsource; - io_notification_port_t libusb_notification_port; - io_iterator_t libusb_rem_device_iterator; - - usbi_info (ctx, "creating hotplug event source"); - - CFRetain (CFRunLoopGetCurrent ()); - - /* add the notification port to the run loop */ - libusb_notification_port = IONotificationPortCreate (libusb_darwin_mp); - libusb_notification_cfsource = IONotificationPortGetRunLoopSource (libusb_notification_port); - CFRunLoopAddSource(CFRunLoopGetCurrent (), libusb_notification_cfsource, kCFRunLoopDefaultMode); - - /* create notifications for removed devices */ - kresult = IOServiceAddMatchingNotification (libusb_notification_port, kIOTerminatedNotification, - IOServiceMatching(kIOUSBDeviceClassName), - (IOServiceMatchingCallback)darwin_devices_detached, - (void *)ctx, &libusb_rem_device_iterator); - - if (kresult != kIOReturnSuccess) { - usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult)); - - pthread_exit ((void *)kresult); - } - - /* arm notifiers */ - darwin_clear_iterator (libusb_rem_device_iterator); - - /* let the main thread know about the async runloop */ - libusb_darwin_acfl = CFRunLoopGetCurrent (); - - usbi_info (ctx, "thread ready to receive events"); - - /* run the runloop */ - CFRunLoopRun(); - - usbi_info (ctx, "thread exiting"); - - /* delete notification port */ - CFRunLoopSourceInvalidate (libusb_notification_cfsource); - IONotificationPortDestroy (libusb_notification_port); - - CFRelease (CFRunLoopGetCurrent ()); - - libusb_darwin_acfl = NULL; - - pthread_exit (0); -} - -static int darwin_init(struct libusb_context *ctx) { - IOReturn kresult; - - if (!(initCount++)) { - /* Create the master port for talking to IOKit */ - if (!libusb_darwin_mp) { - kresult = IOMasterPort (MACH_PORT_NULL, &libusb_darwin_mp); - - if (kresult != kIOReturnSuccess || !libusb_darwin_mp) - return darwin_to_libusb (kresult); - } - - pthread_create (&libusb_darwin_at, NULL, event_thread_main, (void *)ctx); - - while (!libusb_darwin_acfl) - usleep (10); - } - - return 0; -} - -static void darwin_exit (void) { - if (!(--initCount)) { - void *ret; - - /* stop the async runloop */ - CFRunLoopStop (libusb_darwin_acfl); - pthread_join (libusb_darwin_at, &ret); - - if (libusb_darwin_mp) - mach_port_deallocate(mach_task_self(), libusb_darwin_mp); - - libusb_darwin_mp = 0; - } -} - -static int darwin_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian) { - struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv; - - /* return cached copy */ - memmove (buffer, &(priv->dev_descriptor), DEVICE_DESC_LENGTH); - - *host_endian = 0; - - return 0; -} - -static int get_configuration_index (struct libusb_device *dev, int config_value) { - struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv; - UInt8 i, numConfig; - IOUSBConfigurationDescriptorPtr desc; - IOReturn kresult; - - /* is there a simpler way to determine the index? */ - kresult = (*(priv->device))->GetNumberOfConfigurations (priv->device, &numConfig); - if (kresult != kIOReturnSuccess) - return darwin_to_libusb (kresult); - - for (i = 0 ; i < numConfig ; i++) { - (*(priv->device))->GetConfigurationDescriptorPtr (priv->device, i, &desc); - - if (desc->bConfigurationValue == config_value) - return i; - } - - /* configuration not found */ - return LIBUSB_ERROR_OTHER; -} - -static int darwin_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) { - struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv; - int config_index; - - if (0 == priv->active_config) - return LIBUSB_ERROR_INVALID_PARAM; - - config_index = get_configuration_index (dev, priv->active_config); - if (config_index < 0) - return config_index; - - return darwin_get_config_descriptor (dev, config_index, buffer, len, host_endian); -} - -static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) { - struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv; - IOUSBConfigurationDescriptorPtr desc; - IOReturn kresult; - usb_device_t **device = NULL; - - if (!priv) - return LIBUSB_ERROR_OTHER; - - if (!priv->device) { - kresult = darwin_get_device (priv->location, &device); - if (kresult || !device) { - usbi_err (DEVICE_CTX (dev), "could not find device: %s", darwin_error_str (kresult)); - - return darwin_to_libusb (kresult); - } - - /* don't have to open the device to get a config descriptor */ - } else - device = priv->device; - - kresult = (*device)->GetConfigurationDescriptorPtr (device, config_index, &desc); - if (kresult == kIOReturnSuccess) { - /* copy descriptor */ - if (libusb_le16_to_cpu(desc->wTotalLength) < len) - len = libusb_le16_to_cpu(desc->wTotalLength); - - memmove (buffer, desc, len); - - /* GetConfigurationDescriptorPtr returns the descriptor in USB bus order */ - *host_endian = 0; - } - - if (!priv->device) - (*device)->Release (device); - - return darwin_to_libusb (kresult); -} - -/* check whether the os has configured the device */ -static int darwin_check_configuration (struct libusb_context *ctx, struct libusb_device *dev, usb_device_t **darwin_device) { - struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv; - - IOUSBConfigurationDescriptorPtr configDesc; - IOUSBFindInterfaceRequest request; - kern_return_t kresult; - io_iterator_t interface_iterator; - io_service_t firstInterface; - - if (priv->dev_descriptor.bNumConfigurations < 1) { - usbi_err (ctx, "device has no configurations"); - return LIBUSB_ERROR_OTHER; /* no configurations at this speed so we can't use it */ - } - - /* find the first configuration */ - kresult = (*darwin_device)->GetConfigurationDescriptorPtr (darwin_device, 0, &configDesc); - priv->first_config = (kIOReturnSuccess == kresult) ? configDesc->bConfigurationValue : 1; - - /* check if the device is already configured. there is probably a better way than iterating over the - to accomplish this (the trick is we need to avoid a call to GetConfigurations since buggy devices - might lock up on the device request) */ - - /* Setup the Interface Request */ - request.bInterfaceClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; - request.bAlternateSetting = kIOUSBFindInterfaceDontCare; - - kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator); - if (kresult) - return darwin_to_libusb (kresult); - - /* iterate once */ - firstInterface = IOIteratorNext(interface_iterator); - - /* done with the interface iterator */ - IOObjectRelease(interface_iterator); - - if (firstInterface) { - IOObjectRelease (firstInterface); - - /* device is configured */ - if (priv->dev_descriptor.bNumConfigurations == 1) - /* to avoid problems with some devices get the configurations value from the configuration descriptor */ - priv->active_config = priv->first_config; - else - /* devices with more than one configuration should work with GetConfiguration */ - (*darwin_device)->GetConfiguration (darwin_device, &priv->active_config); - } else - /* not configured */ - priv->active_config = 0; - - usbi_info (ctx, "active config: %u, first config: %u", priv->active_config, priv->first_config); - - return 0; -} - -static int process_new_device (struct libusb_context *ctx, usb_device_t **device, UInt32 locationID, struct discovered_devs **_discdevs) { - struct darwin_device_priv *priv; - struct libusb_device *dev; - struct discovered_devs *discdevs; - UInt16 address, idVendor, idProduct; - UInt8 bDeviceClass, bDeviceSubClass; - IOUSBDevRequest req; - int ret = 0, need_unref = 0; - - do { - dev = usbi_get_device_by_session_id(ctx, locationID); - if (!dev) { - usbi_info (ctx, "allocating new device for location 0x%08x", locationID); - dev = usbi_alloc_device(ctx, locationID); - need_unref = 1; - } else - usbi_info (ctx, "using existing device for location 0x%08x", locationID); - - if (!dev) { - ret = LIBUSB_ERROR_NO_MEM; - break; - } - - priv = (struct darwin_device_priv *)dev->os_priv; - - /* Set up request for device descriptor */ - req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); - req.bRequest = kUSBRqGetDescriptor; - req.wValue = kUSBDeviceDesc << 8; - req.wIndex = 0; - req.wLength = sizeof(IOUSBDeviceDescriptor); - req.pData = &(priv->dev_descriptor); - - (*(device))->GetDeviceAddress (device, (USBDeviceAddress *)&address); - (*(device))->GetDeviceProduct (device, &idProduct); - (*(device))->GetDeviceVendor (device, &idVendor); - (*(device))->GetDeviceClass (device, &bDeviceClass); - (*(device))->GetDeviceSubClass (device, &bDeviceSubClass); - - /**** retrieve device descriptors ****/ - /* according to Apple's documentation the device must be open for DeviceRequest but we may not be able to open some - * devices and Apple's USB Prober doesn't bother to open the device before issuing a descriptor request */ - ret = (*(device))->DeviceRequest (device, &req); - if (ret != kIOReturnSuccess) { - int try_unsuspend = 1; -#if DeviceVersion >= 320 - UInt32 info; - - /* device may be suspended. unsuspend it and try again */ - /* IOUSBFamily 320+ provides a way to detect device suspension but earlier versions do not */ - (void)(*device)->GetUSBDeviceInformation (device, &info); - - try_unsuspend = info & (1 << kUSBInformationDeviceIsSuspendedBit); -#endif - - /* the device should be open before to device is unsuspended */ - (void) (*device)->USBDeviceOpenSeize(device); - - if (try_unsuspend) { - /* resume the device */ - (void)(*device)->USBDeviceSuspend (device, 0); - - ret = (*(device))->DeviceRequest (device, &req); - - /* resuspend the device */ - (void)(*device)->USBDeviceSuspend (device, 1); - } - - (*device)->USBDeviceClose (device); - } - - if (ret != kIOReturnSuccess) { - usbi_warn (ctx, "could not retrieve device descriptor: %s. skipping device", darwin_error_str (ret)); - ret = -1; - break; - } - - /**** end: retrieve device descriptors ****/ - - /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices. */ - if (libusb_le16_to_cpu (priv->dev_descriptor.idProduct) != idProduct) { - /* not a valid device */ - usbi_warn (ctx, "idProduct from iokit (%04x) does not match idProduct in descriptor (%04x). skipping device", - idProduct, libusb_le16_to_cpu (priv->dev_descriptor.idProduct)); - ret = -1; - break; - } - - dev->bus_number = locationID >> 24; - dev->device_address = address; - - /* check current active configuration (and cache the first configuration value-- which may be used by claim_interface) */ - ret = darwin_check_configuration (ctx, dev, device); - if (ret < 0) - break; - - /* save our location, we'll need this later */ - priv->location = locationID; - snprintf(priv->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", address, idVendor, idProduct, bDeviceClass, bDeviceSubClass); - - ret = usbi_sanitize_device (dev); - if (ret < 0) - break; - - /* append the device to the list of discovered devices */ - discdevs = discovered_devs_append(*_discdevs, dev); - if (!discdevs) { - ret = LIBUSB_ERROR_NO_MEM; - break; - } - - *_discdevs = discdevs; - - usbi_info (ctx, "found device with address %d at %s", dev->device_address, priv->sys_path); - } while (0); - - if (need_unref) - libusb_unref_device(dev); - - return ret; -} - -static int darwin_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs) { - io_iterator_t deviceIterator; - usb_device_t **device; - kern_return_t kresult; - UInt32 location; - - if (!libusb_darwin_mp) - return LIBUSB_ERROR_INVALID_PARAM; - - kresult = usb_setup_device_iterator (&deviceIterator); - if (kresult != kIOReturnSuccess) - return darwin_to_libusb (kresult); - - while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) { - (void) process_new_device (ctx, device, location, _discdevs); - - (*(device))->Release(device); - } - - IOObjectRelease(deviceIterator); - - return 0; -} - -static int darwin_open (struct libusb_device_handle *dev_handle) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; - usb_device_t **darwin_device; - IOReturn kresult; - - if (0 == dpriv->open_count) { - kresult = darwin_get_device (dpriv->location, &darwin_device); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "could not find device: %s", darwin_error_str (kresult)); - return darwin_to_libusb (kresult); - } - - dpriv->device = darwin_device; - - /* try to open the device */ - kresult = (*(dpriv->device))->USBDeviceOpenSeize (dpriv->device); - - if (kresult != kIOReturnSuccess) { - usbi_err (HANDLE_CTX (dev_handle), "USBDeviceOpen: %s", darwin_error_str(kresult)); - - switch (kresult) { - case kIOReturnExclusiveAccess: - /* it is possible to perform some actions on a device that is not open so do not return an error */ - priv->is_open = 0; - - break; - default: - (*(dpriv->device))->Release (dpriv->device); - dpriv->device = NULL; - return darwin_to_libusb (kresult); - } - } else { - priv->is_open = 1; - - /* create async event source */ - kresult = (*(dpriv->device))->CreateDeviceAsyncEventSource (dpriv->device, &priv->cfSource); - - CFRetain (libusb_darwin_acfl); - - /* add the cfSource to the aync run loop */ - CFRunLoopAddSource(libusb_darwin_acfl, priv->cfSource, kCFRunLoopCommonModes); - } - } - - /* device opened successfully */ - dpriv->open_count++; - - /* create a file descriptor for notifications */ - pipe (priv->fds); - - /* set the pipe to be non-blocking */ - fcntl (priv->fds[1], F_SETFD, O_NONBLOCK); - - usbi_add_pollfd(HANDLE_CTX(dev_handle), priv->fds[0], POLLIN); - - usbi_info (HANDLE_CTX (dev_handle), "device open for access"); - - return 0; -} - -static void darwin_close (struct libusb_device_handle *dev_handle) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; - IOReturn kresult; - int i; - - if (dpriv->open_count == 0) { - /* something is probably very wrong if this is the case */ - usbi_err (HANDLE_CTX (dev_handle), "Close called on a device that was not open!\n"); - return; - } - - dpriv->open_count--; - - /* make sure all interfaces are released */ - for (i = 0 ; i < USB_MAXINTERFACES ; i++) - if (dev_handle->claimed_interfaces & (1 << i)) - libusb_release_interface (dev_handle, i); - - if (0 == dpriv->open_count) { - if (priv->is_open) { - /* delete the device's async event source */ - if (priv->cfSource) { - CFRunLoopRemoveSource (libusb_darwin_acfl, priv->cfSource, kCFRunLoopDefaultMode); - CFRelease (priv->cfSource); - } - - /* close the device */ - kresult = (*(dpriv->device))->USBDeviceClose(dpriv->device); - if (kresult) { - /* Log the fact that we had a problem closing the file, however failing a - * close isn't really an error, so return success anyway */ - usbi_err (HANDLE_CTX (dev_handle), "USBDeviceClose: %s", darwin_error_str(kresult)); - } - } - - kresult = (*(dpriv->device))->Release(dpriv->device); - if (kresult) { - /* Log the fact that we had a problem closing the file, however failing a - * close isn't really an error, so return success anyway */ - usbi_err (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult)); - } - - dpriv->device = NULL; - } - - /* file descriptors are maintained per-instance */ - usbi_remove_pollfd (HANDLE_CTX (dev_handle), priv->fds[0]); - close (priv->fds[1]); - close (priv->fds[0]); - - priv->fds[0] = priv->fds[1] = -1; -} - -static int darwin_get_configuration(struct libusb_device_handle *dev_handle, int *config) { - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; - - *config = (int) dpriv->active_config; - - return 0; -} - -static int darwin_set_configuration(struct libusb_device_handle *dev_handle, int config) { - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; - IOReturn kresult; - int i; - - /* Setting configuration will invalidate the interface, so we need - to reclaim it. First, dispose of existing interfaces, if any. */ - for (i = 0 ; i < USB_MAXINTERFACES ; i++) - if (dev_handle->claimed_interfaces & (1 << i)) - darwin_release_interface (dev_handle, i); - - kresult = (*(dpriv->device))->SetConfiguration (dpriv->device, config); - if (kresult != kIOReturnSuccess) - return darwin_to_libusb (kresult); - - /* Reclaim any interfaces. */ - for (i = 0 ; i < USB_MAXINTERFACES ; i++) - if (dev_handle->claimed_interfaces & (1 << i)) - darwin_claim_interface (dev_handle, i); - - dpriv->active_config = config; - - return 0; -} - -static int darwin_get_interface (usb_device_t **darwin_device, uint8_t ifc, io_service_t *usbInterfacep) { - IOUSBFindInterfaceRequest request; - uint8_t current_interface; - kern_return_t kresult; - io_iterator_t interface_iterator; - - *usbInterfacep = IO_OBJECT_NULL; - - /* Setup the Interface Request */ - request.bInterfaceClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; - request.bAlternateSetting = kIOUSBFindInterfaceDontCare; - - kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator); - if (kresult) - return kresult; - - for ( current_interface = 0 ; current_interface <= ifc ; current_interface++ ) { - *usbInterfacep = IOIteratorNext(interface_iterator); - if (current_interface != ifc) - (void) IOObjectRelease (*usbInterfacep); - } - - /* done with the interface iterator */ - IOObjectRelease(interface_iterator); - - return 0; -} - -static int get_endpoints (struct libusb_device_handle *dev_handle, int iface) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - - /* current interface */ - struct __darwin_interface *cInterface = &priv->interfaces[iface]; - - kern_return_t kresult; - - u_int8_t numep, direction, number; - u_int8_t dont_care1, dont_care3; - u_int16_t dont_care2; - int i; - - usbi_info (HANDLE_CTX (dev_handle), "building table of endpoints."); - - /* retrieve the total number of endpoints on this interface */ - kresult = (*(cInterface->interface))->GetNumEndpoints(cInterface->interface, &numep); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "can't get number of endpoints for interface: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - - /* iterate through pipe references */ - for (i = 1 ; i <= numep ; i++) { - kresult = (*(cInterface->interface))->GetPipeProperties(cInterface->interface, i, &direction, &number, &dont_care1, - &dont_care2, &dont_care3); - - if (kresult != kIOReturnSuccess) { - usbi_err (HANDLE_CTX (dev_handle), "error getting pipe information for pipe %d: %s", i, darwin_error_str(kresult)); - - return darwin_to_libusb (kresult); - } - - usbi_info (HANDLE_CTX (dev_handle), "interface: %i pipe %i: dir: %i number: %i", iface, i, direction, number); - - cInterface->endpoint_addrs[i - 1] = ((direction << 7 & LIBUSB_ENDPOINT_DIR_MASK) | (number & LIBUSB_ENDPOINT_ADDRESS_MASK)); - } - - cInterface->num_endpoints = numep; - - return 0; -} - -static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface) { - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - io_service_t usbInterface = IO_OBJECT_NULL; - IOReturn kresult; - IOCFPlugInInterface **plugInInterface = NULL; - SInt32 score; - - /* current interface */ - struct __darwin_interface *cInterface = &priv->interfaces[iface]; - - kresult = darwin_get_interface (dpriv->device, iface, &usbInterface); - if (kresult != kIOReturnSuccess) - return darwin_to_libusb (kresult); - - /* make sure we have an interface */ - if (!usbInterface && dpriv->first_config != 0) { - usbi_info (HANDLE_CTX (dev_handle), "no interface found; setting configuration: %d", dpriv->first_config); - - /* set the configuration */ - kresult = darwin_set_configuration (dev_handle, dpriv->first_config); - if (kresult != LIBUSB_SUCCESS) { - usbi_err (HANDLE_CTX (dev_handle), "could not set configuration"); - return kresult; - } - - kresult = darwin_get_interface (dpriv->device, iface, &usbInterface); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - } - - if (!usbInterface) { - usbi_err (HANDLE_CTX (dev_handle), "interface not found"); - return LIBUSB_ERROR_NOT_FOUND; - } - - /* get an interface to the device's interface */ - kresult = IOCreatePlugInInterfaceForService (usbInterface, kIOUSBInterfaceUserClientTypeID, - kIOCFPlugInInterfaceID, &plugInInterface, &score); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "IOCreatePlugInInterfaceForService: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - - if (!plugInInterface) { - usbi_err (HANDLE_CTX (dev_handle), "plugin interface not found"); - return LIBUSB_ERROR_NOT_FOUND; - } - - /* ignore release error */ - (void)IOObjectRelease (usbInterface); - - /* Do the actual claim */ - kresult = (*plugInInterface)->QueryInterface(plugInInterface, - CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), - (LPVOID)&cInterface->interface); - if (kresult || !cInterface->interface) { - usbi_err (HANDLE_CTX (dev_handle), "QueryInterface: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - - /* We no longer need the intermediate plug-in */ - (*plugInInterface)->Release(plugInInterface); - - /* claim the interface */ - kresult = (*(cInterface->interface))->USBInterfaceOpen(cInterface->interface); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "USBInterfaceOpen: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - - /* update list of endpoints */ - kresult = get_endpoints (dev_handle, iface); - if (kresult) { - /* this should not happen */ - darwin_release_interface (dev_handle, iface); - usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table"); - return kresult; - } - - cInterface->cfSource = NULL; - - /* create async event source */ - kresult = (*(cInterface->interface))->CreateInterfaceAsyncEventSource (cInterface->interface, &cInterface->cfSource); - if (kresult != kIOReturnSuccess) { - usbi_err (HANDLE_CTX (dev_handle), "could not create async event source"); - - /* can't continue without an async event source */ - (void)darwin_release_interface (dev_handle, iface); - - return darwin_to_libusb (kresult); - } - - /* add the cfSource to the async thread's run loop */ - CFRunLoopAddSource(libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode); - - usbi_info (HANDLE_CTX (dev_handle), "interface opened"); - - return 0; -} - -static int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - IOReturn kresult; - - /* current interface */ - struct __darwin_interface *cInterface = &priv->interfaces[iface]; - - /* Check to see if an interface is open */ - if (!cInterface->interface) - return LIBUSB_SUCCESS; - - /* clean up endpoint data */ - cInterface->num_endpoints = 0; - - /* delete the interface's async event source */ - if (cInterface->cfSource) { - CFRunLoopRemoveSource (libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode); - CFRelease (cInterface->cfSource); - } - - kresult = (*(cInterface->interface))->USBInterfaceClose(cInterface->interface); - if (kresult) - usbi_err (HANDLE_CTX (dev_handle), "USBInterfaceClose: %s", darwin_error_str(kresult)); - - kresult = (*(cInterface->interface))->Release(cInterface->interface); - if (kresult != kIOReturnSuccess) - usbi_err (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult)); - - cInterface->interface = IO_OBJECT_NULL; - - return darwin_to_libusb (kresult); -} - -static int darwin_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - IOReturn kresult; - - /* current interface */ - struct __darwin_interface *cInterface = &priv->interfaces[iface]; - - if (!cInterface->interface) - return LIBUSB_ERROR_NO_DEVICE; - - kresult = (*(cInterface->interface))->SetAlternateInterface (cInterface->interface, altsetting); - if (kresult != kIOReturnSuccess) - darwin_reset_device (dev_handle); - - /* update list of endpoints */ - kresult = get_endpoints (dev_handle, iface); - if (kresult) { - /* this should not happen */ - darwin_release_interface (dev_handle, iface); - usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table"); - return kresult; - } - - return darwin_to_libusb (kresult); -} - -static int darwin_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - - /* current interface */ - struct __darwin_interface *cInterface; - uint8_t pipeRef, iface; - IOReturn kresult; - - /* determine the interface/endpoint to use */ - if (ep_to_pipeRef (dev_handle, endpoint, &pipeRef, &iface) != 0) { - usbi_err (HANDLE_CTX (dev_handle), "endpoint not found on any open interface"); - - return LIBUSB_ERROR_NOT_FOUND; - } - - cInterface = &priv->interfaces[iface]; - -#if (InterfaceVersion < 190) - kresult = (*(cInterface->interface))->ClearPipeStall(cInterface->interface, pipeRef); -#else - /* newer versions of darwin support clearing additional bits on the device's endpoint */ - kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef); -#endif - if (kresult) - usbi_err (HANDLE_CTX (dev_handle), "ClearPipeStall: %s", darwin_error_str (kresult)); - - return darwin_to_libusb (kresult); -} - -static int darwin_reset_device(struct libusb_device_handle *dev_handle) { - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; - IOReturn kresult; - - kresult = (*(dpriv->device))->ResetDevice (dpriv->device); - if (kresult) - usbi_err (HANDLE_CTX (dev_handle), "ResetDevice: %s", darwin_error_str (kresult)); - - return darwin_to_libusb (kresult); -} - -static int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle, int interface) { - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; - io_service_t usbInterface; - CFTypeRef driver; - IOReturn kresult; - - kresult = darwin_get_interface (dpriv->device, interface, &usbInterface); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult)); - - return darwin_to_libusb (kresult); - } - - driver = IORegistryEntryCreateCFProperty (usbInterface, kIOBundleIdentifierKey, kCFAllocatorDefault, 0); - IOObjectRelease (usbInterface); - - if (driver) { - CFRelease (driver); - - return 1; - } - - /* no driver */ - return 0; -} - -/* attaching/detaching kernel drivers is not currently supported (maybe in the future?) */ -static int darwin_attach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) { - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static int darwin_detach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) { - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static void darwin_destroy_device(struct libusb_device *dev) { -} - -static int submit_bulk_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; - - IOReturn ret; - uint8_t is_read; /* 0 = we're reading, 1 = we're writing */ - uint8_t transferType; - /* None of the values below are used in libusb for bulk transfers */ - uint8_t direction, number, interval, pipeRef, iface; - uint16_t maxPacketSize; - - struct __darwin_interface *cInterface; - - /* are we reading or writing? */ - is_read = transfer->endpoint & LIBUSB_ENDPOINT_IN; - - if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) { - usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); - - return LIBUSB_ERROR_NOT_FOUND; - } - - cInterface = &priv->interfaces[iface]; - - (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number, - &transferType, &maxPacketSize, &interval); - - /* submit the request */ - /* timeouts are unavailable on interrupt endpoints */ - if (transferType == kUSBInterrupt) { - if (is_read) - ret = (*(cInterface->interface))->ReadPipeAsync(cInterface->interface, pipeRef, transfer->buffer, - transfer->length, darwin_async_io_callback, itransfer); - else - ret = (*(cInterface->interface))->WritePipeAsync(cInterface->interface, pipeRef, transfer->buffer, - transfer->length, darwin_async_io_callback, itransfer); - } else { - if (is_read) - ret = (*(cInterface->interface))->ReadPipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer, - transfer->length, transfer->timeout, transfer->timeout, - darwin_async_io_callback, (void *)itransfer); - else - ret = (*(cInterface->interface))->WritePipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer, - transfer->length, transfer->timeout, transfer->timeout, - darwin_async_io_callback, (void *)itransfer); - } - - if (ret) - usbi_err (TRANSFER_CTX (transfer), "bulk transfer failed (dir = %s): %s (code = 0x%08x)", is_read ? "In" : "Out", - darwin_error_str(ret), ret); - - return darwin_to_libusb (ret); -} - -static int submit_iso_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; - - IOReturn kresult; - uint8_t is_read; /* 0 = we're writing, 1 = we're reading */ - uint8_t pipeRef, iface; - UInt64 frame; - AbsoluteTime atTime; - int i; - - struct __darwin_interface *cInterface; - - /* are we reading or writing? */ - is_read = transfer->endpoint & LIBUSB_ENDPOINT_IN; - - /* construct an array of IOUSBIsocFrames */ - tpriv->isoc_framelist = (IOUSBIsocFrame*) calloc (transfer->num_iso_packets, sizeof(IOUSBIsocFrame)); - if (!tpriv->isoc_framelist) - return LIBUSB_ERROR_NO_MEM; - - /* copy the frame list from the libusb descriptor (the structures differ only is member order) */ - for (i = 0 ; i < transfer->num_iso_packets ; i++) - tpriv->isoc_framelist[i].frReqCount = transfer->iso_packet_desc[i].length; - - /* determine the interface/endpoint to use */ - if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) { - usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); - - return LIBUSB_ERROR_NOT_FOUND; - } - - cInterface = &priv->interfaces[iface]; - - /* Last but not least we need the bus frame number */ - kresult = (*(cInterface->interface))->GetBusFrameNumber(cInterface->interface, &frame, &atTime); - if (kresult) { - usbi_err (TRANSFER_CTX (transfer), "failed to get bus frame number: %d", kresult); - free(tpriv->isoc_framelist); - tpriv->isoc_framelist = NULL; - - return darwin_to_libusb (kresult); - } - - /* schedule for a frame a little in the future */ - frame += 2; - - /* submit the request */ - if (is_read) - kresult = (*(cInterface->interface))->ReadIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame, - transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback, - itransfer); - else - kresult = (*(cInterface->interface))->WriteIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame, - transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback, - itransfer); - - if (kresult != kIOReturnSuccess) { - usbi_err (TRANSFER_CTX (transfer), "isochronous transfer failed (dir: %s): %s", is_read ? "In" : "Out", - darwin_error_str(kresult)); - free (tpriv->isoc_framelist); - tpriv->isoc_framelist = NULL; - } - - return darwin_to_libusb (kresult); -} - -static int submit_control_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_control_setup *setup = (struct libusb_control_setup *) transfer->buffer; - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)transfer->dev_handle->dev->os_priv; - struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - - IOReturn kresult; - - bzero(&tpriv->req, sizeof(tpriv->req)); - - /* IOUSBDeviceInterface expects the request in cpu endianess */ - tpriv->req.bmRequestType = setup->bmRequestType; - tpriv->req.bRequest = setup->bRequest; - /* these values should be in bus order from libusb_fill_control_setup */ - tpriv->req.wValue = OSSwapLittleToHostInt16 (setup->wValue); - tpriv->req.wIndex = OSSwapLittleToHostInt16 (setup->wIndex); - tpriv->req.wLength = OSSwapLittleToHostInt16 (setup->wLength); - /* data is stored after the libusb control block */ - tpriv->req.pData = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; - tpriv->req.completionTimeout = transfer->timeout; - tpriv->req.noDataTimeout = transfer->timeout; - - /* all transfers in libusb-1.0 are async */ - kresult = (*(dpriv->device))->DeviceRequestAsyncTO(dpriv->device, &(tpriv->req), darwin_async_io_callback, itransfer); - - if (kresult != kIOReturnSuccess) - usbi_err (TRANSFER_CTX (transfer), "control request failed: %s", darwin_error_str(kresult)); - - return darwin_to_libusb (kresult); -} - -static int darwin_submit_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return submit_control_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - return submit_bulk_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return submit_iso_transfer(itransfer); - default: - usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static int cancel_control_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)transfer->dev_handle->dev->os_priv; - IOReturn kresult; - - usbi_info (ITRANSFER_CTX (itransfer), "WARNING: aborting all transactions control pipe"); - - kresult = (*(dpriv->device))->USBDeviceAbortPipeZero (dpriv->device); - - return darwin_to_libusb (kresult); -} - -static int darwin_abort_transfers (struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; - struct __darwin_interface *cInterface; - uint8_t pipeRef, iface; - IOReturn kresult; - - if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) { - usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); - - return LIBUSB_ERROR_NOT_FOUND; - } - - cInterface = &priv->interfaces[iface]; - - usbi_info (ITRANSFER_CTX (itransfer), "WARNING: aborting all transactions on interface %d pipe %d", iface, pipeRef); - - /* abort transactions */ - (*(cInterface->interface))->AbortPipe (cInterface->interface, pipeRef); - - usbi_info (ITRANSFER_CTX (itransfer), "calling clear pipe stall to clear the data toggle bit"); - - /* clear the data toggle bit */ -#if (InterfaceVersion < 190) - kresult = (*(cInterface->interface))->ClearPipeStall(cInterface->interface, pipeRef); -#else - /* newer versions of darwin support clearing additional bits on the device's endpoint */ - kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef); -#endif - - return darwin_to_libusb (kresult); -} - -static int darwin_cancel_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return cancel_control_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return darwin_abort_transfers (itransfer); - default: - usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static void darwin_clear_transfer_priv (struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - - if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS && tpriv->isoc_framelist) { - free (tpriv->isoc_framelist); - tpriv->isoc_framelist = NULL; - } -} - -static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0) { - struct usbi_transfer *itransfer = (struct usbi_transfer *)refcon; - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; - UInt32 message; - - usbi_info (ITRANSFER_CTX (itransfer), "an async io operation has completed"); - - /* send a completion message to the device's file descriptor */ - message = MESSAGE_ASYNC_IO_COMPLETE; - write (priv->fds[1], &message, sizeof (message)); - write (priv->fds[1], &itransfer, sizeof (itransfer)); - write (priv->fds[1], &result, sizeof (IOReturn)); - write (priv->fds[1], &arg0, sizeof (UInt32)); -} - -static int darwin_transfer_status (struct usbi_transfer *itransfer, kern_return_t result) { - switch (result) { - case kIOReturnUnderrun: - case kIOReturnSuccess: - return LIBUSB_TRANSFER_COMPLETED; - case kIOReturnAborted: - return LIBUSB_TRANSFER_CANCELLED; - case kIOUSBPipeStalled: - usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: pipe is stalled"); - return LIBUSB_TRANSFER_STALL; - case kIOReturnOverrun: - usbi_err (ITRANSFER_CTX (itransfer), "transfer error: data overrun"); - return LIBUSB_TRANSFER_OVERFLOW; - case kIOUSBTransactionTimeout: - usbi_err (ITRANSFER_CTX (itransfer), "transfer error: timed out"); - return LIBUSB_TRANSFER_TIMED_OUT; - default: - usbi_err (ITRANSFER_CTX (itransfer), "transfer error: %s (value = 0x%08x)", darwin_error_str (result), result); - return LIBUSB_TRANSFER_ERROR; - } -} - -static void darwin_handle_callback (struct usbi_transfer *itransfer, kern_return_t result, UInt32 io_size) { - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - int isIsoc = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type; - int isBulk = LIBUSB_TRANSFER_TYPE_BULK == transfer->type; - int isControl = LIBUSB_TRANSFER_TYPE_CONTROL == transfer->type; - int isInterrupt = LIBUSB_TRANSFER_TYPE_INTERRUPT == transfer->type; - int i; - - if (!isIsoc && !isBulk && !isControl && !isInterrupt) { - usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); - return; - } - - usbi_info (ITRANSFER_CTX (itransfer), "handling %s completion with kernel status %d", - isControl ? "control" : isBulk ? "bulk" : isIsoc ? "isoc" : "interrupt", result); - - if (kIOReturnSuccess == result || kIOReturnUnderrun == result) { - if (isIsoc && tpriv->isoc_framelist) { - /* copy isochronous results back */ - - for (i = 0; i < transfer->num_iso_packets ; i++) { - struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i]; - lib_desc->status = darwin_to_libusb (tpriv->isoc_framelist[i].frStatus); - lib_desc->actual_length = tpriv->isoc_framelist[i].frActCount; - } - } else if (!isIsoc) - itransfer->transferred += io_size; - } - - /* it is ok to handle cancelled transfers without calling usbi_handle_transfer_cancellation (we catch timeout transfers) */ - usbi_handle_transfer_completion (itransfer, darwin_transfer_status (itransfer, result)); -} - -static int op_handle_events(struct libusb_context *ctx, struct pollfd *fds, nfds_t nfds, int num_ready) { - struct usbi_transfer *itransfer; - UInt32 io_size; - IOReturn kresult; - int i = 0, ret; - UInt32 message; - - usbi_mutex_lock(&ctx->open_devs_lock); - for (i = 0; i < nfds && num_ready > 0; i++) { - struct pollfd *pollfd = &fds[i]; - struct libusb_device_handle *handle; - struct darwin_device_handle_priv *hpriv = NULL; - - usbi_info (ctx, "checking fd %i with revents = %x", fds[i], pollfd->revents); - - if (!pollfd->revents) - continue; - - num_ready--; - list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) { - hpriv = (struct darwin_device_handle_priv *)handle->os_priv; - if (hpriv->fds[0] == pollfd->fd) - break; - } - - if (!(pollfd->revents & POLLERR)) { - ret = read (hpriv->fds[0], &message, sizeof (message)); - if (ret < sizeof (message)) - continue; - } else - /* could not poll the device-- response is to delete the device (this seems a little heavy-handed) */ - message = MESSAGE_DEVICE_GONE; - - switch (message) { - case MESSAGE_DEVICE_GONE: - /* remove the device's async port from the runloop */ - if (hpriv->cfSource) { - if (libusb_darwin_acfl) - CFRunLoopRemoveSource (libusb_darwin_acfl, hpriv->cfSource, kCFRunLoopDefaultMode); - CFRelease (hpriv->cfSource); - hpriv->cfSource = NULL; - } - - usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fds[0]); - usbi_handle_disconnect(handle); - - /* done with this device */ - continue; - case MESSAGE_ASYNC_IO_COMPLETE: - read (hpriv->fds[0], &itransfer, sizeof (itransfer)); - read (hpriv->fds[0], &kresult, sizeof (IOReturn)); - read (hpriv->fds[0], &io_size, sizeof (UInt32)); - - darwin_handle_callback (itransfer, kresult, io_size); - break; - default: - usbi_err (ctx, "unknown message received from device pipe"); - } - } - - usbi_mutex_unlock(&ctx->open_devs_lock); - - return 0; -} - -static int darwin_clock_gettime(int clk_id, struct timespec *tp) { - mach_timespec_t sys_time; - clock_serv_t clock_ref; - - switch (clk_id) { - case USBI_CLOCK_REALTIME: - /* CLOCK_REALTIME represents time since the epoch */ - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clock_ref); - break; - case USBI_CLOCK_MONOTONIC: - /* use system boot time as reference for the monotonic clock */ - host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &clock_ref); - break; - default: - return LIBUSB_ERROR_INVALID_PARAM; - } - - clock_get_time (clock_ref, &sys_time); - - tp->tv_sec = sys_time.tv_sec; - tp->tv_nsec = sys_time.tv_nsec; - - return 0; -} - -const struct usbi_os_backend darwin_backend = { - .name = "Darwin", - .init = darwin_init, - .exit = darwin_exit, - .get_device_list = darwin_get_device_list, - .get_device_descriptor = darwin_get_device_descriptor, - .get_active_config_descriptor = darwin_get_active_config_descriptor, - .get_config_descriptor = darwin_get_config_descriptor, - - .open = darwin_open, - .close = darwin_close, - .get_configuration = darwin_get_configuration, - .set_configuration = darwin_set_configuration, - .claim_interface = darwin_claim_interface, - .release_interface = darwin_release_interface, - - .set_interface_altsetting = darwin_set_interface_altsetting, - .clear_halt = darwin_clear_halt, - .reset_device = darwin_reset_device, - - .kernel_driver_active = darwin_kernel_driver_active, - .detach_kernel_driver = darwin_detach_kernel_driver, - .attach_kernel_driver = darwin_attach_kernel_driver, - - .destroy_device = darwin_destroy_device, - - .submit_transfer = darwin_submit_transfer, - .cancel_transfer = darwin_cancel_transfer, - .clear_transfer_priv = darwin_clear_transfer_priv, - - .handle_events = op_handle_events, - - .clock_gettime = darwin_clock_gettime, - - .device_priv_size = sizeof(struct darwin_device_priv), - .device_handle_priv_size = sizeof(struct darwin_device_handle_priv), - .transfer_priv_size = sizeof(struct darwin_transfer_priv), - .add_iso_packet_size = 0, -}; - diff --git a/include/libusb-1.0/os/darwin_usb.h b/include/libusb-1.0/os/darwin_usb.h deleted file mode 100644 index a71d464..0000000 --- a/include/libusb-1.0/os/darwin_usb.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * darwin backend for libusb 1.0 - * Copyright (C) 2008-2009 Nathan Hjelm <hjelmn@users.sourceforge.net> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#if !defined(LIBUSB_DARWIN_H) -#define LIBUSB_DARWIN_H - -#include "libusbi.h" - -#include <IOKit/IOTypes.h> -#include <IOKit/IOCFBundle.h> -#include <IOKit/usb/IOUSBLib.h> -#include <IOKit/IOCFPlugIn.h> - -/* IOUSBInterfaceInferface */ -#if defined (kIOUSBInterfaceInterfaceID300) - -#define usb_interface_t IOUSBInterfaceInterface300 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300 -#define InterfaceVersion 300 - -#elif defined (kIOUSBInterfaceInterfaceID245) - -#define usb_interface_t IOUSBInterfaceInterface245 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID245 -#define InterfaceVersion 245 - -#elif defined (kIOUSBInterfaceInterfaceID220) - -#define usb_interface_t IOUSBInterfaceInterface220 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220 -#define InterfaceVersion 220 - -#elif defined (kIOUSBInterfaceInterfaceID197) - -#define usb_interface_t IOUSBInterfaceInterface197 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197 -#define InterfaceVersion 197 - -#elif defined (kIOUSBInterfaceInterfaceID190) - -#define usb_interface_t IOUSBInterfaceInterface190 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190 -#define InterfaceVersion 190 - -#elif defined (kIOUSBInterfaceInterfaceID182) - -#define usb_interface_t IOUSBInterfaceInterface182 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182 -#define InterfaceVersion 182 - -#else - -#error "IOUSBFamily is too old. Please upgrade your OS" - -#endif - -/* IOUSBDeviceInterface */ -#if defined (kIOUSBDeviceInterfaceID320) - -#define usb_device_t IOUSBDeviceInterface320 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID320 -#define DeviceVersion 320 - -#elif defined (kIOUSBDeviceInterfaceID300) - -#define usb_device_t IOUSBDeviceInterface300 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID300 -#define DeviceVersion 300 - -#elif defined (kIOUSBDeviceInterfaceID245) - -#define usb_device_t IOUSBDeviceInterface245 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID245 -#define DeviceVersion 245 - -#elif defined (kIOUSBDeviceInterfaceID197) - -#define usb_device_t IOUSBDeviceInterface197 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID197 -#define DeviceVersion 197 - -#elif defined (kIOUSBDeviceInterfaceID187) - -#define usb_device_t IOUSBDeviceInterface187 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID187 -#define DeviceVersion 187 - -#elif defined (kIOUSBDeviceInterfaceID182) - -#define usb_device_t IOUSBDeviceInterface182 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID182 -#define DeviceVersion 182 - -#else - -#error "IOUSBFamily is too old. Please upgrade your OS" - -#endif - -#if !defined(IO_OBJECT_NULL) -#define IO_OBJECT_NULL ((io_object_t) 0) -#endif - -typedef IOCFPlugInInterface *io_cf_plugin_ref_t; -typedef IONotificationPortRef io_notification_port_t; - -/* private structures */ -struct darwin_device_priv { - IOUSBDeviceDescriptor dev_descriptor; - UInt32 location; - char sys_path[21]; - usb_device_t **device; - int open_count; - UInt8 first_config, active_config; -}; - -struct darwin_device_handle_priv { - int is_open; - CFRunLoopSourceRef cfSource; - int fds[2]; - - struct __darwin_interface { - usb_interface_t **interface; - uint8_t num_endpoints; - CFRunLoopSourceRef cfSource; - uint8_t endpoint_addrs[USB_MAXENDPOINTS]; - } interfaces[USB_MAXINTERFACES]; -}; - -struct darwin_transfer_priv { - /* Isoc */ - IOUSBIsocFrame *isoc_framelist; - - /* Control */ -#if !defined (LIBUSB_NO_TIMEOUT_DEVICE) - IOUSBDevRequestTO req; -#else - IOUSBDevRequest req; -#endif - - /* Bulk */ -}; - -enum { - MESSAGE_DEVICE_GONE, - MESSAGE_ASYNC_IO_COMPLETE -}; - - - -#endif diff --git a/include/libusb-1.0/os/libusb.h b/include/libusb-1.0/os/libusb.h deleted file mode 100644 index 8dc3362..0000000 --- a/include/libusb-1.0/os/libusb.h +++ /dev/null @@ -1,1322 +0,0 @@ -/* - * Public libusb header file - * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org> - * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LIBUSB_H__ -#define __LIBUSB_H__ - -/* MSVC doesn't like inline, but does accept __inline ?? */ -#ifdef _MSC_VER -#define inline __inline -#endif - -#include <stdint.h> -#include <sys/types.h> -#include <time.h> -#include <limits.h> - -#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) -#include <sys/time.h> -#endif - -/* 'interface' might be defined as a macro on Windows, so we need to - * undefine it so as not to break the current libusb API, because - * libusb_config_descriptor has an 'interface' member - * As this can be problematic if you include windows.h after libusb.h - * in your sources, we force windows.h to be included first. */ -#if defined(_WIN32) || defined(__CYGWIN__) -#include <windows.h> -#if defined(interface) -#undef interface -#endif -#endif - -/** \def LIBUSB_CALL - * \ingroup misc - * libusb's Windows calling convention. - * - * Under Windows, the selection of available compilers and configurations - * means that, unlike other platforms, there is not <em>one true calling - * convention</em> (calling convention: the manner in which parameters are - * passed to funcions in the generated assembly code). - * - * Matching the Windows API itself, libusb uses the WINAPI convention (which - * translates to the <tt>stdcall</tt> convention) and guarantees that the - * library is compiled in this way. The public header file also includes - * appropriate annotations so that your own software will use the right - * convention, even if another convention is being used by default within - * your codebase. - * - * The one consideration that you must apply in your software is to mark - * all functions which you use as libusb callbacks with this LIBUSB_CALL - * annotation, so that they too get compiled for the correct calling - * convention. - * - * On non-Windows operating systems, this macro is defined as nothing. This - * means that you can apply it to your code without worrying about - * cross-platform compatibility. - */ -/* LIBUSB_CALL must be defined on both definition and declaration of libusb - * functions. You'd think that declaration would be enough, but cygwin will - * complain about conflicting types unless both are marked this way. - * The placement of this macro is important too; it must appear after the - * return type, before the function name. See internal documentation for - * API_EXPORTED. - */ -#if defined(_WIN32) || defined(__CYGWIN__) -#define LIBUSB_CALL WINAPI -#else -#define LIBUSB_CALL -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** \def libusb_cpu_to_le16 - * \ingroup misc - * Convert a 16-bit value from host-endian to little-endian format. On - * little endian systems, this function does nothing. On big endian systems, - * the bytes are swapped. - * \param x the host-endian value to convert - * \returns the value in little-endian byte order - */ -static inline uint16_t libusb_cpu_to_le16(const uint16_t x) -{ - union { - uint8_t b8[2]; - uint16_t b16; - } _tmp; - _tmp.b8[1] = x >> 8; - _tmp.b8[0] = x & 0xff; - return _tmp.b16; -} - -/** \def libusb_le16_to_cpu - * \ingroup misc - * Convert a 16-bit value from little-endian to host-endian format. On - * little endian systems, this function does nothing. On big endian systems, - * the bytes are swapped. - * \param x the little-endian value to convert - * \returns the value in host-endian byte order - */ -#define libusb_le16_to_cpu libusb_cpu_to_le16 - -/* standard USB stuff */ - -/** \ingroup desc - * Device and/or Interface Class codes */ -enum libusb_class_code { - /** In the context of a \ref libusb_device_descriptor "device descriptor", - * this bDeviceClass value indicates that each interface specifies its - * own class information and all interfaces operate independently. - */ - LIBUSB_CLASS_PER_INTERFACE = 0, - - /** Audio class */ - LIBUSB_CLASS_AUDIO = 1, - - /** Communications class */ - LIBUSB_CLASS_COMM = 2, - - /** Human Interface Device class */ - LIBUSB_CLASS_HID = 3, - - /** Printer dclass */ - LIBUSB_CLASS_PRINTER = 7, - - /** Picture transfer protocol class */ - LIBUSB_CLASS_PTP = 6, - - /** Mass storage class */ - LIBUSB_CLASS_MASS_STORAGE = 8, - - /** Hub class */ - LIBUSB_CLASS_HUB = 9, - - /** Data class */ - LIBUSB_CLASS_DATA = 10, - - /** Wireless class */ - LIBUSB_CLASS_WIRELESS = 0xe0, - - /** Application class */ - LIBUSB_CLASS_APPLICATION = 0xfe, - - /** Class is vendor-specific */ - LIBUSB_CLASS_VENDOR_SPEC = 0xff -}; - -/** \ingroup desc - * Descriptor types as defined by the USB specification. */ -enum libusb_descriptor_type { - /** Device descriptor. See libusb_device_descriptor. */ - LIBUSB_DT_DEVICE = 0x01, - - /** Configuration descriptor. See libusb_config_descriptor. */ - LIBUSB_DT_CONFIG = 0x02, - - /** String descriptor */ - LIBUSB_DT_STRING = 0x03, - - /** Interface descriptor. See libusb_interface_descriptor. */ - LIBUSB_DT_INTERFACE = 0x04, - - /** Endpoint descriptor. See libusb_endpoint_descriptor. */ - LIBUSB_DT_ENDPOINT = 0x05, - - /** HID descriptor */ - LIBUSB_DT_HID = 0x21, - - /** HID report descriptor */ - LIBUSB_DT_REPORT = 0x22, - - /** Physical descriptor */ - LIBUSB_DT_PHYSICAL = 0x23, - - /** Hub descriptor */ - LIBUSB_DT_HUB = 0x29 -}; - -/* Descriptor sizes per descriptor type */ -#define LIBUSB_DT_DEVICE_SIZE 18 -#define LIBUSB_DT_CONFIG_SIZE 9 -#define LIBUSB_DT_INTERFACE_SIZE 9 -#define LIBUSB_DT_ENDPOINT_SIZE 7 -#define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ -#define LIBUSB_DT_HUB_NONVAR_SIZE 7 - -#define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */ -#define LIBUSB_ENDPOINT_DIR_MASK 0x80 - -/** \ingroup desc - * Endpoint direction. Values for bit 7 of the - * \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme. - */ -enum libusb_endpoint_direction { - /** In: device-to-host */ - LIBUSB_ENDPOINT_IN = 0x80, - - /** Out: host-to-device */ - LIBUSB_ENDPOINT_OUT = 0x00 -}; - -#define LIBUSB_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */ - -/** \ingroup desc - * Endpoint transfer type. Values for bits 0:1 of the - * \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field. - */ -enum libusb_transfer_type { - /** Control endpoint */ - LIBUSB_TRANSFER_TYPE_CONTROL = 0, - - /** Isochronous endpoint */ - LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1, - - /** Bulk endpoint */ - LIBUSB_TRANSFER_TYPE_BULK = 2, - - /** Interrupt endpoint */ - LIBUSB_TRANSFER_TYPE_INTERRUPT = 3 -}; - -/** \ingroup misc - * Standard requests, as defined in table 9-3 of the USB2 specifications */ -enum libusb_standard_request { - /** Request status of the specific recipient */ - LIBUSB_REQUEST_GET_STATUS = 0x00, - - /** Clear or disable a specific feature */ - LIBUSB_REQUEST_CLEAR_FEATURE = 0x01, - - /* 0x02 is reserved */ - - /** Set or enable a specific feature */ - LIBUSB_REQUEST_SET_FEATURE = 0x03, - - /* 0x04 is reserved */ - - /** Set device address for all future accesses */ - LIBUSB_REQUEST_SET_ADDRESS = 0x05, - - /** Get the specified descriptor */ - LIBUSB_REQUEST_GET_DESCRIPTOR = 0x06, - - /** Used to update existing descriptors or add new descriptors */ - LIBUSB_REQUEST_SET_DESCRIPTOR = 0x07, - - /** Get the current device configuration value */ - LIBUSB_REQUEST_GET_CONFIGURATION = 0x08, - - /** Set device configuration */ - LIBUSB_REQUEST_SET_CONFIGURATION = 0x09, - - /** Return the selected alternate setting for the specified interface */ - LIBUSB_REQUEST_GET_INTERFACE = 0x0A, - - /** Select an alternate interface for the specified interface */ - LIBUSB_REQUEST_SET_INTERFACE = 0x0B, - - /** Set then report an endpoint's synchronization frame */ - LIBUSB_REQUEST_SYNCH_FRAME = 0x0C -}; - -/** \ingroup misc - * Request type bits of the - * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control - * transfers. */ -enum libusb_request_type { - /** Standard */ - LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5), - - /** Class */ - LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5), - - /** Vendor */ - LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5), - - /** Reserved */ - LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5) -}; - -/** \ingroup misc - * Recipient bits of the - * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control - * transfers. Values 4 through 31 are reserved. */ -enum libusb_request_recipient { - /** Device */ - LIBUSB_RECIPIENT_DEVICE = 0x00, - - /** Interface */ - LIBUSB_RECIPIENT_INTERFACE = 0x01, - - /** Endpoint */ - LIBUSB_RECIPIENT_ENDPOINT = 0x02, - - /** Other */ - LIBUSB_RECIPIENT_OTHER = 0x03 -}; - -#define LIBUSB_ISO_SYNC_TYPE_MASK 0x0C - -/** \ingroup desc - * Synchronization type for isochronous endpoints. Values for bits 2:3 of the - * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in - * libusb_endpoint_descriptor. - */ -enum libusb_iso_sync_type { - /** No synchronization */ - LIBUSB_ISO_SYNC_TYPE_NONE = 0, - - /** Asynchronous */ - LIBUSB_ISO_SYNC_TYPE_ASYNC = 1, - - /** Adaptive */ - LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 2, - - /** Synchronous */ - LIBUSB_ISO_SYNC_TYPE_SYNC = 3 -}; - -#define LIBUSB_ISO_USAGE_TYPE_MASK 0x30 - -/** \ingroup desc - * Usage type for isochronous endpoints. Values for bits 4:5 of the - * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in - * libusb_endpoint_descriptor. - */ -enum libusb_iso_usage_type { - /** Data endpoint */ - LIBUSB_ISO_USAGE_TYPE_DATA = 0, - - /** Feedback endpoint */ - LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 1, - - /** Implicit feedback Data endpoint */ - LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2 -}; - -/** \ingroup desc - * A structure representing the standard USB device descriptor. This - * descriptor is documented in section 9.6.1 of the USB 2.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_device_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this - * context. */ - uint8_t bDescriptorType; - - /** USB specification release number in binary-coded decimal. A value of - * 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */ - uint16_t bcdUSB; - - /** USB-IF class code for the device. See \ref libusb_class_code. */ - uint8_t bDeviceClass; - - /** USB-IF subclass code for the device, qualified by the bDeviceClass - * value */ - uint8_t bDeviceSubClass; - - /** USB-IF protocol code for the device, qualified by the bDeviceClass and - * bDeviceSubClass values */ - uint8_t bDeviceProtocol; - - /** Maximum packet size for endpoint 0 */ - uint8_t bMaxPacketSize0; - - /** USB-IF vendor ID */ - uint16_t idVendor; - - /** USB-IF product ID */ - uint16_t idProduct; - - /** Device release number in binary-coded decimal */ - uint16_t bcdDevice; - - /** Index of string descriptor describing manufacturer */ - uint8_t iManufacturer; - - /** Index of string descriptor describing product */ - uint8_t iProduct; - - /** Index of string descriptor containing device serial number */ - uint8_t iSerialNumber; - - /** Number of possible configurations */ - uint8_t bNumConfigurations; -}; - -/** \ingroup desc - * A structure representing the standard USB endpoint descriptor. This - * descriptor is documented in section 9.6.3 of the USB 2.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_endpoint_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT LIBUSB_DT_ENDPOINT in - * this context. */ - uint8_t bDescriptorType; - - /** The address of the endpoint described by this descriptor. Bits 0:3 are - * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction, - * see \ref libusb_endpoint_direction. - */ - uint8_t bEndpointAddress; - - /** Attributes which apply to the endpoint when it is configured using - * the bConfigurationValue. Bits 0:1 determine the transfer type and - * correspond to \ref libusb_transfer_type. Bits 2:3 are only used for - * isochronous endpoints and correspond to \ref libusb_iso_sync_type. - * Bits 4:5 are also only used for isochronous endpoints and correspond to - * \ref libusb_iso_usage_type. Bits 6:7 are reserved. - */ - uint8_t bmAttributes; - - /** Maximum packet size this endpoint is capable of sending/receiving. */ - uint16_t wMaxPacketSize; - - /** Interval for polling endpoint for data transfers. */ - uint8_t bInterval; - - /** For audio devices only: the rate at which synchronization feedback - * is provided. */ - uint8_t bRefresh; - - /** For audio devices only: the address if the synch endpoint */ - uint8_t bSynchAddress; - - /** Extra descriptors. If libusb encounters unknown endpoint descriptors, - * it will store them here, should you wish to parse them. */ - const unsigned char *extra; - - /** Length of the extra descriptors, in bytes. */ - int extra_length; -}; - -/** \ingroup desc - * A structure representing the standard USB interface descriptor. This - * descriptor is documented in section 9.6.5 of the USB 2.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_interface_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE LIBUSB_DT_INTERFACE - * in this context. */ - uint8_t bDescriptorType; - - /** Number of this interface */ - uint8_t bInterfaceNumber; - - /** Value used to select this alternate setting for this interface */ - uint8_t bAlternateSetting; - - /** Number of endpoints used by this interface (excluding the control - * endpoint). */ - uint8_t bNumEndpoints; - - /** USB-IF class code for this interface. See \ref libusb_class_code. */ - uint8_t bInterfaceClass; - - /** USB-IF subclass code for this interface, qualified by the - * bInterfaceClass value */ - uint8_t bInterfaceSubClass; - - /** USB-IF protocol code for this interface, qualified by the - * bInterfaceClass and bInterfaceSubClass values */ - uint8_t bInterfaceProtocol; - - /** Index of string descriptor describing this interface */ - uint8_t iInterface; - - /** Array of endpoint descriptors. This length of this array is determined - * by the bNumEndpoints field. */ - const struct libusb_endpoint_descriptor *endpoint; - - /** Extra descriptors. If libusb encounters unknown interface descriptors, - * it will store them here, should you wish to parse them. */ - const unsigned char *extra; - - /** Length of the extra descriptors, in bytes. */ - int extra_length; -}; - -/** \ingroup desc - * A collection of alternate settings for a particular USB interface. - */ -struct libusb_interface { - /** Array of interface descriptors. The length of this array is determined - * by the num_altsetting field. */ - const struct libusb_interface_descriptor *altsetting; - - /** The number of alternate settings that belong to this interface */ - int num_altsetting; -}; - -/** \ingroup desc - * A structure representing the standard USB configuration descriptor. This - * descriptor is documented in section 9.6.3 of the USB 2.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_config_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG - * in this context. */ - uint8_t bDescriptorType; - - /** Total length of data returned for this configuration */ - uint16_t wTotalLength; - - /** Number of interfaces supported by this configuration */ - uint8_t bNumInterfaces; - - /** Identifier value for this configuration */ - uint8_t bConfigurationValue; - - /** Index of string descriptor describing this configuration */ - uint8_t iConfiguration; - - /** Configuration characteristics */ - uint8_t bmAttributes; - - /** Maximum power consumption of the USB device from this bus in this - * configuration when the device is fully opreation. Expressed in units - * of 2 mA. */ - uint8_t MaxPower; - - /** Array of interfaces supported by this configuration. The length of - * this array is determined by the bNumInterfaces field. */ - const struct libusb_interface *interface; - - /** Extra descriptors. If libusb encounters unknown configuration - * descriptors, it will store them here, should you wish to parse them. */ - const unsigned char *extra; - - /** Length of the extra descriptors, in bytes. */ - int extra_length; -}; - -/** \ingroup asyncio - * Setup packet for control transfers. */ -struct libusb_control_setup { - /** Request type. Bits 0:4 determine recipient, see - * \ref libusb_request_recipient. Bits 5:6 determine type, see - * \ref libusb_request_type. Bit 7 determines data transfer direction, see - * \ref libusb_endpoint_direction. - */ - uint8_t bmRequestType; - - /** Request. If the type bits of bmRequestType are equal to - * \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD - * "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to - * \ref libusb_standard_request. For other cases, use of this field is - * application-specific. */ - uint8_t bRequest; - - /** Value. Varies according to request */ - uint16_t wValue; - - /** Index. Varies according to request, typically used to pass an index - * or offset */ - uint16_t wIndex; - - /** Number of bytes to transfer */ - uint16_t wLength; -}; - -#define LIBUSB_CONTROL_SETUP_SIZE (sizeof(struct libusb_control_setup)) - -/* libusb */ - -struct libusb_context; -struct libusb_device; -struct libusb_device_handle; - -/** \ingroup lib - * Structure representing a libusb session. The concept of individual libusb - * sessions allows for your program to use two libraries (or dynamically - * load two modules) which both independently use libusb. This will prevent - * interference between the individual libusb users - for example - * libusb_set_debug() will not affect the other user of the library, and - * libusb_exit() will not destroy resources that the other user is still - * using. - * - * Sessions are created by libusb_init() and destroyed through libusb_exit(). - * If your application is guaranteed to only ever include a single libusb - * user (i.e. you), you do not have to worry about contexts: pass NULL in - * every function call where a context is required. The default context - * will be used. - * - * For more information, see \ref contexts. - */ -typedef struct libusb_context libusb_context; - -/** \ingroup dev - * Structure representing a USB device detected on the system. This is an - * opaque type for which you are only ever provided with a pointer, usually - * originating from libusb_get_device_list(). - * - * Certain operations can be performed on a device, but in order to do any - * I/O you will have to first obtain a device handle using libusb_open(). - * - * Devices are reference counted with libusb_device_ref() and - * libusb_device_unref(), and are freed when the reference count reaches 0. - * New devices presented by libusb_get_device_list() have a reference count of - * 1, and libusb_free_device_list() can optionally decrease the reference count - * on all devices in the list. libusb_open() adds another reference which is - * later destroyed by libusb_close(). - */ -typedef struct libusb_device libusb_device; - - -/** \ingroup dev - * Structure representing a handle on a USB device. This is an opaque type for - * which you are only ever provided with a pointer, usually originating from - * libusb_open(). - * - * A device handle is used to perform I/O and other operations. When finished - * with a device handle, you should call libusb_close(). - */ -typedef struct libusb_device_handle libusb_device_handle; - -/** \ingroup misc - * Error codes. Most libusb functions return 0 on success or one of these - * codes on failure. - * You can use libusb_strerror() to retrieve a short string description of - * a libusb_error enumeration value. - */ -enum libusb_error { - /** Success (no error) */ - LIBUSB_SUCCESS = 0, - - /** Input/output error */ - LIBUSB_ERROR_IO = -1, - - /** Invalid parameter */ - LIBUSB_ERROR_INVALID_PARAM = -2, - - /** Access denied (insufficient permissions) */ - LIBUSB_ERROR_ACCESS = -3, - - /** No such device (it may have been disconnected) */ - LIBUSB_ERROR_NO_DEVICE = -4, - - /** Entity not found */ - LIBUSB_ERROR_NOT_FOUND = -5, - - /** Resource busy */ - LIBUSB_ERROR_BUSY = -6, - - /** Operation timed out */ - LIBUSB_ERROR_TIMEOUT = -7, - - /** Overflow */ - LIBUSB_ERROR_OVERFLOW = -8, - - /** Pipe error */ - LIBUSB_ERROR_PIPE = -9, - - /** System call interrupted (perhaps due to signal) */ - LIBUSB_ERROR_INTERRUPTED = -10, - - /** Insufficient memory */ - LIBUSB_ERROR_NO_MEM = -11, - - /** Operation not supported or unimplemented on this platform */ - LIBUSB_ERROR_NOT_SUPPORTED = -12, - - /** Other error */ - LIBUSB_ERROR_OTHER = -99 - - /* IMPORTANT: when adding new values to this enum, remember to - update the libusb_strerror() function implementation! */ -}; - -/** \ingroup asyncio - * Transfer status codes */ -enum libusb_transfer_status { - /** Transfer completed without error. Note that this does not indicate - * that the entire amount of requested data was transferred. */ - LIBUSB_TRANSFER_COMPLETED, - - /** Transfer failed */ - LIBUSB_TRANSFER_ERROR, - - /** Transfer timed out */ - LIBUSB_TRANSFER_TIMED_OUT, - - /** Transfer was cancelled */ - LIBUSB_TRANSFER_CANCELLED, - - /** For bulk/interrupt endpoints: halt condition detected (endpoint - * stalled). For control endpoints: control request not supported. */ - LIBUSB_TRANSFER_STALL, - - /** Device was disconnected */ - LIBUSB_TRANSFER_NO_DEVICE, - - /** Device sent more data than requested */ - LIBUSB_TRANSFER_OVERFLOW -}; - -/** \ingroup asyncio - * libusb_transfer.flags values */ -enum libusb_transfer_flags { - /** Report short frames as errors */ - LIBUSB_TRANSFER_SHORT_NOT_OK = 1<<0, - - /** Automatically free() transfer buffer during libusb_free_transfer() */ - LIBUSB_TRANSFER_FREE_BUFFER = 1<<1, - - /** Automatically call libusb_free_transfer() after callback returns. - * If this flag is set, it is illegal to call libusb_free_transfer() - * from your transfer callback, as this will result in a double-free - * when this flag is acted upon. */ - LIBUSB_TRANSFER_FREE_TRANSFER = 1<<2 -}; - -/** \ingroup asyncio - * Isochronous packet descriptor. */ -struct libusb_iso_packet_descriptor { - /** Length of data to request in this packet */ - unsigned int length; - - /** Amount of data that was actually transferred */ - unsigned int actual_length; - - /** Status code for this packet */ - enum libusb_transfer_status status; -}; - -struct libusb_transfer; - -/** \ingroup asyncio - * Asynchronous transfer callback function type. When submitting asynchronous - * transfers, you pass a pointer to a callback function of this type via the - * \ref libusb_transfer::callback "callback" member of the libusb_transfer - * structure. libusb will call this function later, when the transfer has - * completed or failed. See \ref asyncio for more information. - * \param transfer The libusb_transfer struct the callback function is being - * notified about. - */ -typedef void (LIBUSB_CALL *libusb_transfer_cb_fn)(struct libusb_transfer *transfer); - -/** \ingroup asyncio - * The generic USB transfer structure. The user populates this structure and - * then submits it in order to request a transfer. After the transfer has - * completed, the library populates the transfer with the results and passes - * it back to the user. - */ -struct libusb_transfer { - /** Handle of the device that this transfer will be submitted to */ - libusb_device_handle *dev_handle; - - /** A bitwise OR combination of \ref libusb_transfer_flags. */ - uint8_t flags; - - /** Address of the endpoint where this transfer will be sent. */ - unsigned char endpoint; - - /** Type of the endpoint from \ref libusb_transfer_type */ - unsigned char type; - - /** Timeout for this transfer in millseconds. A value of 0 indicates no - * timeout. */ - unsigned int timeout; - - /** The status of the transfer. Read-only, and only for use within - * transfer callback function. - * - * If this is an isochronous transfer, this field may read COMPLETED even - * if there were errors in the frames. Use the - * \ref libusb_iso_packet_descriptor::status "status" field in each packet - * to determine if errors occurred. */ - enum libusb_transfer_status status; - - /** Length of the data buffer */ - int length; - - /** Actual length of data that was transferred. Read-only, and only for - * use within transfer callback function. Not valid for isochronous - * endpoint transfers. */ - int actual_length; - - /** Callback function. This will be invoked when the transfer completes, - * fails, or is cancelled. */ - libusb_transfer_cb_fn callback; - - /** User context data to pass to the callback function. */ - void *user_data; - - /** Data buffer */ - unsigned char *buffer; - - /** Number of isochronous packets. Only used for I/O with isochronous - * endpoints. */ - int num_iso_packets; - - /** Isochronous packet descriptors, for isochronous transfers only. */ - struct libusb_iso_packet_descriptor iso_packet_desc -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - [] /* valid C99 code */ -#else - [0] /* non-standard, but usually working code */ -#endif - ; -}; - -int LIBUSB_CALL libusb_init(libusb_context **ctx); -void LIBUSB_CALL libusb_exit(libusb_context *ctx); -void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level); -const char * LIBUSB_CALL libusb_strerror(enum libusb_error errcode); - -ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx, - libusb_device ***list); -void LIBUSB_CALL libusb_free_device_list(libusb_device **list, - int unref_devices); -libusb_device * LIBUSB_CALL libusb_ref_device(libusb_device *dev); -void LIBUSB_CALL libusb_unref_device(libusb_device *dev); - -int LIBUSB_CALL libusb_get_configuration(libusb_device_handle *dev, - int *config); -int LIBUSB_CALL libusb_get_device_descriptor(libusb_device *dev, - struct libusb_device_descriptor *desc); -int LIBUSB_CALL libusb_get_active_config_descriptor(libusb_device *dev, - struct libusb_config_descriptor **config); -int LIBUSB_CALL libusb_get_config_descriptor(libusb_device *dev, - uint8_t config_index, struct libusb_config_descriptor **config); -int LIBUSB_CALL libusb_get_config_descriptor_by_value(libusb_device *dev, - uint8_t bConfigurationValue, struct libusb_config_descriptor **config); -void LIBUSB_CALL libusb_free_config_descriptor( - struct libusb_config_descriptor *config); -uint8_t LIBUSB_CALL libusb_get_bus_number(libusb_device *dev); -uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device *dev); -int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev, - unsigned char endpoint); -int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev, - unsigned char endpoint); - -int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **handle); -void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle); -libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle); - -int LIBUSB_CALL libusb_set_configuration(libusb_device_handle *dev, - int configuration); -int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev, - int interface_number); -int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev, - int interface_number); - -libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( - libusb_context *ctx, uint16_t vendor_id, uint16_t product_id); - -int LIBUSB_CALL libusb_set_interface_alt_setting(libusb_device_handle *dev, - int interface_number, int alternate_setting); -int LIBUSB_CALL libusb_clear_halt(libusb_device_handle *dev, - unsigned char endpoint); -int LIBUSB_CALL libusb_reset_device(libusb_device_handle *dev); - -int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle *dev, - int interface_number); -int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev, - int interface_number); -int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle *dev, - int interface_number); - -/* async I/O */ - -/** \ingroup asyncio - * Get the data section of a control transfer. This convenience function is here - * to remind you that the data does not start until 8 bytes into the actual - * buffer, as the setup packet comes first. - * - * Calling this function only makes sense from a transfer callback function, - * or situations where you have already allocated a suitably sized buffer at - * transfer->buffer. - * - * \param transfer a transfer - * \returns pointer to the first byte of the data section - */ -static inline unsigned char *libusb_control_transfer_get_data( - struct libusb_transfer *transfer) -{ - return transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; -} - -/** \ingroup asyncio - * Get the control setup packet of a control transfer. This convenience - * function is here to remind you that the control setup occupies the first - * 8 bytes of the transfer data buffer. - * - * Calling this function only makes sense from a transfer callback function, - * or situations where you have already allocated a suitably sized buffer at - * transfer->buffer. - * - * \param transfer a transfer - * \returns a casted pointer to the start of the transfer data buffer - */ -static inline struct libusb_control_setup *libusb_control_transfer_get_setup( - struct libusb_transfer *transfer) -{ - return (struct libusb_control_setup *) transfer->buffer; -} - -/** \ingroup asyncio - * Helper function to populate the setup packet (first 8 bytes of the data - * buffer) for a control transfer. The wIndex, wValue and wLength values should - * be given in host-endian byte order. - * - * \param buffer buffer to output the setup packet into - * \param bmRequestType see the - * \ref libusb_control_setup::bmRequestType "bmRequestType" field of - * \ref libusb_control_setup - * \param bRequest see the - * \ref libusb_control_setup::bRequest "bRequest" field of - * \ref libusb_control_setup - * \param wValue see the - * \ref libusb_control_setup::wValue "wValue" field of - * \ref libusb_control_setup - * \param wIndex see the - * \ref libusb_control_setup::wIndex "wIndex" field of - * \ref libusb_control_setup - * \param wLength see the - * \ref libusb_control_setup::wLength "wLength" field of - * \ref libusb_control_setup - */ -static inline void libusb_fill_control_setup(unsigned char *buffer, - uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, - uint16_t wLength) -{ - struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer; - setup->bmRequestType = bmRequestType; - setup->bRequest = bRequest; - setup->wValue = libusb_cpu_to_le16(wValue); - setup->wIndex = libusb_cpu_to_le16(wIndex); - setup->wLength = libusb_cpu_to_le16(wLength); -} - -struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(int iso_packets); -int LIBUSB_CALL libusb_submit_transfer(struct libusb_transfer *transfer); -int LIBUSB_CALL libusb_cancel_transfer(struct libusb_transfer *transfer); -void LIBUSB_CALL libusb_free_transfer(struct libusb_transfer *transfer); - -/** \ingroup asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for a control transfer. - * - * If you pass a transfer buffer to this function, the first 8 bytes will - * be interpreted as a control setup packet, and the wLength field will be - * used to automatically populate the \ref libusb_transfer::length "length" - * field of the transfer. Therefore the recommended approach is: - * -# Allocate a suitably sized data buffer (including space for control setup) - * -# Call libusb_fill_control_setup() - * -# If this is a host-to-device transfer with a data stage, put the data - * in place after the setup packet - * -# Call this function - * -# Call libusb_submit_transfer() - * - * It is also legal to pass a NULL buffer to this function, in which case this - * function will not attempt to populate the length field. Remember that you - * must then populate the buffer and length fields later. - * - * \param transfer the transfer to populate - * \param dev_handle handle of the device that will handle the transfer - * \param buffer data buffer. If provided, this function will interpret the - * first 8 bytes as a setup packet and infer the transfer length from that. - * \param callback callback function to be invoked on transfer completion - * \param user_data user data to pass to callback function - * \param timeout timeout for the transfer in milliseconds - */ -static inline void libusb_fill_control_transfer( - struct libusb_transfer *transfer, libusb_device_handle *dev_handle, - unsigned char *buffer, libusb_transfer_cb_fn callback, void *user_data, - unsigned int timeout) -{ - struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer; - transfer->dev_handle = dev_handle; - transfer->endpoint = 0; - transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL; - transfer->timeout = timeout; - transfer->buffer = buffer; - if (setup) - transfer->length = LIBUSB_CONTROL_SETUP_SIZE - + libusb_le16_to_cpu(setup->wLength); - transfer->user_data = user_data; - transfer->callback = callback; -} - -/** \ingroup asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for a bulk transfer. - * - * \param transfer the transfer to populate - * \param dev_handle handle of the device that will handle the transfer - * \param endpoint address of the endpoint where this transfer will be sent - * \param buffer data buffer - * \param length length of data buffer - * \param callback callback function to be invoked on transfer completion - * \param user_data user data to pass to callback function - * \param timeout timeout for the transfer in milliseconds - */ -static inline void libusb_fill_bulk_transfer(struct libusb_transfer *transfer, - libusb_device_handle *dev_handle, unsigned char endpoint, - unsigned char *buffer, int length, libusb_transfer_cb_fn callback, - void *user_data, unsigned int timeout) -{ - transfer->dev_handle = dev_handle; - transfer->endpoint = endpoint; - transfer->type = LIBUSB_TRANSFER_TYPE_BULK; - transfer->timeout = timeout; - transfer->buffer = buffer; - transfer->length = length; - transfer->user_data = user_data; - transfer->callback = callback; -} - -/** \ingroup asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for an interrupt transfer. - * - * \param transfer the transfer to populate - * \param dev_handle handle of the device that will handle the transfer - * \param endpoint address of the endpoint where this transfer will be sent - * \param buffer data buffer - * \param length length of data buffer - * \param callback callback function to be invoked on transfer completion - * \param user_data user data to pass to callback function - * \param timeout timeout for the transfer in milliseconds - */ -static inline void libusb_fill_interrupt_transfer( - struct libusb_transfer *transfer, libusb_device_handle *dev_handle, - unsigned char endpoint, unsigned char *buffer, int length, - libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) -{ - transfer->dev_handle = dev_handle; - transfer->endpoint = endpoint; - transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT; - transfer->timeout = timeout; - transfer->buffer = buffer; - transfer->length = length; - transfer->user_data = user_data; - transfer->callback = callback; -} - -/** \ingroup asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for an isochronous transfer. - * - * \param transfer the transfer to populate - * \param dev_handle handle of the device that will handle the transfer - * \param endpoint address of the endpoint where this transfer will be sent - * \param buffer data buffer - * \param length length of data buffer - * \param num_iso_packets the number of isochronous packets - * \param callback callback function to be invoked on transfer completion - * \param user_data user data to pass to callback function - * \param timeout timeout for the transfer in milliseconds - */ -static inline void libusb_fill_iso_transfer(struct libusb_transfer *transfer, - libusb_device_handle *dev_handle, unsigned char endpoint, - unsigned char *buffer, int length, int num_iso_packets, - libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) -{ - transfer->dev_handle = dev_handle; - transfer->endpoint = endpoint; - transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS; - transfer->timeout = timeout; - transfer->buffer = buffer; - transfer->length = length; - transfer->num_iso_packets = num_iso_packets; - transfer->user_data = user_data; - transfer->callback = callback; -} - -/** \ingroup asyncio - * Convenience function to set the length of all packets in an isochronous - * transfer, based on the num_iso_packets field in the transfer structure. - * - * \param transfer a transfer - * \param length the length to set in each isochronous packet descriptor - * \see libusb_get_max_packet_size() - */ -static inline void libusb_set_iso_packet_lengths( - struct libusb_transfer *transfer, unsigned int length) -{ - int i; - for (i = 0; i < transfer->num_iso_packets; i++) - transfer->iso_packet_desc[i].length = length; -} - -/** \ingroup asyncio - * Convenience function to locate the position of an isochronous packet - * within the buffer of an isochronous transfer. - * - * This is a thorough function which loops through all preceding packets, - * accumulating their lengths to find the position of the specified packet. - * Typically you will assign equal lengths to each packet in the transfer, - * and hence the above method is sub-optimal. You may wish to use - * libusb_get_iso_packet_buffer_simple() instead. - * - * \param transfer a transfer - * \param packet the packet to return the address of - * \returns the base address of the packet buffer inside the transfer buffer, - * or NULL if the packet does not exist. - * \see libusb_get_iso_packet_buffer_simple() - */ -static inline unsigned char *libusb_get_iso_packet_buffer( - struct libusb_transfer *transfer, unsigned int packet) -{ - int i; - size_t offset = 0; - int _packet; - - /* oops..slight bug in the API. packet is an unsigned int, but we use - * signed integers almost everywhere else. range-check and convert to - * signed to avoid compiler warnings. FIXME for libusb-2. */ - if (packet > INT_MAX) - return NULL; - _packet = packet; - - if (_packet >= transfer->num_iso_packets) - return NULL; - - for (i = 0; i < _packet; i++) - offset += transfer->iso_packet_desc[i].length; - - return transfer->buffer + offset; -} - -/** \ingroup asyncio - * Convenience function to locate the position of an isochronous packet - * within the buffer of an isochronous transfer, for transfers where each - * packet is of identical size. - * - * This function relies on the assumption that every packet within the transfer - * is of identical size to the first packet. Calculating the location of - * the packet buffer is then just a simple calculation: - * <tt>buffer + (packet_size * packet)</tt> - * - * Do not use this function on transfers other than those that have identical - * packet lengths for each packet. - * - * \param transfer a transfer - * \param packet the packet to return the address of - * \returns the base address of the packet buffer inside the transfer buffer, - * or NULL if the packet does not exist. - * \see libusb_get_iso_packet_buffer() - */ -static inline unsigned char *libusb_get_iso_packet_buffer_simple( - struct libusb_transfer *transfer, unsigned int packet) -{ - int _packet; - - /* oops..slight bug in the API. packet is an unsigned int, but we use - * signed integers almost everywhere else. range-check and convert to - * signed to avoid compiler warnings. FIXME for libusb-2. */ - if (packet > INT_MAX) - return NULL; - _packet = packet; - - if (_packet >= transfer->num_iso_packets) - return NULL; - - return transfer->buffer + (transfer->iso_packet_desc[0].length * _packet); -} - -/* sync I/O */ - -int LIBUSB_CALL libusb_control_transfer(libusb_device_handle *dev_handle, - uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, - unsigned char *data, uint16_t wLength, unsigned int timeout); - -int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle *dev_handle, - unsigned char endpoint, unsigned char *data, int length, - int *actual_length, unsigned int timeout); - -int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle, - unsigned char endpoint, unsigned char *data, int length, - int *actual_length, unsigned int timeout); - -/** \ingroup desc - * Retrieve a descriptor from the default control pipe. - * This is a convenience function which formulates the appropriate control - * message to retrieve the descriptor. - * - * \param dev a device handle - * \param desc_type the descriptor type, see \ref libusb_descriptor_type - * \param desc_index the index of the descriptor to retrieve - * \param data output buffer for descriptor - * \param length size of data buffer - * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure - */ -static inline int libusb_get_descriptor(libusb_device_handle *dev, - uint8_t desc_type, uint8_t desc_index, unsigned char *data, int length) -{ - return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, - LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, - (uint16_t) length, 1000); -} - -/** \ingroup desc - * Retrieve a descriptor from a device. - * This is a convenience function which formulates the appropriate control - * message to retrieve the descriptor. The string returned is Unicode, as - * detailed in the USB specifications. - * - * \param dev a device handle - * \param desc_index the index of the descriptor to retrieve - * \param langid the language ID for the string descriptor - * \param data output buffer for descriptor - * \param length size of data buffer - * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure - * \see libusb_get_string_descriptor_ascii() - */ -static inline int libusb_get_string_descriptor(libusb_device_handle *dev, - uint8_t desc_index, uint16_t langid, unsigned char *data, int length) -{ - return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, - LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc_index, - langid, data, (uint16_t) length, 1000); -} - -int LIBUSB_CALL libusb_get_string_descriptor_ascii(libusb_device_handle *dev, - uint8_t desc_index, unsigned char *data, int length); - -/* polling and timeouts */ - -int LIBUSB_CALL libusb_try_lock_events(libusb_context *ctx); -void LIBUSB_CALL libusb_lock_events(libusb_context *ctx); -void LIBUSB_CALL libusb_unlock_events(libusb_context *ctx); -int LIBUSB_CALL libusb_event_handling_ok(libusb_context *ctx); -int LIBUSB_CALL libusb_event_handler_active(libusb_context *ctx); -void LIBUSB_CALL libusb_lock_event_waiters(libusb_context *ctx); -void LIBUSB_CALL libusb_unlock_event_waiters(libusb_context *ctx); -int LIBUSB_CALL libusb_wait_for_event(libusb_context *ctx, struct timeval *tv); - -int LIBUSB_CALL libusb_handle_events_timeout(libusb_context *ctx, - struct timeval *tv); -int LIBUSB_CALL libusb_handle_events(libusb_context *ctx); -int LIBUSB_CALL libusb_handle_events_locked(libusb_context *ctx, - struct timeval *tv); -int LIBUSB_CALL libusb_pollfds_handle_timeouts(libusb_context *ctx); -int LIBUSB_CALL libusb_get_next_timeout(libusb_context *ctx, - struct timeval *tv); - -/** \ingroup poll - * File descriptor for polling - */ -struct libusb_pollfd { - /** Numeric file descriptor */ - int fd; - - /** Event flags to poll for from <poll.h>. POLLIN indicates that you - * should monitor this file descriptor for becoming ready to read from, - * and POLLOUT indicates that you should monitor this file descriptor for - * nonblocking write readiness. */ - short events; -}; - -/** \ingroup poll - * Callback function, invoked when a new file descriptor should be added - * to the set of file descriptors monitored for events. - * \param fd the new file descriptor - * \param events events to monitor for, see \ref libusb_pollfd for a - * description - * \param user_data User data pointer specified in - * libusb_set_pollfd_notifiers() call - * \see libusb_set_pollfd_notifiers() - */ -typedef void (LIBUSB_CALL *libusb_pollfd_added_cb)(int fd, short events, - void *user_data); - -/** \ingroup poll - * Callback function, invoked when a file descriptor should be removed from - * the set of file descriptors being monitored for events. After returning - * from this callback, do not use that file descriptor again. - * \param fd the file descriptor to stop monitoring - * \param user_data User data pointer specified in - * libusb_set_pollfd_notifiers() call - * \see libusb_set_pollfd_notifiers() - */ -typedef void (LIBUSB_CALL *libusb_pollfd_removed_cb)(int fd, void *user_data); - -const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds( - libusb_context *ctx); -void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx, - libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, - void *user_data); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/libusb-1.0/os/libusbi.h b/include/libusb-1.0/os/libusbi.h deleted file mode 100644 index 9b2fa70..0000000 --- a/include/libusb-1.0/os/libusbi.h +++ /dev/null @@ -1,872 +0,0 @@ -/* - * Internal header for libusb - * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org> - * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LIBUSBI_H__ -#define __LIBUSBI_H__ - -#include <config.h> - -#include <stddef.h> -#include <stdint.h> -#include <time.h> - -#include <libusb.h> - -/* Inside the libusb code, mark all public functions as follows: - * return_type API_EXPORTED function_name(params) { ... } - * But if the function returns a pointer, mark it as follows: - * DEFAULT_VISIBILITY return_type * LIBUSB_CALL function_name(params) { ... } - * In the libusb public header, mark all declarations as: - * return_type LIBUSB_CALL function_name(params); - */ -#define API_EXPORTED LIBUSB_CALL DEFAULT_VISIBILITY - -#define DEVICE_DESC_LENGTH 18 - -#define USB_MAXENDPOINTS 32 -#define USB_MAXINTERFACES 32 -#define USB_MAXCONFIG 8 - -struct list_head { - struct list_head *prev, *next; -}; - -/* Get an entry from the list - * ptr - the address of this list_head element in "type" - * type - the data type that contains "member" - * member - the list_head element in "type" - */ -#define list_entry(ptr, type, member) \ - ((type *)((uintptr_t)(ptr) - (uintptr_t)(&((type *)0L)->member))) - -/* Get each entry from a list - * pos - A structure pointer has a "member" element - * head - list head - * member - the list_head element in "pos" - * type - the type of the first parameter - */ -#define list_for_each_entry(pos, head, member, type) \ - for (pos = list_entry((head)->next, type, member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, type, member)) - -#define list_for_each_entry_safe(pos, n, head, member, type) \ - for (pos = list_entry((head)->next, type, member), \ - n = list_entry(pos->member.next, type, member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, type, member)) - -#define list_empty(entry) ((entry)->next == (entry)) - -static inline void list_init(struct list_head *entry) -{ - entry->prev = entry->next = entry; -} - -static inline void list_add(struct list_head *entry, struct list_head *head) -{ - entry->next = head->next; - entry->prev = head; - - head->next->prev = entry; - head->next = entry; -} - -static inline void list_add_tail(struct list_head *entry, - struct list_head *head) -{ - entry->next = head; - entry->prev = head->prev; - - head->prev->next = entry; - head->prev = entry; -} - -static inline void list_del(struct list_head *entry) -{ - entry->next->prev = entry->prev; - entry->prev->next = entry->next; -} - -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - -#define TIMESPEC_IS_SET(ts) ((ts)->tv_sec != 0 || (ts)->tv_nsec != 0) - -enum usbi_log_level { - LOG_LEVEL_DEBUG, - LOG_LEVEL_INFO, - LOG_LEVEL_WARNING, - LOG_LEVEL_ERROR, -}; - -void usbi_log(struct libusb_context *ctx, enum usbi_log_level level, - const char *function, const char *format, ...); - -#if !defined(_MSC_VER) || _MSC_VER > 1200 - -#ifdef ENABLE_LOGGING -#define _usbi_log(ctx, level, ...) usbi_log(ctx, level, __FUNCTION__, __VA_ARGS__) -#else -#define _usbi_log(ctx, level, ...) -#endif - -#ifdef ENABLE_DEBUG_LOGGING -#define usbi_dbg(...) _usbi_log(NULL, LOG_LEVEL_DEBUG, __VA_ARGS__) -#else -#define usbi_dbg(...) -#endif - -#define usbi_info(ctx, ...) _usbi_log(ctx, LOG_LEVEL_INFO, __VA_ARGS__) -#define usbi_warn(ctx, ...) _usbi_log(ctx, LOG_LEVEL_WARNING, __VA_ARGS__) -#define usbi_err(ctx, ...) _usbi_log(ctx, LOG_LEVEL_ERROR, __VA_ARGS__) - -#else /* !defined(_MSC_VER) || _MSC_VER > 1200 */ - -void usbi_log_v(struct libusb_context *ctx, enum usbi_log_level level, - const char *function, const char *format, va_list args); - -#ifdef ENABLE_LOGGING -#define LOG_BODY(ctxt, level) \ -{ \ - va_list args; \ - va_start (args, format); \ - usbi_log_v(ctxt, level, "", format, args); \ - va_end(args); \ -} -#else -#define LOG_BODY(ctxt, level) { } -#endif - -static inline void usbi_info(struct libusb_context *ctx, const char *format, - ...) - LOG_BODY(ctx,LOG_LEVEL_INFO) -static inline void usbi_warn(struct libusb_context *ctx, const char *format, - ...) - LOG_BODY(ctx,LOG_LEVEL_WARNING) -static inline void usbi_err( struct libusb_context *ctx, const char *format, - ...) - LOG_BODY(ctx,LOG_LEVEL_ERROR) - -static inline void usbi_dbg(const char *format, ...) -#ifdef ENABLE_DEBUG_LOGGING - LOG_BODY(NULL,LOG_LEVEL_DEBUG) -#else -{ } -#endif - -#endif /* !defined(_MSC_VER) || _MSC_VER > 1200 */ - -#define USBI_GET_CONTEXT(ctx) if (!(ctx)) (ctx) = usbi_default_context -#define DEVICE_CTX(dev) ((dev)->ctx) -#define HANDLE_CTX(handle) (DEVICE_CTX((handle)->dev)) -#define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle)) -#define ITRANSFER_CTX(transfer) \ - (TRANSFER_CTX(__USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer))) - -/* Internal abstractions for thread synchronization and poll */ -#if defined(THREADS_POSIX) -#include <os/threads_posix.h> -#elif defined(OS_WINDOWS) -#include <os/threads_windows.h> -#endif - -#if defined(OS_LINUX) || defined(OS_DARWIN) -#include <os/poll_posix.h> -#elif defined(OS_WINDOWS) -#include <os/poll_windows.h> -#endif - -extern struct libusb_context *usbi_default_context; - -struct libusb_context { - int debug; - int debug_fixed; - - /* internal control pipe, used for interrupting event handling when - * something needs to modify poll fds. */ - int ctrl_pipe[2]; - - struct list_head usb_devs; - usbi_mutex_t usb_devs_lock; - - /* A list of open handles. Backends are free to traverse this if required. - */ - struct list_head open_devs; - usbi_mutex_t open_devs_lock; - - /* this is a list of in-flight transfer handles, sorted by timeout - * expiration. URBs to timeout the soonest are placed at the beginning of - * the list, URBs that will time out later are placed after, and urbs with - * infinite timeout are always placed at the very end. */ - struct list_head flying_transfers; - usbi_mutex_t flying_transfers_lock; - - /* list of poll fds */ - struct list_head pollfds; - usbi_mutex_t pollfds_lock; - - /* a counter that is set when we want to interrupt event handling, in order - * to modify the poll fd set. and a lock to protect it. */ - unsigned int pollfd_modify; - usbi_mutex_t pollfd_modify_lock; - - /* user callbacks for pollfd changes */ - libusb_pollfd_added_cb fd_added_cb; - libusb_pollfd_removed_cb fd_removed_cb; - void *fd_cb_user_data; - - /* ensures that only one thread is handling events at any one time */ - usbi_mutex_t events_lock; - - /* used to see if there is an active thread doing event handling */ - int event_handler_active; - - /* used to wait for event completion in threads other than the one that is - * event handling */ - usbi_mutex_t event_waiters_lock; - usbi_cond_t event_waiters_cond; - -#ifdef USBI_TIMERFD_AVAILABLE - /* used for timeout handling, if supported by OS. - * this timerfd is maintained to trigger on the next pending timeout */ - int timerfd; -#endif -}; - -#ifdef USBI_TIMERFD_AVAILABLE -#define usbi_using_timerfd(ctx) ((ctx)->timerfd >= 0) -#else -#define usbi_using_timerfd(ctx) (0) -#endif - -struct libusb_device { - /* lock protects refcnt, everything else is finalized at initialization - * time */ - usbi_mutex_t lock; - int refcnt; - - struct libusb_context *ctx; - - uint8_t bus_number; - uint8_t device_address; - uint8_t num_configurations; - - struct list_head list; - unsigned long session_data; - unsigned char os_priv[0]; -}; - -struct libusb_device_handle { - /* lock protects claimed_interfaces */ - usbi_mutex_t lock; - unsigned long claimed_interfaces; - - struct list_head list; - struct libusb_device *dev; - unsigned char os_priv[0]; -}; - -#define USBI_TRANSFER_TIMED_OUT (1<<0) - -enum { - USBI_CLOCK_MONOTONIC, - USBI_CLOCK_REALTIME -}; - -/* in-memory transfer layout: - * - * 1. struct usbi_transfer - * 2. struct libusb_transfer (which includes iso packets) [variable size] - * 3. os private data [variable size] - * - * from a libusb_transfer, you can get the usbi_transfer by rewinding the - * appropriate number of bytes. - * the usbi_transfer includes the number of allocated packets, so you can - * determine the size of the transfer and hence the start and length of the - * OS-private data. - */ - -struct usbi_transfer { - int num_iso_packets; - struct list_head list; - struct timeval timeout; - int transferred; - uint8_t flags; - - /* this lock is held during libusb_submit_transfer() and - * libusb_cancel_transfer() (allowing the OS backend to prevent duplicate - * cancellation, submission-during-cancellation, etc). the OS backend - * should also take this lock in the handle_events path, to prevent the user - * cancelling the transfer from another thread while you are processing - * its completion (presumably there would be races within your OS backend - * if this were possible). */ - usbi_mutex_t lock; -}; - -#define __USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \ - ((struct libusb_transfer *)(((unsigned char *)(transfer)) \ - + sizeof(struct usbi_transfer))) -#define __LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer) \ - ((struct usbi_transfer *)(((unsigned char *)(transfer)) \ - - sizeof(struct usbi_transfer))) - -static inline void *usbi_transfer_get_os_priv(struct usbi_transfer *transfer) -{ - return ((unsigned char *)transfer) + sizeof(struct usbi_transfer) - + sizeof(struct libusb_transfer) - + (transfer->num_iso_packets - * sizeof(struct libusb_iso_packet_descriptor)); -} - -/* bus structures */ - -/* All standard descriptors have these 2 fields in common */ -struct usb_descriptor_header { - uint8_t bLength; - uint8_t bDescriptorType; -}; - -/* shared data and functions */ - -int usbi_io_init(struct libusb_context *ctx); -void usbi_io_exit(struct libusb_context *ctx); - -struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, - unsigned long session_id); -struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx, - unsigned long session_id); -int usbi_sanitize_device(struct libusb_device *dev); -void usbi_handle_disconnect(struct libusb_device_handle *handle); - -int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, - enum libusb_transfer_status status); -int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer); - -int usbi_parse_descriptor(unsigned char *source, char *descriptor, void *dest, - int host_endian); -int usbi_get_config_index_by_value(struct libusb_device *dev, - uint8_t bConfigurationValue, int *idx); - -/* polling */ - -struct usbi_pollfd { - /* must come first */ - struct libusb_pollfd pollfd; - - struct list_head list; -}; - -int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events); -void usbi_remove_pollfd(struct libusb_context *ctx, int fd); -void usbi_fd_notification(struct libusb_context *ctx); - -/* device discovery */ - -/* we traverse usbfs without knowing how many devices we are going to find. - * so we create this discovered_devs model which is similar to a linked-list - * which grows when required. it can be freed once discovery has completed, - * eliminating the need for a list node in the libusb_device structure - * itself. */ -struct discovered_devs { - size_t len; - size_t capacity; - struct libusb_device *devices[0]; -}; - -struct discovered_devs *discovered_devs_append( - struct discovered_devs *discdevs, struct libusb_device *dev); - -/* OS abstraction */ - -/* This is the interface that OS backends need to implement. - * All fields are mandatory, except ones explicitly noted as optional. */ -struct usbi_os_backend { - /* A human-readable name for your backend, e.g. "Linux usbfs" */ - const char *name; - - /* Perform initialization of your backend. You might use this function - * to determine specific capabilities of the system, allocate required - * data structures for later, etc. - * - * This function is called when a libusb user initializes the library - * prior to use. - * - * Return 0 on success, or a LIBUSB_ERROR code on failure. - */ - int (*init)(struct libusb_context *ctx); - - /* Deinitialization. Optional. This function should destroy anything - * that was set up by init. - * - * This function is called when the user deinitializes the library. - */ - void (*exit)(void); - - /* Enumerate all the USB devices on the system, returning them in a list - * of discovered devices. - * - * Your implementation should enumerate all devices on the system, - * regardless of whether they have been seen before or not. - * - * When you have found a device, compute a session ID for it. The session - * ID should uniquely represent that particular device for that particular - * connection session since boot (i.e. if you disconnect and reconnect a - * device immediately after, it should be assigned a different session ID). - * If your OS cannot provide a unique session ID as described above, - * presenting a session ID of (bus_number << 8 | device_address) should - * be sufficient. Bus numbers and device addresses wrap and get reused, - * but that is an unlikely case. - * - * After computing a session ID for a device, call - * usbi_get_device_by_session_id(). This function checks if libusb already - * knows about the device, and if so, it provides you with a libusb_device - * structure for it. - * - * If usbi_get_device_by_session_id() returns NULL, it is time to allocate - * a new device structure for the device. Call usbi_alloc_device() to - * obtain a new libusb_device structure with reference count 1. Populate - * the bus_number and device_address attributes of the new device, and - * perform any other internal backend initialization you need to do. At - * this point, you should be ready to provide device descriptors and so - * on through the get_*_descriptor functions. Finally, call - * usbi_sanitize_device() to perform some final sanity checks on the - * device. Assuming all of the above succeeded, we can now continue. - * If any of the above failed, remember to unreference the device that - * was returned by usbi_alloc_device(). - * - * At this stage we have a populated libusb_device structure (either one - * that was found earlier, or one that we have just allocated and - * populated). This can now be added to the discovered devices list - * using discovered_devs_append(). Note that discovered_devs_append() - * may reallocate the list, returning a new location for it, and also - * note that reallocation can fail. Your backend should handle these - * error conditions appropriately. - * - * This function should not generate any bus I/O and should not block. - * If I/O is required (e.g. reading the active configuration value), it is - * OK to ignore these suggestions :) - * - * This function is executed when the user wishes to retrieve a list - * of USB devices connected to the system. - * - * Return 0 on success, or a LIBUSB_ERROR code on failure. - */ - int (*get_device_list)(struct libusb_context *ctx, - struct discovered_devs **discdevs); - - /* Open a device for I/O and other USB operations. The device handle - * is preallocated for you, you can retrieve the device in question - * through handle->dev. - * - * Your backend should allocate any internal resources required for I/O - * and other operations so that those operations can happen (hopefully) - * without hiccup. This is also a good place to inform libusb that it - * should monitor certain file descriptors related to this device - - * see the usbi_add_pollfd() function. - * - * This function should not generate any bus I/O and should not block. - * - * This function is called when the user attempts to obtain a device - * handle for a device. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_ACCESS if the user has insufficient permissions - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since - * discovery - * - another LIBUSB_ERROR code on other failure - * - * Do not worry about freeing the handle on failed open, the upper layers - * do this for you. - */ - int (*open)(struct libusb_device_handle *handle); - - /* Close a device such that the handle cannot be used again. Your backend - * should destroy any resources that were allocated in the open path. - * This may also be a good place to call usbi_remove_pollfd() to inform - * libusb of any file descriptors associated with this device that should - * no longer be monitored. - * - * This function is called when the user closes a device handle. - */ - void (*close)(struct libusb_device_handle *handle); - - /* Retrieve the device descriptor from a device. - * - * The descriptor should be retrieved from memory, NOT via bus I/O to the - * device. This means that you may have to cache it in a private structure - * during get_device_list enumeration. Alternatively, you may be able - * to retrieve it from a kernel interface (some Linux setups can do this) - * still without generating bus I/O. - * - * This function is expected to write DEVICE_DESC_LENGTH (18) bytes into - * buffer, which is guaranteed to be big enough. - * - * This function is called when sanity-checking a device before adding - * it to the list of discovered devices, and also when the user requests - * to read the device descriptor. - * - * This function is expected to return the descriptor in bus-endian format - * (LE). If it returns the multi-byte values in host-endian format, - * set the host_endian output parameter to "1". - * - * Return 0 on success or a LIBUSB_ERROR code on failure. - */ - int (*get_device_descriptor)(struct libusb_device *device, - unsigned char *buffer, int *host_endian); - - /* Get the ACTIVE configuration descriptor for a device. - * - * The descriptor should be retrieved from memory, NOT via bus I/O to the - * device. This means that you may have to cache it in a private structure - * during get_device_list enumeration. You may also have to keep track - * of which configuration is active when the user changes it. - * - * This function is expected to write len bytes of data into buffer, which - * is guaranteed to be big enough. If you can only do a partial write, - * return an error code. - * - * This function is expected to return the descriptor in bus-endian format - * (LE). If it returns the multi-byte values in host-endian format, - * set the host_endian output parameter to "1". - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state - * - another LIBUSB_ERROR code on other failure - */ - int (*get_active_config_descriptor)(struct libusb_device *device, - unsigned char *buffer, size_t len, int *host_endian); - - /* Get a specific configuration descriptor for a device. - * - * The descriptor should be retrieved from memory, NOT via bus I/O to the - * device. This means that you may have to cache it in a private structure - * during get_device_list enumeration. - * - * The requested descriptor is expressed as a zero-based index (i.e. 0 - * indicates that we are requesting the first descriptor). The index does - * not (necessarily) equal the bConfigurationValue of the configuration - * being requested. - * - * This function is expected to write len bytes of data into buffer, which - * is guaranteed to be big enough. If you can only do a partial write, - * return an error code. - * - * This function is expected to return the descriptor in bus-endian format - * (LE). If it returns the multi-byte values in host-endian format, - * set the host_endian output parameter to "1". - * - * Return 0 on success or a LIBUSB_ERROR code on failure. - */ - int (*get_config_descriptor)(struct libusb_device *device, - uint8_t config_index, unsigned char *buffer, size_t len, - int *host_endian); - - /* Get the bConfigurationValue for the active configuration for a device. - * Optional. This should only be implemented if you can retrieve it from - * cache (don't generate I/O). - * - * If you cannot retrieve this from cache, either do not implement this - * function, or return LIBUSB_ERROR_NOT_SUPPORTED. This will cause - * libusb to retrieve the information through a standard control transfer. - * - * This function must be non-blocking. - * Return: - * - 0 on success - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - LIBUSB_ERROR_NOT_SUPPORTED if the value cannot be retrieved without - * blocking - * - another LIBUSB_ERROR code on other failure. - */ - int (*get_configuration)(struct libusb_device_handle *handle, int *config); - - /* Set the active configuration for a device. - * - * A configuration value of -1 should put the device in unconfigured state. - * - * This function can block. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the configuration does not exist - * - LIBUSB_ERROR_BUSY if interfaces are currently claimed (and hence - * configuration cannot be changed) - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure. - */ - int (*set_configuration)(struct libusb_device_handle *handle, int config); - - /* Claim an interface. When claimed, the application can then perform - * I/O to an interface's endpoints. - * - * This function should not generate any bus I/O and should not block. - * Interface claiming is a logical operation that simply ensures that - * no other drivers/applications are using the interface, and after - * claiming, no other drivers/applicatiosn can use the interface because - * we now "own" it. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the interface does not exist - * - LIBUSB_ERROR_BUSY if the interface is in use by another driver/app - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*claim_interface)(struct libusb_device_handle *handle, int interface_number); - - /* Release a previously claimed interface. - * - * This function should also generate a SET_INTERFACE control request, - * resetting the alternate setting of that interface to 0. It's OK for - * this function to block as a result. - * - * You will only ever be asked to release an interface which was - * successfully claimed earlier. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*release_interface)(struct libusb_device_handle *handle, int interface_number); - - /* Set the alternate setting for an interface. - * - * You will only ever be asked to set the alternate setting for an - * interface which was successfully claimed earlier. - * - * It's OK for this function to block. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the alternate setting does not exist - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*set_interface_altsetting)(struct libusb_device_handle *handle, - int interface_number, int altsetting); - - /* Clear a halt/stall condition on an endpoint. - * - * It's OK for this function to block. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*clear_halt)(struct libusb_device_handle *handle, - unsigned char endpoint); - - /* Perform a USB port reset to reinitialize a device. - * - * If possible, the handle should still be usable after the reset - * completes, assuming that the device descriptors did not change during - * reset and all previous interface state can be restored. - * - * If something changes, or you cannot easily locate/verify the resetted - * device, return LIBUSB_ERROR_NOT_FOUND. This prompts the application - * to close the old handle and re-enumerate the device. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the device - * has been disconnected since it was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*reset_device)(struct libusb_device_handle *handle); - - /* Determine if a kernel driver is active on an interface. Optional. - * - * The presence of a kernel driver on an interface indicates that any - * calls to claim_interface would fail with the LIBUSB_ERROR_BUSY code. - * - * Return: - * - 0 if no driver is active - * - 1 if a driver is active - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*kernel_driver_active)(struct libusb_device_handle *handle, - int interface_number); - - /* Detach a kernel driver from an interface. Optional. - * - * After detaching a kernel driver, the interface should be available - * for claim. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active - * - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*detach_kernel_driver)(struct libusb_device_handle *handle, - int interface_number); - - /* Attach a kernel driver to an interface. Optional. - * - * Reattach a kernel driver to the device. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active - * - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - LIBUSB_ERROR_BUSY if a program or driver has claimed the interface, - * preventing reattachment - * - another LIBUSB_ERROR code on other failure - */ - int (*attach_kernel_driver)(struct libusb_device_handle *handle, - int interface_number); - - /* Destroy a device. Optional. - * - * This function is called when the last reference to a device is - * destroyed. It should free any resources allocated in the get_device_list - * path. - */ - void (*destroy_device)(struct libusb_device *dev); - - /* Submit a transfer. Your implementation should take the transfer, - * morph it into whatever form your platform requires, and submit it - * asynchronously. - * - * This function must not block. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * - another LIBUSB_ERROR code on other failure - */ - int (*submit_transfer)(struct usbi_transfer *itransfer); - - /* Cancel a previously submitted transfer. - * - * This function must not block. The transfer cancellation must complete - * later, resulting in a call to usbi_handle_transfer_cancellation() - * from the context of handle_events. - */ - int (*cancel_transfer)(struct usbi_transfer *itransfer); - - /* Clear a transfer as if it has completed or cancelled, but do not - * report any completion/cancellation to the library. You should free - * all private data from the transfer as if you were just about to report - * completion or cancellation. - * - * This function might seem a bit out of place. It is used when libusb - * detects a disconnected device - it calls this function for all pending - * transfers before reporting completion (with the disconnect code) to - * the user. Maybe we can improve upon this internal interface in future. - */ - void (*clear_transfer_priv)(struct usbi_transfer *itransfer); - - /* Handle any pending events. This involves monitoring any active - * transfers and processing their completion or cancellation. - * - * The function is passed an array of pollfd structures (size nfds) - * as a result of the poll() system call. The num_ready parameter - * indicates the number of file descriptors that have reported events - * (i.e. the poll() return value). This should be enough information - * for you to determine which actions need to be taken on the currently - * active transfers. - * - * For any cancelled transfers, call usbi_handle_transfer_cancellation(). - * For completed transfers, call usbi_handle_transfer_completion(). - * For control/bulk/interrupt transfers, populate the "transferred" - * element of the appropriate usbi_transfer structure before calling the - * above functions. For isochronous transfers, populate the status and - * transferred fields of the iso packet descriptors of the transfer. - * - * This function should also be able to detect disconnection of the - * device, reporting that situation with usbi_handle_disconnect(). - * - * When processing an event related to a transfer, you probably want to - * take usbi_transfer.lock to prevent races. See the documentation for - * the usbi_transfer structure. - * - * Return 0 on success, or a LIBUSB_ERROR code on failure. - */ - int (*handle_events)(struct libusb_context *ctx, - struct pollfd *fds, nfds_t nfds, int num_ready); - - /* Get time from specified clock. At least two clocks must be implemented - by the backend: USBI_CLOCK_REALTIME, and USBI_CLOCK_MONOTONIC. - - Description of clocks: - USBI_CLOCK_REALTIME : clock returns time since system epoch. - USBI_CLOCK_MONOTONIC: clock returns time since unspecified start - time (usually boot). - */ - int (*clock_gettime)(int clkid, struct timespec *tp); - -#ifdef USBI_TIMERFD_AVAILABLE - /* clock ID of the clock that should be used for timerfd */ - clockid_t (*get_timerfd_clockid)(void); -#endif - - /* Number of bytes to reserve for per-device private backend data. - * This private data area is accessible through the "os_priv" field of - * struct libusb_device. */ - size_t device_priv_size; - - /* Number of bytes to reserve for per-handle private backend data. - * This private data area is accessible through the "os_priv" field of - * struct libusb_device. */ - size_t device_handle_priv_size; - - /* Number of bytes to reserve for per-transfer private backend data. - * This private data area is accessible by calling - * usbi_transfer_get_os_priv() on the appropriate usbi_transfer instance. - */ - size_t transfer_priv_size; - - /* Mumber of additional bytes for os_priv for each iso packet. - * Can your backend use this? */ - /* FIXME: linux can't use this any more. if other OS's cannot either, - * then remove this */ - size_t add_iso_packet_size; -}; - -extern const struct usbi_os_backend * const usbi_backend; - -extern const struct usbi_os_backend linux_usbfs_backend; -extern const struct usbi_os_backend darwin_backend; -extern const struct usbi_os_backend windows_backend; - -#endif - diff --git a/include/libusb-1.0/os/linux_usbfs.c b/include/libusb-1.0/os/linux_usbfs.c deleted file mode 100644 index a44688d..0000000 --- a/include/libusb-1.0/os/linux_usbfs.c +++ /dev/null @@ -1,2220 +0,0 @@ -/* - * Linux usbfs backend for libusb - * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org> - * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <config.h> -#include <ctype.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <poll.h> -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/utsname.h> -#include <unistd.h> - -#include "libusb.h" -#include "libusbi.h" -#include "linux_usbfs.h" - -/* sysfs vs usbfs: - * opening a usbfs node causes the device to be resumed, so we attempt to - * avoid this during enumeration. - * - * sysfs allows us to read the kernel's in-memory copies of device descriptors - * and so forth, avoiding the need to open the device: - * - The binary "descriptors" file was added in 2.6.23. - * - The "busnum" file was added in 2.6.22 - * - The "devnum" file has been present since pre-2.6.18 - * - the "bConfigurationValue" file has been present since pre-2.6.18 - * - * If we have bConfigurationValue, busnum, and devnum, then we can determine - * the active configuration without having to open the usbfs node in RDWR mode. - * We assume this is the case if we see the busnum file (indicates 2.6.22+). - * The busnum file is important as that is the only way we can relate sysfs - * devices to usbfs nodes. - * - * If we also have descriptors, we can obtain the device descriptor and active - * configuration without touching usbfs at all. - * - * The descriptors file originally only contained the active configuration - * descriptor alongside the device descriptor, but all configurations are - * included as of Linux 2.6.26. - */ - -/* endianness for multi-byte fields: - * - * Descriptors exposed by usbfs have the multi-byte fields in the device - * descriptor as host endian. Multi-byte fields in the other descriptors are - * bus-endian. The kernel documentation says otherwise, but it is wrong. - */ - -static const char *usbfs_path = NULL; - -/* Linux 2.6.32 adds support for a bulk continuation URB flag. this basically - * allows us to mark URBs as being part of a specific logical transfer when - * we submit them to the kernel. then, on any error error except a - * cancellation, all URBs within that transfer will be cancelled with the - * endpoint is disabled, meaning that no more data can creep in during the - * time it takes to cancel the remaining URBs. - * - * The BULK_CONTINUATION flag must be set on all URBs within a bulk transfer - * (in either direction) except the first. - * For IN transfers, we must also set SHORT_NOT_OK on all the URBs. - * For OUT transfers, SHORT_NOT_OK must not be set. The effective behaviour - * (where an OUT transfer does not complete, the rest of the URBs in the - * transfer get cancelled) is already in effect, and setting this flag is - * disallowed (a kernel with USB debugging enabled will reject such URBs). - */ -static int supports_flag_bulk_continuation = -1; - -/* clock ID for monotonic clock, as not all clock sources are available on all - * systems. appropriate choice made at initialization time. */ -static clockid_t monotonic_clkid = -1; - -/* do we have a busnum to relate devices? this also implies that we can read - * the active configuration through bConfigurationValue */ -static int sysfs_can_relate_devices = -1; - -/* do we have a descriptors file? */ -static int sysfs_has_descriptors = -1; - -struct linux_device_priv { - char *sysfs_dir; - unsigned char *dev_descriptor; - unsigned char *config_descriptor; -}; - -struct linux_device_handle_priv { - int fd; -}; - -enum reap_action { - NORMAL = 0, - /* submission failed after the first URB, so await cancellation/completion - * of all the others */ - SUBMIT_FAILED, - - /* cancelled by user or timeout */ - CANCELLED, - - /* completed multi-URB transfer in non-final URB */ - COMPLETED_EARLY, - - /* one or more urbs encountered a low-level error */ - ERROR, -}; - -struct linux_transfer_priv { - union { - struct usbfs_urb *urbs; - struct usbfs_urb **iso_urbs; - }; - - enum reap_action reap_action; - int num_urbs; - unsigned int num_retired; - enum libusb_transfer_status reap_status; - - /* next iso packet in user-supplied transfer to be populated */ - int iso_packet_offset; -}; - -static void __get_usbfs_path(struct libusb_device *dev, char *path) -{ - snprintf(path, PATH_MAX, "%s/%03d/%03d", usbfs_path, dev->bus_number, - dev->device_address); -} - -static struct linux_device_priv *__device_priv(struct libusb_device *dev) -{ - return (struct linux_device_priv *) dev->os_priv; -} - -static struct linux_device_handle_priv *__device_handle_priv( - struct libusb_device_handle *handle) -{ - return (struct linux_device_handle_priv *) handle->os_priv; -} - -static int check_usb_vfs(const char *dirname) -{ - DIR *dir; - struct dirent *entry; - int found = 0; - - dir = opendir(dirname); - if (!dir) - return 0; - - while ((entry = readdir(dir)) != NULL) { - if (entry->d_name[0] == '.') - continue; - - /* We assume if we find any files that it must be the right place */ - found = 1; - break; - } - - closedir(dir); - return found; -} - -static const char *find_usbfs_path(void) -{ - const char *path = "/dev/bus/usb"; - const char *ret = NULL; - - if (check_usb_vfs(path)) { - ret = path; - } else { - path = "/proc/bus/usb"; - if (check_usb_vfs(path)) - ret = path; - } - - usbi_dbg("found usbfs at %s", ret); - return ret; -} - -/* the monotonic clock is not usable on all systems (e.g. embedded ones often - * seem to lack it). fall back to REALTIME if we have to. */ -static clockid_t find_monotonic_clock(void) -{ - struct timespec ts; - int r; - -#ifdef CLOCK_MONOTONIC - /* Linux 2.6.28 adds CLOCK_MONOTONIC_RAW but we don't use it - * because it's not available through timerfd */ - r = clock_gettime(CLOCK_MONOTONIC, &ts); - if (r == 0) - return CLOCK_MONOTONIC; - usbi_dbg("monotonic clock doesn't work, errno %d", errno); -#endif - - return CLOCK_REALTIME; -} - -/* bulk continuation URB flag available from Linux 2.6.32 */ -static int check_flag_bulk_continuation(void) -{ - struct utsname uts; - int sublevel; - - if (uname(&uts) < 0) - return -1; - if (strlen(uts.release) < 4) - return 0; - if (strncmp(uts.release, "2.6.", 4) != 0) - return 0; - - sublevel = atoi(uts.release + 4); - return sublevel >= 32; -} - -static int op_init(struct libusb_context *ctx) -{ - struct stat statbuf; - int r; - - usbfs_path = find_usbfs_path(); - if (!usbfs_path) { - usbi_err(ctx, "could not find usbfs"); - return LIBUSB_ERROR_OTHER; - } - - if (monotonic_clkid == -1) - monotonic_clkid = find_monotonic_clock(); - - if (supports_flag_bulk_continuation == -1) { - supports_flag_bulk_continuation = check_flag_bulk_continuation(); - if (supports_flag_bulk_continuation == -1) { - usbi_err(ctx, "error checking for bulk continuation support"); - return LIBUSB_ERROR_OTHER; - } - } - - if (supports_flag_bulk_continuation) - usbi_dbg("bulk continuation flag supported"); - - r = stat(SYSFS_DEVICE_PATH, &statbuf); - if (r == 0 && S_ISDIR(statbuf.st_mode)) { - usbi_dbg("found usb devices in sysfs"); - } else { - usbi_dbg("sysfs usb info not available"); - sysfs_has_descriptors = 0; - sysfs_can_relate_devices = 0; - } - - return 0; -} - -static int usbfs_get_device_descriptor(struct libusb_device *dev, - unsigned char *buffer) -{ - struct linux_device_priv *priv = __device_priv(dev); - - /* return cached copy */ - memcpy(buffer, priv->dev_descriptor, DEVICE_DESC_LENGTH); - return 0; -} - -static int __open_sysfs_attr(struct libusb_device *dev, const char *attr) -{ - struct linux_device_priv *priv = __device_priv(dev); - char filename[PATH_MAX]; - int fd; - - snprintf(filename, PATH_MAX, "%s/%s/%s", - SYSFS_DEVICE_PATH, priv->sysfs_dir, attr); - fd = open(filename, O_RDONLY); - if (fd < 0) { - usbi_err(DEVICE_CTX(dev), - "open %s failed ret=%d errno=%d", filename, fd, errno); - return LIBUSB_ERROR_IO; - } - - return fd; -} - -static int sysfs_get_device_descriptor(struct libusb_device *dev, - unsigned char *buffer) -{ - int fd; - ssize_t r; - - /* sysfs provides access to an in-memory copy of the device descriptor, - * so we use that rather than keeping our own copy */ - - fd = __open_sysfs_attr(dev, "descriptors"); - if (fd < 0) - return fd; - - r = read(fd, buffer, DEVICE_DESC_LENGTH);; - close(fd); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), "read failed, ret=%d errno=%d", fd, errno); - return LIBUSB_ERROR_IO; - } else if (r < DEVICE_DESC_LENGTH) { - usbi_err(DEVICE_CTX(dev), "short read %d/%d", r, DEVICE_DESC_LENGTH); - return LIBUSB_ERROR_IO; - } - - return 0; -} - -static int op_get_device_descriptor(struct libusb_device *dev, - unsigned char *buffer, int *host_endian) -{ - if (sysfs_has_descriptors) { - return sysfs_get_device_descriptor(dev, buffer); - } else { - *host_endian = 1; - return usbfs_get_device_descriptor(dev, buffer); - } -} - -static int usbfs_get_active_config_descriptor(struct libusb_device *dev, - unsigned char *buffer, size_t len) -{ - struct linux_device_priv *priv = __device_priv(dev); - if (!priv->config_descriptor) - return LIBUSB_ERROR_NOT_FOUND; /* device is unconfigured */ - - /* retrieve cached copy */ - memcpy(buffer, priv->config_descriptor, len); - return 0; -} - -/* read the bConfigurationValue for a device */ -static int sysfs_get_active_config(struct libusb_device *dev, int *config) -{ - char *endptr; - char tmp[4] = {0, 0, 0, 0}; - long num; - int fd; - size_t r; - - fd = __open_sysfs_attr(dev, "bConfigurationValue"); - if (fd < 0) - return fd; - - r = read(fd, tmp, sizeof(tmp)); - close(fd); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), - "read bConfigurationValue failed ret=%d errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } else if (r == 0) { - usbi_err(DEVICE_CTX(dev), "device unconfigured"); - *config = -1; - return 0; - } - - if (tmp[sizeof(tmp) - 1] != 0) { - usbi_err(DEVICE_CTX(dev), "not null-terminated?"); - return LIBUSB_ERROR_IO; - } else if (tmp[0] == 0) { - usbi_err(DEVICE_CTX(dev), "no configuration value?"); - return LIBUSB_ERROR_IO; - } - - num = strtol(tmp, &endptr, 10); - if (endptr == tmp) { - usbi_err(DEVICE_CTX(dev), "error converting '%s' to integer", tmp); - return LIBUSB_ERROR_IO; - } - - *config = (int) num; - return 0; -} - -/* takes a usbfs/descriptors fd seeked to the start of a configuration, and - * seeks to the next one. */ -static int seek_to_next_config(struct libusb_context *ctx, int fd, - int host_endian) -{ - struct libusb_config_descriptor config; - unsigned char tmp[6]; - off_t off; - int r; - - /* read first 6 bytes of descriptor */ - r = read(fd, tmp, sizeof(tmp)); - if (r < 0) { - usbi_err(ctx, "read failed ret=%d errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } else if (r < sizeof(tmp)) { - usbi_err(ctx, "short descriptor read %d/%d", r, sizeof(tmp)); - return LIBUSB_ERROR_IO; - } - - /* seek forward to end of config */ - usbi_parse_descriptor(tmp, "bbwbb", &config, host_endian); - off = lseek(fd, config.wTotalLength - sizeof(tmp), SEEK_CUR); - if (off < 0) { - usbi_err(ctx, "seek failed ret=%d errno=%d", off, errno); - return LIBUSB_ERROR_IO; - } - - return 0; -} - -static int sysfs_get_active_config_descriptor(struct libusb_device *dev, - unsigned char *buffer, size_t len) -{ - int fd; - ssize_t r; - off_t off; - int to_copy; - int config; - unsigned char tmp[6]; - - r = sysfs_get_active_config(dev, &config); - if (r < 0) - return r; - if (config == -1) - return LIBUSB_ERROR_NOT_FOUND; - - usbi_dbg("active configuration %d", config); - - /* sysfs provides access to an in-memory copy of the device descriptor, - * so we use that rather than keeping our own copy */ - - fd = __open_sysfs_attr(dev, "descriptors"); - if (fd < 0) - return fd; - - /* device might have been unconfigured since we read bConfigurationValue, - * so first check that there is any config descriptor data at all... */ - off = lseek(fd, 0, SEEK_END); - if (off < 1) { - usbi_err(DEVICE_CTX(dev), "end seek failed, ret=%d errno=%d", - off, errno); - close(fd); - return LIBUSB_ERROR_IO; - } else if (off == DEVICE_DESC_LENGTH) { - close(fd); - return LIBUSB_ERROR_NOT_FOUND; - } - - off = lseek(fd, DEVICE_DESC_LENGTH, SEEK_SET); - if (off < 0) { - usbi_err(DEVICE_CTX(dev), "seek failed, ret=%d errno=%d", off, errno); - close(fd); - return LIBUSB_ERROR_IO; - } - - /* unbounded loop: we expect the descriptor to be present under all - * circumstances */ - while (1) { - r = read(fd, tmp, sizeof(tmp)); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), "read failed, ret=%d errno=%d", - fd, errno); - return LIBUSB_ERROR_IO; - } else if (r < sizeof(tmp)) { - usbi_err(DEVICE_CTX(dev), "short read %d/%d", r, sizeof(tmp)); - return LIBUSB_ERROR_IO; - } - - /* check bConfigurationValue */ - if (tmp[5] == config) - break; - - /* try the next descriptor */ - off = lseek(fd, 0 - sizeof(tmp), SEEK_CUR); - if (off < 0) - return LIBUSB_ERROR_IO; - - r = seek_to_next_config(DEVICE_CTX(dev), fd, 1); - if (r < 0) - return r; - } - - to_copy = (len < sizeof(tmp)) ? len : sizeof(tmp); - memcpy(buffer, tmp, to_copy); - if (len > sizeof(tmp)) { - r = read(fd, buffer + sizeof(tmp), len - sizeof(tmp)); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), "read failed, ret=%d errno=%d", - fd, errno); - r = LIBUSB_ERROR_IO; - } else if (r == 0) { - usbi_dbg("device is unconfigured"); - r = LIBUSB_ERROR_NOT_FOUND; - } else if (r < len - sizeof(tmp)) { - usbi_err(DEVICE_CTX(dev), "short read %d/%d", r, len); - r = LIBUSB_ERROR_IO; - } - } else { - r = 0; - } - - close(fd); - return r; -} - -static int op_get_active_config_descriptor(struct libusb_device *dev, - unsigned char *buffer, size_t len, int *host_endian) -{ - if (sysfs_has_descriptors) { - return sysfs_get_active_config_descriptor(dev, buffer, len); - } else { - return usbfs_get_active_config_descriptor(dev, buffer, len); - } -} - -/* takes a usbfs fd, attempts to find the requested config and copy a certain - * amount of it into an output buffer. */ -static int get_config_descriptor(struct libusb_context *ctx, int fd, - uint8_t config_index, unsigned char *buffer, size_t len) -{ - off_t off; - ssize_t r; - - off = lseek(fd, DEVICE_DESC_LENGTH, SEEK_SET); - if (off < 0) { - usbi_err(ctx, "seek failed ret=%d errno=%d", off, errno); - return LIBUSB_ERROR_IO; - } - - /* might need to skip some configuration descriptors to reach the - * requested configuration */ - while (config_index > 0) { - r = seek_to_next_config(ctx, fd, 0); - if (r < 0) - return r; - config_index--; - } - - /* read the rest of the descriptor */ - r = read(fd, buffer, len); - if (r < 0) { - usbi_err(ctx, "read failed ret=%d errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } else if (r < len) { - usbi_err(ctx, "short output read %d/%d", r, len); - return LIBUSB_ERROR_IO; - } - - return 0; -} - -static int op_get_config_descriptor(struct libusb_device *dev, - uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) -{ - char filename[PATH_MAX]; - int fd; - int r; - - /* always read from usbfs: sysfs only has the active descriptor - * this will involve waking the device up, but oh well! */ - - /* FIXME: the above is no longer true, new kernels have all descriptors - * in the descriptors file. but its kinda hard to detect if the kernel - * is sufficiently new. */ - - __get_usbfs_path(dev, filename); - fd = open(filename, O_RDONLY); - if (fd < 0) { - usbi_err(DEVICE_CTX(dev), - "open '%s' failed, ret=%d errno=%d", filename, fd, errno); - return LIBUSB_ERROR_IO; - } - - r = get_config_descriptor(DEVICE_CTX(dev), fd, config_index, buffer, len); - close(fd); - return r; -} - -/* cache the active config descriptor in memory. a value of -1 means that - * we aren't sure which one is active, so just assume the first one. - * only for usbfs. */ -static int cache_active_config(struct libusb_device *dev, int fd, - int active_config) -{ - struct linux_device_priv *priv = __device_priv(dev); - struct libusb_config_descriptor config; - unsigned char tmp[8]; - unsigned char *buf; - int idx; - int r; - - if (active_config == -1) { - idx = 0; - } else { - r = usbi_get_config_index_by_value(dev, active_config, &idx); - if (r < 0) - return r; - if (idx == -1) - return LIBUSB_ERROR_NOT_FOUND; - } - - r = get_config_descriptor(DEVICE_CTX(dev), fd, idx, tmp, sizeof(tmp)); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), "first read error %d", r); - return r; - } - - usbi_parse_descriptor(tmp, "bbw", &config, 0); - buf = malloc(config.wTotalLength); - if (!buf) - return LIBUSB_ERROR_NO_MEM; - - r = get_config_descriptor(DEVICE_CTX(dev), fd, idx, buf, - config.wTotalLength); - if (r < 0) { - free(buf); - return r; - } - - if (priv->config_descriptor) - free(priv->config_descriptor); - priv->config_descriptor = buf; - return 0; -} - -/* send a control message to retrieve active configuration */ -static int usbfs_get_active_config(struct libusb_device *dev, int fd) -{ - unsigned char active_config = 0; - int r; - - struct usbfs_ctrltransfer ctrl = { - .bmRequestType = LIBUSB_ENDPOINT_IN, - .bRequest = LIBUSB_REQUEST_GET_CONFIGURATION, - .wValue = 0, - .wIndex = 0, - .wLength = 1, - .timeout = 1000, - .data = &active_config - }; - - r = ioctl(fd, IOCTL_USBFS_CONTROL, &ctrl); - if (r < 0) { - if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - /* we hit this error path frequently with buggy devices :( */ - usbi_warn(DEVICE_CTX(dev), - "get_configuration failed ret=%d errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } - - return active_config; -} - -static int initialize_device(struct libusb_device *dev, uint8_t busnum, - uint8_t devaddr, const char *sysfs_dir) -{ - struct linux_device_priv *priv = __device_priv(dev); - unsigned char *dev_buf; - char path[PATH_MAX]; - int fd; - int active_config = 0; - int device_configured = 1; - ssize_t r; - - dev->bus_number = busnum; - dev->device_address = devaddr; - - if (sysfs_dir) { - priv->sysfs_dir = malloc(strlen(sysfs_dir) + 1); - if (!priv->sysfs_dir) - return LIBUSB_ERROR_NO_MEM; - strcpy(priv->sysfs_dir, sysfs_dir); - } - - if (sysfs_has_descriptors) - return 0; - - /* cache device descriptor in memory so that we can retrieve it later - * without waking the device up (op_get_device_descriptor) */ - - priv->dev_descriptor = NULL; - priv->config_descriptor = NULL; - - if (sysfs_can_relate_devices) { - int tmp = sysfs_get_active_config(dev, &active_config); - if (tmp < 0) - return tmp; - if (active_config == -1) - device_configured = 0; - } - - __get_usbfs_path(dev, path); - fd = open(path, O_RDWR); - if (fd < 0 && errno == EACCES) { - fd = open(path, O_RDONLY); - /* if we only have read-only access to the device, we cannot - * send a control message to determine the active config. just - * assume the first one is active. */ - active_config = -1; - } - - if (fd < 0) { - usbi_err(DEVICE_CTX(dev), "open failed, ret=%d errno=%d", fd, errno); - return LIBUSB_ERROR_IO; - } - - if (!sysfs_can_relate_devices) { - if (active_config == -1) { - /* if we only have read-only access to the device, we cannot - * send a control message to determine the active config. just - * assume the first one is active. */ - usbi_warn(DEVICE_CTX(dev), "access to %s is read-only; cannot " - "determine active configuration descriptor", path); - } else { - active_config = usbfs_get_active_config(dev, fd); - if (active_config == LIBUSB_ERROR_IO) { - /* buggy devices sometimes fail to report their active config. - * assume unconfigured and continue the probing */ - usbi_warn(DEVICE_CTX(dev), "couldn't query active " - "configuration, assumung unconfigured"); - device_configured = 0; - } else if (active_config < 0) { - close(fd); - return active_config; - } else if (active_config == 0) { - /* some buggy devices have a configuration 0, but we're - * reaching into the corner of a corner case here, so let's - * not support buggy devices in these circumstances. - * stick to the specs: a configuration value of 0 means - * unconfigured. */ - usbi_dbg("active cfg 0? assuming unconfigured device"); - device_configured = 0; - } - } - } - - dev_buf = malloc(DEVICE_DESC_LENGTH); - if (!dev_buf) { - close(fd); - return LIBUSB_ERROR_NO_MEM; - } - - r = read(fd, dev_buf, DEVICE_DESC_LENGTH); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), - "read descriptor failed ret=%d errno=%d", fd, errno); - free(dev_buf); - close(fd); - return LIBUSB_ERROR_IO; - } else if (r < DEVICE_DESC_LENGTH) { - usbi_err(DEVICE_CTX(dev), "short descriptor read (%d)", r); - free(dev_buf); - close(fd); - return LIBUSB_ERROR_IO; - } - - /* bit of a hack: set num_configurations now because cache_active_config() - * calls usbi_get_config_index_by_value() which uses it */ - dev->num_configurations = dev_buf[DEVICE_DESC_LENGTH - 1]; - - if (device_configured) { - r = cache_active_config(dev, fd, active_config); - if (r < 0) { - close(fd); - free(dev_buf); - return r; - } - } - - close(fd); - priv->dev_descriptor = dev_buf; - return 0; -} - -static int enumerate_device(struct libusb_context *ctx, - struct discovered_devs **_discdevs, uint8_t busnum, uint8_t devaddr, - const char *sysfs_dir) -{ - struct discovered_devs *discdevs; - unsigned long session_id; - int need_unref = 0; - struct libusb_device *dev; - int r = 0; - - /* FIXME: session ID is not guaranteed unique as addresses can wrap and - * will be reused. instead we should add a simple sysfs attribute with - * a session ID. */ - session_id = busnum << 8 | devaddr; - usbi_dbg("busnum %d devaddr %d session_id %ld", busnum, devaddr, - session_id); - - dev = usbi_get_device_by_session_id(ctx, session_id); - if (dev) { - usbi_dbg("using existing device for %d/%d (session %ld)", - busnum, devaddr, session_id); - } else { - usbi_dbg("allocating new device for %d/%d (session %ld)", - busnum, devaddr, session_id); - dev = usbi_alloc_device(ctx, session_id); - if (!dev) - return LIBUSB_ERROR_NO_MEM; - need_unref = 1; - r = initialize_device(dev, busnum, devaddr, sysfs_dir); - if (r < 0) - goto out; - r = usbi_sanitize_device(dev); - if (r < 0) - goto out; - } - - discdevs = discovered_devs_append(*_discdevs, dev); - if (!discdevs) - r = LIBUSB_ERROR_NO_MEM; - else - *_discdevs = discdevs; - -out: - if (need_unref) - libusb_unref_device(dev); - return r; -} - -/* open a bus directory and adds all discovered devices to discdevs. on - * failure (non-zero return) the pre-existing discdevs should be destroyed - * (and devices freed). on success, the new discdevs pointer should be used - * as it may have been moved. */ -static int usbfs_scan_busdir(struct libusb_context *ctx, - struct discovered_devs **_discdevs, uint8_t busnum) -{ - DIR *dir; - char dirpath[PATH_MAX]; - struct dirent *entry; - struct discovered_devs *discdevs = *_discdevs; - int r = 0; - - snprintf(dirpath, PATH_MAX, "%s/%03d", usbfs_path, busnum); - usbi_dbg("%s", dirpath); - dir = opendir(dirpath); - if (!dir) { - usbi_err(ctx, "opendir '%s' failed, errno=%d", dirpath, errno); - /* FIXME: should handle valid race conditions like hub unplugged - * during directory iteration - this is not an error */ - return LIBUSB_ERROR_IO; - } - - while ((entry = readdir(dir))) { - int devaddr; - - if (entry->d_name[0] == '.') - continue; - - devaddr = atoi(entry->d_name); - if (devaddr == 0) { - usbi_dbg("unknown dir entry %s", entry->d_name); - continue; - } - - r = enumerate_device(ctx, &discdevs, busnum, (uint8_t) devaddr, NULL); - if (r < 0) - goto out; - } - - *_discdevs = discdevs; -out: - closedir(dir); - return r; -} - -static int usbfs_get_device_list(struct libusb_context *ctx, - struct discovered_devs **_discdevs) -{ - struct dirent *entry; - DIR *buses = opendir(usbfs_path); - struct discovered_devs *discdevs = *_discdevs; - int r = 0; - - if (!buses) { - usbi_err(ctx, "opendir buses failed errno=%d", errno); - return LIBUSB_ERROR_IO; - } - - while ((entry = readdir(buses))) { - struct discovered_devs *discdevs_new = discdevs; - int busnum; - - if (entry->d_name[0] == '.') - continue; - - busnum = atoi(entry->d_name); - if (busnum == 0) { - usbi_dbg("unknown dir entry %s", entry->d_name); - continue; - } - - r = usbfs_scan_busdir(ctx, &discdevs_new, busnum); - if (r < 0) - goto out; - discdevs = discdevs_new; - } - -out: - closedir(buses); - *_discdevs = discdevs; - return r; - -} - -static int sysfs_scan_device(struct libusb_context *ctx, - struct discovered_devs **_discdevs, const char *devname, - int *usbfs_fallback) -{ - int r; - FILE *fd; - char filename[PATH_MAX]; - int busnum; - int devaddr; - - usbi_dbg("scan %s", devname); - - /* determine descriptors presence ahead of time, we need to know this - * when we reach initialize_device */ - if (sysfs_has_descriptors == -1) { - struct stat statbuf; - - snprintf(filename, PATH_MAX, "%s/%s/descriptors", SYSFS_DEVICE_PATH, - devname); - r = stat(filename, &statbuf); - if (r == 0 && S_ISREG(statbuf.st_mode)) { - usbi_dbg("sysfs descriptors available"); - sysfs_has_descriptors = 1; - } else { - usbi_dbg("sysfs descriptors not available"); - sysfs_has_descriptors = 0; - } - } - - snprintf(filename, PATH_MAX, "%s/%s/busnum", SYSFS_DEVICE_PATH, devname); - fd = fopen(filename, "r"); - if (!fd) { - if (errno == ENOENT) { - usbi_dbg("busnum not found, cannot relate sysfs to usbfs, " - "falling back on pure usbfs"); - sysfs_can_relate_devices = 0; - *usbfs_fallback = 1; - return LIBUSB_ERROR_OTHER; - } - usbi_err(ctx, "open busnum failed, errno=%d", errno); - return LIBUSB_ERROR_IO; - } - - sysfs_can_relate_devices = 1; - - r = fscanf(fd, "%d", &busnum); - fclose(fd); - if (r != 1) { - usbi_err(ctx, "fscanf busnum returned %d, errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } - - snprintf(filename, PATH_MAX, "%s/%s/devnum", SYSFS_DEVICE_PATH, devname); - fd = fopen(filename, "r"); - if (!fd) { - usbi_err(ctx, "open devnum failed, errno=%d", errno); - return LIBUSB_ERROR_IO; - } - - r = fscanf(fd, "%d", &devaddr); - fclose(fd); - if (r != 1) { - usbi_err(ctx, "fscanf devnum returned %d, errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } - - usbi_dbg("bus=%d dev=%d", busnum, devaddr); - if (busnum > 255 || devaddr > 255) - return LIBUSB_ERROR_INVALID_PARAM; - - return enumerate_device(ctx, _discdevs, busnum & 0xff, devaddr & 0xff, - devname); -} - -static int sysfs_get_device_list(struct libusb_context *ctx, - struct discovered_devs **_discdevs, int *usbfs_fallback) -{ - struct discovered_devs *discdevs = *_discdevs; - DIR *devices = opendir(SYSFS_DEVICE_PATH); - struct dirent *entry; - int r = 0; - - if (!devices) { - usbi_err(ctx, "opendir devices failed errno=%d", errno); - return LIBUSB_ERROR_IO; - } - - while ((entry = readdir(devices))) { - struct discovered_devs *discdevs_new = discdevs; - - if ((!isdigit(entry->d_name[0]) && strncmp(entry->d_name, "usb", 3)) - || strchr(entry->d_name, ':')) - continue; - - r = sysfs_scan_device(ctx, &discdevs_new, entry->d_name, - usbfs_fallback); - if (r < 0) - goto out; - discdevs = discdevs_new; - } - -out: - closedir(devices); - *_discdevs = discdevs; - return r; -} - -static int op_get_device_list(struct libusb_context *ctx, - struct discovered_devs **_discdevs) -{ - /* we can retrieve device list and descriptors from sysfs or usbfs. - * sysfs is preferable, because if we use usbfs we end up resuming - * any autosuspended USB devices. however, sysfs is not available - * everywhere, so we need a usbfs fallback too. - * - * as described in the "sysfs vs usbfs" comment, sometimes we have - * sysfs but not enough information to relate sysfs devices to usbfs - * nodes. the usbfs_fallback variable is used to indicate that we should - * fall back on usbfs. - */ - if (sysfs_can_relate_devices != 0) { - int usbfs_fallback = 0; - int r = sysfs_get_device_list(ctx, _discdevs, &usbfs_fallback); - if (!usbfs_fallback) - return r; - } - - return usbfs_get_device_list(ctx, _discdevs); -} - -static int op_open(struct libusb_device_handle *handle) -{ - struct linux_device_handle_priv *hpriv = __device_handle_priv(handle); - char filename[PATH_MAX]; - - __get_usbfs_path(handle->dev, filename); - hpriv->fd = open(filename, O_RDWR); - if (hpriv->fd < 0) { - if (errno == EACCES) { - usbi_err(HANDLE_CTX(handle), "libusb couldn't open USB device %s: " - "Permission denied.", filename); - usbi_err(HANDLE_CTX(handle), - "libusb requires write access to USB device nodes."); - return LIBUSB_ERROR_ACCESS; - } else if (errno == ENOENT) { - return LIBUSB_ERROR_NO_DEVICE; - } else { - usbi_err(HANDLE_CTX(handle), - "open failed, code %d errno %d", hpriv->fd, errno); - return LIBUSB_ERROR_IO; - } - } - - return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT); -} - -static void op_close(struct libusb_device_handle *dev_handle) -{ - int fd = __device_handle_priv(dev_handle)->fd; - usbi_remove_pollfd(HANDLE_CTX(dev_handle), fd); - close(fd); -} - -static int op_get_configuration(struct libusb_device_handle *handle, - int *config) -{ - int r; - if (sysfs_can_relate_devices != 1) - return LIBUSB_ERROR_NOT_SUPPORTED; - - r = sysfs_get_active_config(handle->dev, config); - if (*config == -1) - *config = 0; - - return 0; -} - -static int op_set_configuration(struct libusb_device_handle *handle, int config) -{ - struct linux_device_priv *priv = __device_priv(handle->dev); - int fd = __device_handle_priv(handle)->fd; - int r = ioctl(fd, IOCTL_USBFS_SETCONFIG, &config); - if (r) { - if (errno == EINVAL) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == EBUSY) - return LIBUSB_ERROR_BUSY; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), "failed, error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - if (!sysfs_has_descriptors) { - /* update our cached active config descriptor */ - if (config == -1) { - if (priv->config_descriptor) { - free(priv->config_descriptor); - priv->config_descriptor = NULL; - } - } else { - r = cache_active_config(handle->dev, fd, config); - if (r < 0) - usbi_warn(HANDLE_CTX(handle), - "failed to update cached config descriptor, error %d", r); - } - } - - return 0; -} - -static int op_claim_interface(struct libusb_device_handle *handle, int iface) -{ - int fd = __device_handle_priv(handle)->fd; - int r = ioctl(fd, IOCTL_USBFS_CLAIMINTF, &iface); - if (r) { - if (errno == ENOENT) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == EBUSY) - return LIBUSB_ERROR_BUSY; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "claim interface failed, error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - return 0; -} - -static int op_release_interface(struct libusb_device_handle *handle, int iface) -{ - int fd = __device_handle_priv(handle)->fd; - int r = ioctl(fd, IOCTL_USBFS_RELEASEINTF, &iface); - if (r) { - if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "release interface failed, error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - return 0; -} - -static int op_set_interface(struct libusb_device_handle *handle, int iface, - int altsetting) -{ - int fd = __device_handle_priv(handle)->fd; - struct usbfs_setinterface setintf; - int r; - - setintf.interface = iface; - setintf.altsetting = altsetting; - r = ioctl(fd, IOCTL_USBFS_SETINTF, &setintf); - if (r) { - if (errno == EINVAL) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "setintf failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - return 0; -} - -static int op_clear_halt(struct libusb_device_handle *handle, - unsigned char endpoint) -{ - int fd = __device_handle_priv(handle)->fd; - unsigned int _endpoint = endpoint; - int r = ioctl(fd, IOCTL_USBFS_CLEAR_HALT, &_endpoint); - if (r) { - if (errno == ENOENT) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "clear_halt failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - return 0; -} - -static int op_reset_device(struct libusb_device_handle *handle) -{ - int fd = __device_handle_priv(handle)->fd; - int r = ioctl(fd, IOCTL_USBFS_RESET, NULL); - if (r) { - if (errno == ENODEV) - return LIBUSB_ERROR_NOT_FOUND; - - usbi_err(HANDLE_CTX(handle), - "reset failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - return 0; -} - -static int op_kernel_driver_active(struct libusb_device_handle *handle, - int interface) -{ - int fd = __device_handle_priv(handle)->fd; - struct usbfs_getdriver getdrv; - int r; - - getdrv.interface = interface; - r = ioctl(fd, IOCTL_USBFS_GETDRIVER, &getdrv); - if (r) { - if (errno == ENODATA) - return 0; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "get driver failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - return 1; -} - -static int op_detach_kernel_driver(struct libusb_device_handle *handle, - int interface) -{ - int fd = __device_handle_priv(handle)->fd; - struct usbfs_ioctl command; - int r; - - command.ifno = interface; - command.ioctl_code = IOCTL_USBFS_DISCONNECT; - command.data = NULL; - - r = ioctl(fd, IOCTL_USBFS_IOCTL, &command); - if (r) { - if (errno == ENODATA) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == EINVAL) - return LIBUSB_ERROR_INVALID_PARAM; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "detach failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - return 0; -} - -static int op_attach_kernel_driver(struct libusb_device_handle *handle, - int interface) -{ - int fd = __device_handle_priv(handle)->fd; - struct usbfs_ioctl command; - int r; - - command.ifno = interface; - command.ioctl_code = IOCTL_USBFS_CONNECT; - command.data = NULL; - - r = ioctl(fd, IOCTL_USBFS_IOCTL, &command); - if (r < 0) { - if (errno == ENODATA) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == EINVAL) - return LIBUSB_ERROR_INVALID_PARAM; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - else if (errno == EBUSY) - return LIBUSB_ERROR_BUSY; - - usbi_err(HANDLE_CTX(handle), - "attach failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } else if (r == 0) { - return LIBUSB_ERROR_NOT_FOUND; - } - - return 0; -} - -static void op_destroy_device(struct libusb_device *dev) -{ - struct linux_device_priv *priv = __device_priv(dev); - if (!sysfs_has_descriptors) { - if (priv->dev_descriptor) - free(priv->dev_descriptor); - if (priv->config_descriptor) - free(priv->config_descriptor); - } - if (priv->sysfs_dir) - free(priv->sysfs_dir); -} - -static void free_iso_urbs(struct linux_transfer_priv *tpriv) -{ - int i; - for (i = 0; i < tpriv->num_urbs; i++) { - struct usbfs_urb *urb = tpriv->iso_urbs[i]; - if (!urb) - break; - free(urb); - } - - free(tpriv->iso_urbs); - tpriv->iso_urbs = NULL; -} - -static int submit_bulk_transfer(struct usbi_transfer *itransfer, - unsigned char urb_type) -{ - struct libusb_transfer *transfer = - __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct linux_device_handle_priv *dpriv = - __device_handle_priv(transfer->dev_handle); - struct usbfs_urb *urbs; - int is_out = (transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK) - == LIBUSB_ENDPOINT_OUT; - int r; - int i; - size_t alloc_size; - - if (tpriv->urbs) - return LIBUSB_ERROR_BUSY; - - /* usbfs places a 16kb limit on bulk URBs. we divide up larger requests - * into smaller units to meet such restriction, then fire off all the - * units at once. it would be simpler if we just fired one unit at a time, - * but there is a big performance gain through doing it this way. */ - int num_urbs = transfer->length / MAX_BULK_BUFFER_LENGTH; - int last_urb_partial = 0; - - if (transfer->length == 0) { - num_urbs = 1; - } else if ((transfer->length % MAX_BULK_BUFFER_LENGTH) > 0) { - last_urb_partial = 1; - num_urbs++; - } - usbi_dbg("need %d urbs for new transfer with length %d", num_urbs, - transfer->length); - alloc_size = num_urbs * sizeof(struct usbfs_urb); - urbs = malloc(alloc_size); - if (!urbs) - return LIBUSB_ERROR_NO_MEM; - memset(urbs, 0, alloc_size); - tpriv->urbs = urbs; - tpriv->num_urbs = num_urbs; - tpriv->num_retired = 0; - tpriv->reap_action = NORMAL; - tpriv->reap_status = LIBUSB_TRANSFER_COMPLETED; - - for (i = 0; i < num_urbs; i++) { - struct usbfs_urb *urb = &urbs[i]; - urb->usercontext = itransfer; - urb->type = urb_type; - urb->endpoint = transfer->endpoint; - urb->buffer = transfer->buffer + (i * MAX_BULK_BUFFER_LENGTH); - if (supports_flag_bulk_continuation && !is_out) - urb->flags = USBFS_URB_SHORT_NOT_OK; - if (i == num_urbs - 1 && last_urb_partial) - urb->buffer_length = transfer->length % MAX_BULK_BUFFER_LENGTH; - else if (transfer->length == 0) - urb->buffer_length = 0; - else - urb->buffer_length = MAX_BULK_BUFFER_LENGTH; - - if (i > 0 && supports_flag_bulk_continuation) - urb->flags |= USBFS_URB_BULK_CONTINUATION; - - r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb); - if (r < 0) { - int j; - - if (errno == ENODEV) { - r = LIBUSB_ERROR_NO_DEVICE; - } else { - usbi_err(TRANSFER_CTX(transfer), - "submiturb failed error %d errno=%d", r, errno); - r = LIBUSB_ERROR_IO; - } - - /* if the first URB submission fails, we can simply free up and - * return failure immediately. */ - if (i == 0) { - usbi_dbg("first URB failed, easy peasy"); - free(urbs); - tpriv->urbs = NULL; - return r; - } - - /* if it's not the first URB that failed, the situation is a bit - * tricky. we may need to discard all previous URBs. there are - * complications: - * - discarding is asynchronous - discarded urbs will be reaped - * later. the user must not have freed the transfer when the - * discarded URBs are reaped, otherwise libusb will be using - * freed memory. - * - the earlier URBs may have completed successfully and we do - * not want to throw away any data. - * - this URB failing may be no error; EREMOTEIO means that - * this transfer simply didn't need all the URBs we submitted - * so, we report that the transfer was submitted successfully and - * in case of error we discard all previous URBs. later when - * the final reap completes we can report error to the user, - * or success if an earlier URB was completed successfully. - */ - tpriv->reap_action = EREMOTEIO == errno ? COMPLETED_EARLY : SUBMIT_FAILED; - - /* The URBs we haven't submitted yet we count as already - * retired. */ - tpriv->num_retired += num_urbs - i; - - /* If we completed short then don't try to discard. */ - if (COMPLETED_EARLY == tpriv->reap_action) - return 0; - - for (j = 0; j < i; j++) { - int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, &urbs[j]); - if (tmp && errno != EINVAL) - usbi_warn(TRANSFER_CTX(transfer), - "unrecognised discard errno %d", errno); - } - - usbi_dbg("reporting successful submission but waiting for %d " - "discards before reporting error", i); - return 0; - } - } - - return 0; -} - -static int submit_iso_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = - __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct linux_device_handle_priv *dpriv = - __device_handle_priv(transfer->dev_handle); - struct usbfs_urb **urbs; - size_t alloc_size; - int num_packets = transfer->num_iso_packets; - int i; - int this_urb_len = 0; - int num_urbs = 1; - int packet_offset = 0; - unsigned int packet_len; - unsigned char *urb_buffer = transfer->buffer; - - if (tpriv->iso_urbs) - return LIBUSB_ERROR_BUSY; - - /* usbfs places a 32kb limit on iso URBs. we divide up larger requests - * into smaller units to meet such restriction, then fire off all the - * units at once. it would be simpler if we just fired one unit at a time, - * but there is a big performance gain through doing it this way. */ - - /* calculate how many URBs we need */ - for (i = 0; i < num_packets; i++) { - int space_remaining = MAX_ISO_BUFFER_LENGTH - this_urb_len; - packet_len = transfer->iso_packet_desc[i].length; - - if (packet_len > space_remaining) { - num_urbs++; - this_urb_len = packet_len; - } else { - this_urb_len += packet_len; - } - } - usbi_dbg("need %d 32k URBs for transfer", num_urbs); - - alloc_size = num_urbs * sizeof(*urbs); - urbs = malloc(alloc_size); - if (!urbs) - return LIBUSB_ERROR_NO_MEM; - memset(urbs, 0, alloc_size); - - tpriv->iso_urbs = urbs; - tpriv->num_urbs = num_urbs; - tpriv->num_retired = 0; - tpriv->reap_action = NORMAL; - tpriv->iso_packet_offset = 0; - - /* allocate + initialize each URB with the correct number of packets */ - for (i = 0; i < num_urbs; i++) { - struct usbfs_urb *urb; - int space_remaining_in_urb = MAX_ISO_BUFFER_LENGTH; - int urb_packet_offset = 0; - unsigned char *urb_buffer_orig = urb_buffer; - int j; - int k; - - /* swallow up all the packets we can fit into this URB */ - while (packet_offset < transfer->num_iso_packets) { - packet_len = transfer->iso_packet_desc[packet_offset].length; - if (packet_len <= space_remaining_in_urb) { - /* throw it in */ - urb_packet_offset++; - packet_offset++; - space_remaining_in_urb -= packet_len; - urb_buffer += packet_len; - } else { - /* it can't fit, save it for the next URB */ - break; - } - } - - alloc_size = sizeof(*urb) - + (urb_packet_offset * sizeof(struct usbfs_iso_packet_desc)); - urb = malloc(alloc_size); - if (!urb) { - free_iso_urbs(tpriv); - return LIBUSB_ERROR_NO_MEM; - } - memset(urb, 0, alloc_size); - urbs[i] = urb; - - /* populate packet lengths */ - for (j = 0, k = packet_offset - urb_packet_offset; - k < packet_offset; k++, j++) { - packet_len = transfer->iso_packet_desc[k].length; - urb->iso_frame_desc[j].length = packet_len; - } - - urb->usercontext = itransfer; - urb->type = USBFS_URB_TYPE_ISO; - /* FIXME: interface for non-ASAP data? */ - urb->flags = USBFS_URB_ISO_ASAP; - urb->endpoint = transfer->endpoint; - urb->number_of_packets = urb_packet_offset; - urb->buffer = urb_buffer_orig; - } - - /* submit URBs */ - for (i = 0; i < num_urbs; i++) { - int r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urbs[i]); - if (r < 0) { - int j; - - if (errno == ENODEV) { - r = LIBUSB_ERROR_NO_DEVICE; - } else { - usbi_err(TRANSFER_CTX(transfer), - "submiturb failed error %d errno=%d", r, errno); - r = LIBUSB_ERROR_IO; - } - - /* if the first URB submission fails, we can simply free up and - * return failure immediately. */ - if (i == 0) { - usbi_dbg("first URB failed, easy peasy"); - free_iso_urbs(tpriv); - return r; - } - - /* if it's not the first URB that failed, the situation is a bit - * tricky. we must discard all previous URBs. there are - * complications: - * - discarding is asynchronous - discarded urbs will be reaped - * later. the user must not have freed the transfer when the - * discarded URBs are reaped, otherwise libusb will be using - * freed memory. - * - the earlier URBs may have completed successfully and we do - * not want to throw away any data. - * so, in this case we discard all the previous URBs BUT we report - * that the transfer was submitted successfully. then later when - * the final discard completes we can report error to the user. - */ - tpriv->reap_action = SUBMIT_FAILED; - - /* The URBs we haven't submitted yet we count as already - * retired. */ - tpriv->num_retired = num_urbs - i; - for (j = 0; j < i; j++) { - int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, urbs[j]); - if (tmp && errno != EINVAL) - usbi_warn(TRANSFER_CTX(transfer), - "unrecognised discard errno %d", errno); - } - - usbi_dbg("reporting successful submission but waiting for %d " - "discards before reporting error", i); - return 0; - } - } - - return 0; -} - -static int submit_control_transfer(struct usbi_transfer *itransfer) -{ - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = - __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_device_handle_priv *dpriv = - __device_handle_priv(transfer->dev_handle); - struct usbfs_urb *urb; - int r; - - if (tpriv->urbs) - return LIBUSB_ERROR_BUSY; - - if (transfer->length - LIBUSB_CONTROL_SETUP_SIZE > MAX_CTRL_BUFFER_LENGTH) - return LIBUSB_ERROR_INVALID_PARAM; - - urb = malloc(sizeof(struct usbfs_urb)); - if (!urb) - return LIBUSB_ERROR_NO_MEM; - memset(urb, 0, sizeof(struct usbfs_urb)); - tpriv->urbs = urb; - tpriv->reap_action = NORMAL; - - urb->usercontext = itransfer; - urb->type = USBFS_URB_TYPE_CONTROL; - urb->endpoint = transfer->endpoint; - urb->buffer = transfer->buffer; - urb->buffer_length = transfer->length; - - r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb); - if (r < 0) { - free(urb); - tpriv->urbs = NULL; - if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(TRANSFER_CTX(transfer), - "submiturb failed error %d errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } - return 0; -} - -static int op_submit_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = - __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return submit_control_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - return submit_bulk_transfer(itransfer, USBFS_URB_TYPE_BULK); - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - return submit_bulk_transfer(itransfer, USBFS_URB_TYPE_INTERRUPT); - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return submit_iso_transfer(itransfer); - default: - usbi_err(TRANSFER_CTX(transfer), - "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static int cancel_control_transfer(struct usbi_transfer *itransfer) -{ - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = - __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_device_handle_priv *dpriv = - __device_handle_priv(transfer->dev_handle); - int r; - - if (!tpriv->urbs) - return LIBUSB_ERROR_NOT_FOUND; - - tpriv->reap_action = CANCELLED; - r = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, tpriv->urbs); - if(r) { - if (errno == EINVAL) { - usbi_dbg("URB not found --> assuming ready to be reaped"); - return 0; - } else { - usbi_err(TRANSFER_CTX(transfer), - "unrecognised DISCARD code %d", errno); - return LIBUSB_ERROR_OTHER; - } - } - - return 0; -} - -static int cancel_bulk_transfer(struct usbi_transfer *itransfer) -{ - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = - __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_device_handle_priv *dpriv = - __device_handle_priv(transfer->dev_handle); - int i; - - if (!tpriv->urbs) - return LIBUSB_ERROR_NOT_FOUND; - - if (tpriv->reap_action != ERROR) - tpriv->reap_action = CANCELLED; - - for (i = 0; i < tpriv->num_urbs; i++) { - int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, &tpriv->urbs[i]); - if (tmp && errno != EINVAL) - usbi_warn(TRANSFER_CTX(transfer), - "unrecognised discard errno %d", errno); - } - return 0; -} - -static int cancel_iso_transfer(struct usbi_transfer *itransfer) -{ - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = - __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_device_handle_priv *dpriv = - __device_handle_priv(transfer->dev_handle); - int i; - - if (!tpriv->iso_urbs) - return LIBUSB_ERROR_NOT_FOUND; - - tpriv->reap_action = CANCELLED; - for (i = 0; i < tpriv->num_urbs; i++) { - int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, tpriv->iso_urbs[i]); - if (tmp && errno != EINVAL) - usbi_warn(TRANSFER_CTX(transfer), - "unrecognised discard errno %d", errno); - } - return 0; -} - -static int op_cancel_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = - __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return cancel_control_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - return cancel_bulk_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return cancel_iso_transfer(itransfer); - default: - usbi_err(TRANSFER_CTX(transfer), - "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static void op_clear_transfer_priv(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = - __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - free(tpriv->urbs); - tpriv->urbs = NULL; - break; - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - free_iso_urbs(tpriv); - break; - default: - usbi_err(TRANSFER_CTX(transfer), - "unknown endpoint type %d", transfer->type); - } -} - -static int handle_bulk_completion(struct usbi_transfer *itransfer, - struct usbfs_urb *urb) -{ - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_device_handle_priv *dpriv = __device_handle_priv(transfer->dev_handle); - int urb_idx = urb - tpriv->urbs; - - usbi_mutex_lock(&itransfer->lock); - usbi_dbg("handling completion status %d of bulk urb %d/%d", urb->status, - urb_idx + 1, tpriv->num_urbs); - - tpriv->num_retired++; - - if (tpriv->reap_action != NORMAL) { - /* cancelled, submit_fail, or completed early */ - usbi_dbg("abnormal reap: urb status %d", urb->status); - - /* even though we're in the process of cancelling, it's possible that - * we may receive some data in these URBs that we don't want to lose. - * examples: - * 1. while the kernel is cancelling all the packets that make up an - * URB, a few of them might complete. so we get back a successful - * cancellation *and* some data. - * 2. we receive a short URB which marks the early completion condition, - * so we start cancelling the remaining URBs. however, we're too - * slow and another URB completes (or at least completes partially). - * - * When this happens, our objectives are not to lose any "surplus" data, - * and also to stick it at the end of the previously-received data - * (closing any holes), so that libusb reports the total amount of - * transferred data and presents it in a contiguous chunk. - */ - if (urb->actual_length > 0) { - unsigned char *target = transfer->buffer + itransfer->transferred; - usbi_dbg("received %d bytes of surplus data", urb->actual_length); - if (urb->buffer != target) { - usbi_dbg("moving surplus data from offset %d to offset %d", - (unsigned char *) urb->buffer - transfer->buffer, - target - transfer->buffer); - memmove(target, urb->buffer, urb->actual_length); - } - itransfer->transferred += urb->actual_length; - } - - if (tpriv->num_retired == tpriv->num_urbs) { - usbi_dbg("abnormal reap: last URB handled, reporting"); - if (tpriv->reap_action != COMPLETED_EARLY && - tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED) - tpriv->reap_status = LIBUSB_TRANSFER_ERROR; - goto completed; - } - goto out_unlock; - } - - if (urb->status == 0 || urb->status == -EREMOTEIO || - (urb->status == -EOVERFLOW && urb->actual_length > 0)) - itransfer->transferred += urb->actual_length; - - - switch (urb->status) { - case 0: - break; - case -EREMOTEIO: /* short transfer */ - break; - case -EPIPE: - usbi_dbg("detected endpoint stall"); - if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED) - tpriv->reap_status = LIBUSB_TRANSFER_STALL; - goto cancel_remaining; - case -EOVERFLOW: - /* overflow can only ever occur in the last urb */ - usbi_dbg("overflow, actual_length=%d", urb->actual_length); - if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED) - tpriv->reap_status = LIBUSB_TRANSFER_OVERFLOW; - goto completed; - case -ETIME: - case -EPROTO: - case -EILSEQ: - /* These can happen on *any* urb of a multi-urb transfer, so - * save a status and tear down rest of the transfer */ - usbi_dbg("low level error %d", urb->status); - tpriv->reap_action = ERROR; - if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED) - tpriv->reap_status = LIBUSB_TRANSFER_ERROR; - goto cancel_remaining; - default: - usbi_warn(ITRANSFER_CTX(itransfer), - "unrecognised urb status %d", urb->status); - if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED) - tpriv->reap_status = LIBUSB_TRANSFER_ERROR; - goto cancel_remaining; - } - - /* if we're the last urb or we got less data than requested then we're - * done */ - if (urb_idx == tpriv->num_urbs - 1) { - usbi_dbg("last URB in transfer --> complete!"); - goto completed; - } else if (urb->actual_length < urb->buffer_length) { - usbi_dbg("short transfer %d/%d --> complete!", - urb->actual_length, urb->buffer_length); - if (tpriv->reap_action == NORMAL) - tpriv->reap_action = COMPLETED_EARLY; - } else - goto out_unlock; - -cancel_remaining: - if (tpriv->num_retired == tpriv->num_urbs) /* nothing to cancel */ - goto completed; - - /* cancel remaining urbs and wait for their completion before - * reporting results */ - while (++urb_idx < tpriv->num_urbs) { - /* remaining URBs with continuation flag are - * automatically cancelled by the kernel */ - if (tpriv->urbs[urb_idx].flags & USBFS_URB_BULK_CONTINUATION) - continue; - int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, &tpriv->urbs[urb_idx]); - if (tmp && errno != EINVAL) - usbi_warn(TRANSFER_CTX(transfer), - "unrecognised discard errno %d", errno); - } - -out_unlock: - usbi_mutex_unlock(&itransfer->lock); - return 0; - -completed: - free(tpriv->urbs); - tpriv->urbs = NULL; - usbi_mutex_unlock(&itransfer->lock); - return CANCELLED == tpriv->reap_action ? - usbi_handle_transfer_cancellation(itransfer) : - usbi_handle_transfer_completion(itransfer, tpriv->reap_status); -} - -static int handle_iso_completion(struct usbi_transfer *itransfer, - struct usbfs_urb *urb) -{ - struct libusb_transfer *transfer = - __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - int num_urbs = tpriv->num_urbs; - int urb_idx = 0; - int i; - - usbi_mutex_lock(&itransfer->lock); - for (i = 0; i < num_urbs; i++) { - if (urb == tpriv->iso_urbs[i]) { - urb_idx = i + 1; - break; - } - } - if (urb_idx == 0) { - usbi_err(TRANSFER_CTX(transfer), "could not locate urb!"); - usbi_mutex_unlock(&itransfer->lock); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("handling completion status %d of iso urb %d/%d", urb->status, - urb_idx, num_urbs); - - if (urb->status == 0) { - /* copy isochronous results back in */ - - for (i = 0; i < urb->number_of_packets; i++) { - struct usbfs_iso_packet_desc *urb_desc = &urb->iso_frame_desc[i]; - struct libusb_iso_packet_descriptor *lib_desc = - &transfer->iso_packet_desc[tpriv->iso_packet_offset++]; - lib_desc->status = urb_desc->status; - lib_desc->actual_length = urb_desc->actual_length; - } - } - - tpriv->num_retired++; - - if (tpriv->reap_action != NORMAL) { /* cancelled or submit_fail */ - usbi_dbg("CANCEL: urb status %d", urb->status); - - if (tpriv->num_retired == num_urbs) { - usbi_dbg("CANCEL: last URB handled, reporting"); - free_iso_urbs(tpriv); - if (tpriv->reap_action == CANCELLED) { - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_cancellation(itransfer); - } else { - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_completion(itransfer, - LIBUSB_TRANSFER_ERROR); - } - } - goto out; - } - - switch (urb->status) { - case 0: - break; - case -ETIME: - case -EPROTO: - case -EILSEQ: - usbi_dbg("low-level USB error %d", urb->status); - break; - default: - usbi_warn(TRANSFER_CTX(transfer), - "unrecognised urb status %d", urb->status); - break; - } - - /* if we're the last urb or we got less data than requested then we're - * done */ - if (urb_idx == num_urbs) { - usbi_dbg("last URB in transfer --> complete!"); - free_iso_urbs(tpriv); - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED); - } - -out: - usbi_mutex_unlock(&itransfer->lock); - return 0; -} - -static int handle_control_completion(struct usbi_transfer *itransfer, - struct usbfs_urb *urb) -{ - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - int status; - - usbi_mutex_lock(&itransfer->lock); - usbi_dbg("handling completion status %d", urb->status); - - if (urb->status == 0) - itransfer->transferred += urb->actual_length; - - if (tpriv->reap_action == CANCELLED) { - if (urb->status != 0 && urb->status != -ENOENT) - usbi_warn(ITRANSFER_CTX(itransfer), - "cancel: unrecognised urb status %d", urb->status); - free(tpriv->urbs); - tpriv->urbs = NULL; - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_cancellation(itransfer); - } - - switch (urb->status) { - case 0: - itransfer->transferred = urb->actual_length; - status = LIBUSB_TRANSFER_COMPLETED; - break; - case -EPIPE: - usbi_dbg("unsupported control request"); - status = LIBUSB_TRANSFER_STALL; - break; - case -ETIME: - case -EPROTO: - case -EILSEQ: - usbi_dbg("low-level bus error occurred"); - status = LIBUSB_TRANSFER_ERROR; - break; - default: - usbi_warn(ITRANSFER_CTX(itransfer), - "unrecognised urb status %d", urb->status); - status = LIBUSB_TRANSFER_ERROR; - break; - } - - free(tpriv->urbs); - tpriv->urbs = NULL; - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_completion(itransfer, status); -} - -static int reap_for_handle(struct libusb_device_handle *handle) -{ - struct linux_device_handle_priv *hpriv = __device_handle_priv(handle); - int r; - struct usbfs_urb *urb; - struct usbi_transfer *itransfer; - struct libusb_transfer *transfer; - - r = ioctl(hpriv->fd, IOCTL_USBFS_REAPURBNDELAY, &urb); - if (r == -1 && errno == EAGAIN) - return 1; - if (r < 0) { - if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), "reap failed error %d errno=%d", - r, errno); - return LIBUSB_ERROR_IO; - } - - itransfer = urb->usercontext; - transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - usbi_dbg("urb type=%d status=%d transferred=%d", urb->type, urb->status, - urb->actual_length); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return handle_iso_completion(itransfer, urb); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - return handle_bulk_completion(itransfer, urb); - case LIBUSB_TRANSFER_TYPE_CONTROL: - return handle_control_completion(itransfer, urb); - default: - usbi_err(HANDLE_CTX(handle), "unrecognised endpoint type %x", - transfer->type); - return LIBUSB_ERROR_OTHER; - } -} - -static int op_handle_events(struct libusb_context *ctx, - struct pollfd *fds, nfds_t nfds, int num_ready) -{ - int r; - int i = 0; - - usbi_mutex_lock(&ctx->open_devs_lock); - for (i = 0; i < nfds && num_ready > 0; i++) { - struct pollfd *pollfd = &fds[i]; - struct libusb_device_handle *handle; - struct linux_device_handle_priv *hpriv = NULL; - - if (!pollfd->revents) - continue; - - num_ready--; - list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) { - hpriv = __device_handle_priv(handle); - if (hpriv->fd == pollfd->fd) - break; - } - - if (pollfd->revents & POLLERR) { - usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fd); - usbi_handle_disconnect(handle); - continue; - } - - r = reap_for_handle(handle); - if (r == 1 || r == LIBUSB_ERROR_NO_DEVICE) - continue; - else if (r < 0) - goto out; - } - - r = 0; -out: - usbi_mutex_unlock(&ctx->open_devs_lock); - return r; -} - -static int op_clock_gettime(int clk_id, struct timespec *tp) -{ - switch (clk_id) { - case USBI_CLOCK_MONOTONIC: - return clock_gettime(monotonic_clkid, tp); - case USBI_CLOCK_REALTIME: - return clock_gettime(CLOCK_REALTIME, tp); - default: - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -#ifdef USBI_TIMERFD_AVAILABLE -static clockid_t op_get_timerfd_clockid(void) -{ - return monotonic_clkid; - -} -#endif - -const struct usbi_os_backend linux_usbfs_backend = { - .name = "Linux usbfs", - .init = op_init, - .exit = NULL, - .get_device_list = op_get_device_list, - .get_device_descriptor = op_get_device_descriptor, - .get_active_config_descriptor = op_get_active_config_descriptor, - .get_config_descriptor = op_get_config_descriptor, - - .open = op_open, - .close = op_close, - .get_configuration = op_get_configuration, - .set_configuration = op_set_configuration, - .claim_interface = op_claim_interface, - .release_interface = op_release_interface, - - .set_interface_altsetting = op_set_interface, - .clear_halt = op_clear_halt, - .reset_device = op_reset_device, - - .kernel_driver_active = op_kernel_driver_active, - .detach_kernel_driver = op_detach_kernel_driver, - .attach_kernel_driver = op_attach_kernel_driver, - - .destroy_device = op_destroy_device, - - .submit_transfer = op_submit_transfer, - .cancel_transfer = op_cancel_transfer, - .clear_transfer_priv = op_clear_transfer_priv, - - .handle_events = op_handle_events, - - .clock_gettime = op_clock_gettime, - -#ifdef USBI_TIMERFD_AVAILABLE - .get_timerfd_clockid = op_get_timerfd_clockid, -#endif - - .device_priv_size = sizeof(struct linux_device_priv), - .device_handle_priv_size = sizeof(struct linux_device_handle_priv), - .transfer_priv_size = sizeof(struct linux_transfer_priv), - .add_iso_packet_size = 0, -}; - diff --git a/include/libusb-1.0/os/linux_usbfs.h b/include/libusb-1.0/os/linux_usbfs.h deleted file mode 100644 index bd02edc..0000000 --- a/include/libusb-1.0/os/linux_usbfs.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * usbfs header structures - * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> - * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LIBUSB_USBFS_H__ -#define __LIBUSB_USBFS_H__ - -#define SYSFS_DEVICE_PATH "/sys/bus/usb/devices" - -struct usbfs_ctrltransfer { - /* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */ - uint8_t bmRequestType; - uint8_t bRequest; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; - - uint32_t timeout; /* in milliseconds */ - - /* pointer to data */ - void *data; -}; - -struct usbfs_bulktransfer { - /* keep in sync with usbdevice_fs.h:usbdevfs_bulktransfer */ - unsigned int ep; - unsigned int len; - unsigned int timeout; /* in milliseconds */ - - /* pointer to data */ - void *data; -}; - -struct usbfs_setinterface { - /* keep in sync with usbdevice_fs.h:usbdevfs_setinterface */ - unsigned int interface; - unsigned int altsetting; -}; - -#define USBFS_MAXDRIVERNAME 255 - -struct usbfs_getdriver { - unsigned int interface; - char driver[USBFS_MAXDRIVERNAME + 1]; -}; - -#define USBFS_URB_SHORT_NOT_OK 0x01 -#define USBFS_URB_ISO_ASAP 0x02 -#define USBFS_URB_BULK_CONTINUATION 0x04 -#define USBFS_URB_QUEUE_BULK 0x10 - -enum usbfs_urb_type { - USBFS_URB_TYPE_ISO = 0, - USBFS_URB_TYPE_INTERRUPT = 1, - USBFS_URB_TYPE_CONTROL = 2, - USBFS_URB_TYPE_BULK = 3, -}; - -struct usbfs_iso_packet_desc { - unsigned int length; - unsigned int actual_length; - unsigned int status; -}; - -#define MAX_ISO_BUFFER_LENGTH 32768 -#define MAX_BULK_BUFFER_LENGTH 16384 -#define MAX_CTRL_BUFFER_LENGTH 4096 - -struct usbfs_urb { - unsigned char type; - unsigned char endpoint; - int status; - unsigned int flags; - void *buffer; - int buffer_length; - int actual_length; - int start_frame; - int number_of_packets; - int error_count; - unsigned int signr; - void *usercontext; - struct usbfs_iso_packet_desc iso_frame_desc[0]; -}; - -struct usbfs_connectinfo { - unsigned int devnum; - unsigned char slow; -}; - -struct usbfs_ioctl { - int ifno; /* interface 0..N ; negative numbers reserved */ - int ioctl_code; /* MUST encode size + direction of data so the - * macros in <asm/ioctl.h> give correct values */ - void *data; /* param buffer (in, or out) */ -}; - -struct usbfs_hub_portinfo { - unsigned char numports; - unsigned char port[127]; /* port to device num mapping */ -}; - -#define IOCTL_USBFS_CONTROL _IOWR('U', 0, struct usbfs_ctrltransfer) -#define IOCTL_USBFS_BULK _IOWR('U', 2, struct usbfs_bulktransfer) -#define IOCTL_USBFS_RESETEP _IOR('U', 3, unsigned int) -#define IOCTL_USBFS_SETINTF _IOR('U', 4, struct usbfs_setinterface) -#define IOCTL_USBFS_SETCONFIG _IOR('U', 5, unsigned int) -#define IOCTL_USBFS_GETDRIVER _IOW('U', 8, struct usbfs_getdriver) -#define IOCTL_USBFS_SUBMITURB _IOR('U', 10, struct usbfs_urb) -#define IOCTL_USBFS_DISCARDURB _IO('U', 11) -#define IOCTL_USBFS_REAPURB _IOW('U', 12, void *) -#define IOCTL_USBFS_REAPURBNDELAY _IOW('U', 13, void *) -#define IOCTL_USBFS_CLAIMINTF _IOR('U', 15, unsigned int) -#define IOCTL_USBFS_RELEASEINTF _IOR('U', 16, unsigned int) -#define IOCTL_USBFS_CONNECTINFO _IOW('U', 17, struct usbfs_connectinfo) -#define IOCTL_USBFS_IOCTL _IOWR('U', 18, struct usbfs_ioctl) -#define IOCTL_USBFS_HUB_PORTINFO _IOR('U', 19, struct usbfs_hub_portinfo) -#define IOCTL_USBFS_RESET _IO('U', 20) -#define IOCTL_USBFS_CLEAR_HALT _IOR('U', 21, unsigned int) -#define IOCTL_USBFS_DISCONNECT _IO('U', 22) -#define IOCTL_USBFS_CONNECT _IO('U', 23) - -#endif diff --git a/include/libusb-1.0/os/poll_posix.h b/include/libusb-1.0/os/poll_posix.h deleted file mode 100644 index 17298a5..0000000 --- a/include/libusb-1.0/os/poll_posix.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __LIBUSB_POLL_POSIX_H__ -#define __LIBUSB_POLL_POSIX_H__ - -#include <unistd.h> -#include <poll.h> -#define usbi_write write -#define usbi_read read -#define usbi_close close -#define usbi_pipe pipe -#define usbi_poll poll - -#endif /* __LIBUSB_POLL_POSIX_H__ */ diff --git a/include/libusb-1.0/os/poll_windows.c b/include/libusb-1.0/os/poll_windows.c deleted file mode 100644 index 9ae9895..0000000 --- a/include/libusb-1.0/os/poll_windows.c +++ /dev/null @@ -1,860 +0,0 @@ -/* - * poll_windows: poll compatibility wrapper for Windows - * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com> - * With contributions from Michael Plante, Orin Eman et al. - * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -/* - * poll() and pipe() Windows compatibility layer for libusb 1.0 - * - * The way this layer works is by using OVERLAPPED with async I/O transfers, as - * OVERLAPPED have an associated event which is flagged for I/O completion. - * - * For USB pollable async I/O, you would typically: - * - obtain a Windows HANDLE to a file or device that has been opened in - * OVERLAPPED mode - * - call usbi_create_fd with this handle to obtain a custom fd. - * Note that if you need simultaneous R/W access, you need to call create_fd - * twice, once in _O_RDONLY and once in _O_WRONLY mode to obtain 2 separate - * pollable fds - * - leave the core functions call the poll routine and flag POLLIN/POLLOUT - * - * The pipe pollable synchronous I/O works using the overlapped event associated - * with a fake pipe. The read/write functions are only meant to be used in that - * context. - */ -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <io.h> - -#include <libusbi.h> - -// Uncomment to debug the polling layer -//#define DEBUG_POLL_WINDOWS -#if defined(DEBUG_POLL_WINDOWS) -#define poll_dbg usbi_dbg -#else -// MSVC6 cannot use a variadic argument and non MSVC -// compilers produce warnings if parenthesis are ommitted. -#if defined(_MSC_VER) -#define poll_dbg -#else -#define poll_dbg(...) -#endif -#endif - -#if defined(_PREFAST_) -#pragma warning(disable:28719) -#endif - -#if defined(__CYGWIN__) -// cygwin produces a warning unless these prototypes are defined -extern int _close(int fd); -extern int _snprintf(char *buffer, size_t count, const char *format, ...); -extern int cygwin_attach_handle_to_fd(char *name, int fd, HANDLE handle, int bin, int access_mode); -// _open_osfhandle() is not available on cygwin, but we can emulate -// it for our needs with cygwin_attach_handle_to_fd() -static inline int _open_osfhandle(intptr_t osfhandle, int flags) -{ - int access_mode; - switch (flags) { - case _O_RDONLY: - access_mode = GENERIC_READ; - break; - case _O_WRONLY: - access_mode = GENERIC_WRITE; - break; - case _O_RDWR: - access_mode = GENERIC_READ|GENERIC_WRITE; - break; - default: - usbi_err(NULL, "unsupported access mode"); - return -1; - } - return cygwin_attach_handle_to_fd("/dev/null", -1, (HANDLE)osfhandle, -1, access_mode); -} -#endif - -#define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0) - -// public fd data -const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, RW_NONE}; -struct winfd poll_fd[MAX_FDS]; -// internal fd data -struct { - CRITICAL_SECTION mutex; // lock for fds - // Additional variables for XP CancelIoEx partial emulation - HANDLE original_handle; - DWORD thread_id; -} _poll_fd[MAX_FDS]; - -// globals -BOOLEAN is_polling_set = FALSE; -#if defined(DYNAMIC_FDS) -HANDLE fd_update = INVALID_HANDLE_VALUE; // event to notify poll of fd update -HANDLE new_fd[MAX_FDS]; // overlapped event handles for fds created since last poll -unsigned nb_new_fds = 0; // nb new fds created since last poll -usbi_mutex_t new_fd_mutex; // mutex required for the above -#endif -LONG pipe_number = 0; -static volatile LONG compat_spinlock = 0; - -// CancelIoEx, available on Vista and later only, provides the ability to cancel -// a single transfer (OVERLAPPED) when used. As it may not be part of any of the -// platform headers, we hook into the Kernel32 system DLL directly to seek it. -static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL; -#define CancelIoEx_Available (pCancelIoEx != NULL) -__inline BOOL cancel_io(int index) -{ - if ((index < 0) || (index >= MAX_FDS)) { - return FALSE; - } - - if ( (poll_fd[index].fd < 0) || (poll_fd[index].handle == INVALID_HANDLE_VALUE) - || (poll_fd[index].handle == 0) || (poll_fd[index].overlapped == NULL) ) { - return TRUE; - } - if (CancelIoEx_Available) { - return (*pCancelIoEx)(poll_fd[index].handle, poll_fd[index].overlapped); - } - if (_poll_fd[index].thread_id == GetCurrentThreadId()) { - return CancelIo(poll_fd[index].handle); - } - usbi_warn(NULL, "Unable to cancel I/O that was started from another thread"); - return FALSE; -} - -// Init -void init_polling(void) -{ - int i; - - while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { - SleepEx(0, TRUE); - } - if (!is_polling_set) { - pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED)) - GetProcAddress(GetModuleHandle("KERNEL32"), "CancelIoEx"); - usbi_dbg("Will use CancelIo%s for I/O cancellation", - CancelIoEx_Available?"Ex":""); - for (i=0; i<MAX_FDS; i++) { - poll_fd[i] = INVALID_WINFD; - _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; - _poll_fd[i].thread_id = 0; - InitializeCriticalSection(&_poll_fd[i].mutex); - } -#if defined(DYNAMIC_FDS) - // We need to create an update event so that poll is warned when there - // are new/deleted fds during a timeout wait operation - fd_update = CreateEvent(NULL, TRUE, FALSE, NULL); - if (fd_update == NULL) { - usbi_err(NULL, "unable to create update event"); - } - usbi_mutex_init(&new_fd_mutex, NULL); - nb_new_fds = 0; -#endif - is_polling_set = TRUE; - } - compat_spinlock = 0; -} - -// Internal function to retrieve the table index (and lock the fd mutex) -int _fd_to_index_and_lock(int fd) -{ - int i; - - if (fd <= 0) - return -1; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd == fd) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have changed before we got to critical - if (poll_fd[i].fd != fd) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - return i; - } - } - return -1; -} - -OVERLAPPED *create_overlapped(void) -{ - OVERLAPPED *overlapped = calloc(1, sizeof(OVERLAPPED)); - if (overlapped == NULL) { - return NULL; - } - overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if(overlapped->hEvent == NULL) { - free (overlapped); - return NULL; - } - return overlapped; -} - -void free_overlapped(OVERLAPPED *overlapped) -{ - if (overlapped == NULL) - return; - - if ( (overlapped->hEvent != 0) - && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) { - CloseHandle(overlapped->hEvent); - } - free(overlapped); -} - -void reset_overlapped(OVERLAPPED *overlapped) -{ - HANDLE event_handle; - if (overlapped == NULL) - return; - - event_handle = overlapped->hEvent; - if (event_handle != NULL) { - ResetEvent(event_handle); - } - memset(overlapped, 0, sizeof(OVERLAPPED)); - overlapped->hEvent = event_handle; -} - -void exit_polling(void) -{ - int i; - - while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { - SleepEx(0, TRUE); - } - if (is_polling_set) { - is_polling_set = FALSE; - - for (i=0; i<MAX_FDS; i++) { - // Cancel any async I/O (handle can be invalid) - cancel_io(i); - // If anything was pending on that I/O, it should be - // terminating, and we should be able to access the fd - // mutex lock before too long - EnterCriticalSection(&_poll_fd[i].mutex); - if ( (poll_fd[i].fd > 0) && (poll_fd[i].handle != INVALID_HANDLE_VALUE) && (poll_fd[i].handle != 0) - && (GetFileType(poll_fd[i].handle) == FILE_TYPE_UNKNOWN) ) { - _close(poll_fd[i].fd); - } - free_overlapped(poll_fd[i].overlapped); - if (!CancelIoEx_Available) { - // Close duplicate handle - if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) { - CloseHandle(poll_fd[i].handle); - } - } - poll_fd[i] = INVALID_WINFD; -#if defined(DYNAMIC_FDS) - usbi_mutex_destroy(&new_fd_mutex); - CloseHandle(fd_update); - fd_update = INVALID_HANDLE_VALUE; -#endif - LeaveCriticalSection(&_poll_fd[i].mutex); - DeleteCriticalSection(&_poll_fd[i].mutex); - } - } - compat_spinlock = 0; -} - -/* - * Create a fake pipe. - * As libusb only uses pipes for signaling, all we need from a pipe is an - * event. To that extent, we create a single wfd and overlapped as a means - * to access that event. - */ -int usbi_pipe(int filedes[2]) -{ - int i; - HANDLE handle; - OVERLAPPED* overlapped; - - CHECK_INIT_POLLING; - - overlapped = calloc(1, sizeof(OVERLAPPED)); - if (overlapped == NULL) { - return -1; - } - // The overlapped must have status pending for signaling to work in poll - overlapped->Internal = STATUS_PENDING; - overlapped->InternalHigh = 0; - - // Read end of the "pipe" - handle = CreateFileA("NUL", 0, 0, NULL, OPEN_EXISTING, 0, NULL); - if (handle == INVALID_HANDLE_VALUE) { - usbi_err(NULL, "could not create pipe: errcode %d", (int)GetLastError()); - goto out1; - } - filedes[0] = _open_osfhandle((intptr_t)handle, _O_RDONLY); - // We can use the same handle for both ends - filedes[1] = filedes[0]; - poll_dbg("pipe filedes = %d", filedes[0]); - - // Note: manual reset must be true (second param) as the reset occurs in read - overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if(!overlapped->hEvent) { - goto out2; - } - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd < 0) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been allocated before we got to critical - if (poll_fd[i].fd >= 0) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - - poll_fd[i].fd = filedes[0]; - poll_fd[i].handle = handle; - poll_fd[i].overlapped = overlapped; - // There's no polling on the write end, so we just use READ for our needs - poll_fd[i].rw = RW_READ; - _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; - LeaveCriticalSection(&_poll_fd[i].mutex); - return 0; - } - } - - CloseHandle(overlapped->hEvent); -out2: - CloseHandle(handle); -out1: - free(overlapped); - return -1; -} - -/* - * Create both an fd and an OVERLAPPED from an open Windows handle, so that - * it can be used with our polling function - * The handle MUST support overlapped transfers (usually requires CreateFile - * with FILE_FLAG_OVERLAPPED) - * Return a pollable file descriptor struct, or INVALID_WINFD on error - * - * Note that the fd returned by this function is a per-transfer fd, rather - * than a per-session fd and cannot be used for anything else but our - * custom functions (the fd itself points to the NUL: device) - * if you plan to do R/W on the same handle, you MUST create 2 fds: one for - * read and one for write. Using a single R/W fd is unsupported and will - * produce unexpected results - */ -struct winfd usbi_create_fd(HANDLE handle, int access_mode) -{ - int i, fd; - struct winfd wfd = INVALID_WINFD; - OVERLAPPED* overlapped = NULL; - - CHECK_INIT_POLLING; - - if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) { - return INVALID_WINFD; - } - - if ((access_mode != _O_RDONLY) && (access_mode != _O_WRONLY)) { - usbi_warn(NULL, "only one of _O_RDONLY or _O_WRONLY are supported.\n" - "If you want to poll for R/W simultaneously, create multiple fds from the same handle."); - return INVALID_WINFD; - } - if (access_mode == _O_RDONLY) { - wfd.rw = RW_READ; - } else { - wfd.rw = RW_WRITE; - } - - // Ensure that we get a non system conflicting unique fd - fd = _open_osfhandle((intptr_t)CreateFileA("NUL", 0, 0, - NULL, OPEN_EXISTING, 0, NULL), _O_RDWR); - if (fd < 0) { - return INVALID_WINFD; - } - - overlapped = create_overlapped(); - if(overlapped == NULL) { - _close(fd); - return INVALID_WINFD; - } - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd < 0) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been removed before we got to critical - if (poll_fd[i].fd >= 0) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - wfd.fd = fd; - // Attempt to emulate some of the CancelIoEx behaviour on platforms - // that don't have it - if (!CancelIoEx_Available) { - _poll_fd[i].thread_id = GetCurrentThreadId(); - if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), - &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) { - usbi_dbg("could not duplicate handle for CancelIo - using original one"); - wfd.handle = handle; - // Make sure we won't close the original handle on fd deletion then - _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; - } else { - _poll_fd[i].original_handle = handle; - } - } else { - wfd.handle = handle; - } - wfd.overlapped = overlapped; - memcpy(&poll_fd[i], &wfd, sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); -#if defined(DYNAMIC_FDS) - usbi_mutex_lock(&new_fd_mutex); - new_fd[nb_new_fds++] = overlapped->hEvent; - usbi_mutex_unlock(&new_fd_mutex); - // Notify poll that fds have been updated - SetEvent(fd_update); -#endif - return wfd; - } - } - free_overlapped(overlapped); - _close(fd); - return INVALID_WINFD; -} - -void _free_index(int index) -{ - // Cancel any async IO (Don't care about the validity of our handles for this) - cancel_io(index); - // close fake handle for devices - if ( (poll_fd[index].handle != INVALID_HANDLE_VALUE) && (poll_fd[index].handle != 0) - && (GetFileType(poll_fd[index].handle) == FILE_TYPE_UNKNOWN) ) { - _close(poll_fd[index].fd); - } - // close the duplicate handle (if we have an actual duplicate) - if (!CancelIoEx_Available) { - if (_poll_fd[index].original_handle != INVALID_HANDLE_VALUE) { - CloseHandle(poll_fd[index].handle); - } - _poll_fd[index].original_handle = INVALID_HANDLE_VALUE; - _poll_fd[index].thread_id = 0; - } - free_overlapped(poll_fd[index].overlapped); - poll_fd[index] = INVALID_WINFD; -} - -/* - * Release a pollable file descriptor. - * - * Note that the associated Windows handle is not closed by this call - */ -void usbi_free_fd(int fd) -{ - int index; - - CHECK_INIT_POLLING; - - index = _fd_to_index_and_lock(fd); - if (index < 0) { - return; - } - _free_index(index); - LeaveCriticalSection(&_poll_fd[index].mutex); -} - -/* - * The functions below perform various conversions between fd, handle and OVERLAPPED - */ -struct winfd fd_to_winfd(int fd) -{ - int i; - struct winfd wfd; - - CHECK_INIT_POLLING; - - if (fd <= 0) - return INVALID_WINFD; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd == fd) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been deleted before we got to critical - if (poll_fd[i].fd != fd) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; - } - } - return INVALID_WINFD; -} - -struct winfd handle_to_winfd(HANDLE handle) -{ - int i; - struct winfd wfd; - - CHECK_INIT_POLLING; - - if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) - return INVALID_WINFD; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].handle == handle) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been deleted before we got to critical - if (poll_fd[i].handle != handle) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; - } - } - return INVALID_WINFD; -} - -struct winfd overlapped_to_winfd(OVERLAPPED* overlapped) -{ - int i; - struct winfd wfd; - - CHECK_INIT_POLLING; - - if (overlapped == NULL) - return INVALID_WINFD; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].overlapped == overlapped) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been deleted before we got to critical - if (poll_fd[i].overlapped != overlapped) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; - } - } - return INVALID_WINFD; -} - -/* - * POSIX poll equivalent, using Windows OVERLAPPED - * Currently, this function only accepts one of POLLIN or POLLOUT per fd - * (but you can create multiple fds from the same handle for read and write) - */ -int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) -{ - unsigned i; - int index, object_index, triggered; - HANDLE *handles_to_wait_on; - int *handle_to_index; - DWORD nb_handles_to_wait_on = 0; - DWORD ret; - -#if defined(DYNAMIC_FDS) - DWORD nb_extra_handles = 0; - unsigned j; - - // To address the possibility of missing new fds between the time the new - // pollable fd set is assembled, and the ResetEvent() call below, an - // additional new_fd[] HANDLE table is used for any new fd that was created - // since the last call to poll (see below) - ResetEvent(fd_update); - - // At this stage, any new fd creation will be detected through the fd_update - // event notification, and any previous creation that we may have missed - // will be picked up through the existing new_fd[] table. -#endif - - CHECK_INIT_POLLING; - - triggered = 0; - handles_to_wait_on = malloc((nfds+1)*sizeof(HANDLE)); // +1 for fd_update - handle_to_index = malloc(nfds*sizeof(int)); - if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) { - errno = ENOMEM; - triggered = -1; - goto poll_exit; - } - - for (i = 0; i < nfds; ++i) { - fds[i].revents = 0; - - // Only one of POLLIN or POLLOUT can be selected with this version of poll (not both) - if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) { - fds[i].revents |= POLLERR; - errno = EACCES; - usbi_warn(NULL, "unsupported set of events"); - triggered = -1; - goto poll_exit; - } - - index = _fd_to_index_and_lock(fds[i].fd); - poll_dbg("fd[%d]=%d: (overlapped=%p) got events %04X", i, poll_fd[index].fd, poll_fd[index].overlapped, fds[i].events); - - if ( (index < 0) || (poll_fd[index].handle == INVALID_HANDLE_VALUE) - || (poll_fd[index].handle == 0) || (poll_fd[index].overlapped == NULL)) { - fds[i].revents |= POLLNVAL | POLLERR; - errno = EBADF; - if (index >= 0) { - LeaveCriticalSection(&_poll_fd[index].mutex); - } - usbi_warn(NULL, "invalid fd"); - triggered = -1; - goto poll_exit; - } - - // IN or OUT must match our fd direction - if ((fds[i].events & POLLIN) && (poll_fd[index].rw != RW_READ)) { - fds[i].revents |= POLLNVAL | POLLERR; - errno = EBADF; - usbi_warn(NULL, "attempted POLLIN on fd without READ access"); - LeaveCriticalSection(&_poll_fd[index].mutex); - triggered = -1; - goto poll_exit; - } - - if ((fds[i].events & POLLOUT) && (poll_fd[index].rw != RW_WRITE)) { - fds[i].revents |= POLLNVAL | POLLERR; - errno = EBADF; - usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access"); - LeaveCriticalSection(&_poll_fd[index].mutex); - triggered = -1; - goto poll_exit; - } - - // The following macro only works if overlapped I/O was reported pending - if ( (HasOverlappedIoCompleted(poll_fd[index].overlapped)) - || (HasOverlappedIoCompletedSync(poll_fd[index].overlapped)) ) { - poll_dbg(" completed"); - // checks above should ensure this works: - fds[i].revents = fds[i].events; - triggered++; - } else { - handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[index].overlapped->hEvent; - handle_to_index[nb_handles_to_wait_on] = i; -#if defined(DYNAMIC_FDS) - // If this fd from the poll set is also part of the new_fd event handle table, remove it - usbi_mutex_lock(&new_fd_mutex); - for (j=0; j<nb_new_fds; j++) { - if (handles_to_wait_on[nb_handles_to_wait_on] == new_fd[j]) { - new_fd[j] = INVALID_HANDLE_VALUE; - break; - } - } - usbi_mutex_unlock(&new_fd_mutex); -#endif - nb_handles_to_wait_on++; - } - LeaveCriticalSection(&_poll_fd[index].mutex); - } -#if defined(DYNAMIC_FDS) - // At this stage, new_fd[] should only contain events from fds that - // have been added since the last call to poll, but are not (yet) part - // of the pollable fd set. Typically, these would be from fds that have - // been created between the construction of the fd set and the calling - // of poll. - // Event if we won't be able to return usable poll data on these events, - // make sure we monitor them to return an EINTR code - usbi_mutex_lock(&new_fd_mutex); // We could probably do without - for (i=0; i<nb_new_fds; i++) { - if (new_fd[i] != INVALID_HANDLE_VALUE) { - handles_to_wait_on[nb_handles_to_wait_on++] = new_fd[i]; - nb_extra_handles++; - } - } - usbi_mutex_unlock(&new_fd_mutex); - poll_dbg("dynamic_fds: added %d extra handles", nb_extra_handles); -#endif - - // If nothing was triggered, wait on all fds that require it - if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) { -#if defined(DYNAMIC_FDS) - // Register for fd update notifications - handles_to_wait_on[nb_handles_to_wait_on++] = fd_update; - nb_extra_handles++; -#endif - if (timeout < 0) { - poll_dbg("starting infinite wait for %d handles...", (int)nb_handles_to_wait_on); - } else { - poll_dbg("starting %d ms wait for %d handles...", timeout, (int)nb_handles_to_wait_on); - } - ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on, - FALSE, (timeout<0)?INFINITE:(DWORD)timeout); - object_index = ret-WAIT_OBJECT_0; - if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) { -#if defined(DYNAMIC_FDS) - if ((DWORD)object_index >= (nb_handles_to_wait_on-nb_extra_handles)) { - // Detected fd update => flag a poll interruption - if ((DWORD)object_index == (nb_handles_to_wait_on-1)) - poll_dbg(" dynamic_fds: fd_update event"); - else - poll_dbg(" dynamic_fds: new fd I/O event"); - errno = EINTR; - triggered = -1; - goto poll_exit; - } -#endif - poll_dbg(" completed after wait"); - i = handle_to_index[object_index]; - index = _fd_to_index_and_lock(fds[i].fd); - fds[i].revents = fds[i].events; - triggered++; - if (index >= 0) { - LeaveCriticalSection(&_poll_fd[index].mutex); - } - } else if (ret == WAIT_TIMEOUT) { - poll_dbg(" timed out"); - triggered = 0; // 0 = timeout - } else { - errno = EIO; - triggered = -1; // error - } - } - -poll_exit: - if (handles_to_wait_on != NULL) { - free(handles_to_wait_on); - } - if (handle_to_index != NULL) { - free(handle_to_index); - } -#if defined(DYNAMIC_FDS) - usbi_mutex_lock(&new_fd_mutex); - nb_new_fds = 0; - usbi_mutex_unlock(&new_fd_mutex); -#endif - return triggered; -} - -/* - * close a fake pipe fd - */ -int usbi_close(int fd) -{ - int index; - int r = -1; - - CHECK_INIT_POLLING; - - index = _fd_to_index_and_lock(fd); - - if (index < 0) { - errno = EBADF; - } else { - if (poll_fd[index].overlapped != NULL) { - // Must be a different event for each end of the pipe - CloseHandle(poll_fd[index].overlapped->hEvent); - free(poll_fd[index].overlapped); - } - if (CloseHandle(poll_fd[index].handle) == 0) { - errno = EIO; - } else { - r = 0; - } - poll_fd[index] = INVALID_WINFD; - LeaveCriticalSection(&_poll_fd[index].mutex); - } - return r; -} - -/* - * synchronous write for fake "pipe" signaling - */ -ssize_t usbi_write(int fd, const void *buf, size_t count) -{ - int index; - - CHECK_INIT_POLLING; - - if (count != sizeof(unsigned char)) { - usbi_err(NULL, "this function should only used for signaling"); - return -1; - } - - index = _fd_to_index_and_lock(fd); - - if ( (index < 0) || (poll_fd[index].overlapped == NULL) ) { - errno = EBADF; - if (index >= 0) { - LeaveCriticalSection(&_poll_fd[index].mutex); - } - return -1; - } - - poll_dbg("set pipe event (fd = %d, thread = %08X)", index, GetCurrentThreadId()); - SetEvent(poll_fd[index].overlapped->hEvent); - poll_fd[index].overlapped->Internal = STATUS_WAIT_0; - // If two threads write on the pipe at the same time, we need to - // process two separate reads => use the overlapped as a counter - poll_fd[index].overlapped->InternalHigh++; - - LeaveCriticalSection(&_poll_fd[index].mutex); - return sizeof(unsigned char); -} - -/* - * synchronous read for fake "pipe" signaling - */ -ssize_t usbi_read(int fd, void *buf, size_t count) -{ - int index; - ssize_t r = -1; - - CHECK_INIT_POLLING; - - if (count != sizeof(unsigned char)) { - usbi_err(NULL, "this function should only used for signaling"); - return -1; - } - - index = _fd_to_index_and_lock(fd); - - if (index < 0) { - errno = EBADF; - return -1; - } - - if (WaitForSingleObject(poll_fd[index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) { - usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError()); - errno = EIO; - goto out; - } - - poll_dbg("clr pipe event (fd = %d, thread = %08X)", index, GetCurrentThreadId()); - poll_fd[index].overlapped->InternalHigh--; - // Don't reset unless we don't have any more events to process - if (poll_fd[index].overlapped->InternalHigh <= 0) { - ResetEvent(poll_fd[index].overlapped->hEvent); - poll_fd[index].overlapped->Internal = STATUS_PENDING; - } - - r = sizeof(unsigned char); - -out: - LeaveCriticalSection(&_poll_fd[index].mutex); - return r; -} diff --git a/include/libusb-1.0/os/poll_windows.h b/include/libusb-1.0/os/poll_windows.h deleted file mode 100644 index a9e3e90..0000000 --- a/include/libusb-1.0/os/poll_windows.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Windows compat: POSIX compatibility wrapper - * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com> - * With contributions from Michael Plante, Orin Eman et al. - * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#pragma once - -#if defined(_MSC_VER) -// disable /W4 MSVC warnings that are benign -#pragma warning(disable:4127) // conditional expression is constant -#endif - -// Uncomment to have poll return with EINTR as soon as a new transfer (fd) is added -// This should result in a LIBUSB_ERROR_INTERRUPTED being returned by libusb calls, -// which should give the app an opportunity to resubmit a new fd set. -//#define DYNAMIC_FDS - -// Handle synchronous completion through the overlapped structure -#if !defined(STATUS_REPARSE) // reuse the REPARSE status code -#define STATUS_REPARSE ((LONG)0x00000104L) -#endif -#define STATUS_COMPLETED_SYNCHRONOUSLY STATUS_REPARSE -#define HasOverlappedIoCompletedSync(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) == STATUS_COMPLETED_SYNCHRONOUSLY) - -enum windows_version { - WINDOWS_UNSUPPORTED, - WINDOWS_XP, - WINDOWS_2003, // also includes XP 64 - WINDOWS_VISTA_AND_LATER, -}; -extern enum windows_version windows_version; - -#define MAX_FDS 256 - -#define POLLIN 0x0001 /* There is data to read */ -#define POLLPRI 0x0002 /* There is urgent data to read */ -#define POLLOUT 0x0004 /* Writing now will not block */ -#define POLLERR 0x0008 /* Error condition */ -#define POLLHUP 0x0010 /* Hung up */ -#define POLLNVAL 0x0020 /* Invalid request: fd not open */ - -struct pollfd { - int fd; /* file descriptor */ - short events; /* requested events */ - short revents; /* returned events */ -}; - -typedef unsigned int nfds_t; - -// access modes -enum rw_type { - RW_NONE, - RW_READ, - RW_WRITE, -}; - -// fd struct that can be used for polling on Windows -struct winfd { - int fd; // what's exposed to libusb core - HANDLE handle; // what we need to attach overlapped to the I/O op, so we can poll it - OVERLAPPED* overlapped; // what will report our I/O status - enum rw_type rw; // I/O transfer direction: read *XOR* write (NOT BOTH) -}; -extern const struct winfd INVALID_WINFD; - -int usbi_pipe(int pipefd[2]); -int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout); -ssize_t usbi_write(int fd, const void *buf, size_t count); -ssize_t usbi_read(int fd, void *buf, size_t count); -int usbi_close(int fd); - -void init_polling(void); -void exit_polling(void); -struct winfd usbi_create_fd(HANDLE handle, int access_mode); -void usbi_free_fd(int fd); -struct winfd fd_to_winfd(int fd); -struct winfd handle_to_winfd(HANDLE handle); -struct winfd overlapped_to_winfd(OVERLAPPED* overlapped); - -/* - * Timeval operations - */ -#if defined(DDKBUILD) -#include <winsock.h> // defines timeval functions on DDK -#endif - -#if !defined(TIMESPEC_TO_TIMEVAL) -#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ - (tv)->tv_sec = (long)(ts)->tv_sec; \ - (tv)->tv_usec = (long)(ts)->tv_nsec / 1000; \ -} -#endif -#if !defined(timersub) -#define timersub(a, b, result) \ -do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ - } \ -} while (0) -#endif - diff --git a/include/libusb-1.0/os/threads_posix.h b/include/libusb-1.0/os/threads_posix.h deleted file mode 100644 index dc558d4..0000000 --- a/include/libusb-1.0/os/threads_posix.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * libusb synchronization using POSIX Threads - * - * Copyright (C) 2010 Peter Stuge <peter@stuge.se> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LIBUSB_THREADS_POSIX_H__ -#define __LIBUSB_THREADS_POSIX_H__ - -#include <pthread.h> - -#define usbi_mutex_static_t pthread_mutex_t -#define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER -#define usbi_mutex_static_lock pthread_mutex_lock -#define usbi_mutex_static_unlock pthread_mutex_unlock - -#define usbi_mutex_t pthread_mutex_t -#define usbi_mutex_init pthread_mutex_init -#define usbi_mutex_lock pthread_mutex_lock -#define usbi_mutex_unlock pthread_mutex_unlock -#define usbi_mutex_trylock pthread_mutex_trylock -#define usbi_mutex_destroy pthread_mutex_destroy - -#define usbi_cond_t pthread_cond_t -#define usbi_cond_init pthread_cond_init -#define usbi_cond_wait pthread_cond_wait -#define usbi_cond_timedwait pthread_cond_timedwait -#define usbi_cond_broadcast pthread_cond_broadcast -#define usbi_cond_destroy pthread_cond_destroy -#define usbi_cond_signal pthread_cond_signal - -#endif /* __LIBUSB_THREADS_POSIX_H__ */ diff --git a/include/libusb-1.0/os/threads_windows.c b/include/libusb-1.0/os/threads_windows.c deleted file mode 100644 index 8a29920..0000000 --- a/include/libusb-1.0/os/threads_windows.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * libusb synchronization on Microsoft Windows - * - * Copyright (C) 2010 Michael Plante <michael.plante@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <config.h> -#include <objbase.h> -#include <errno.h> -#include <stdarg.h> - -#include "libusbi.h" - - -int usbi_mutex_init(usbi_mutex_t *mutex, - const usbi_mutexattr_t *attr) { - if(! mutex) return ((errno=EINVAL)); - *mutex = CreateMutex(NULL, FALSE, NULL); - if(!*mutex) return ((errno=ENOMEM)); - return 0; -} -int usbi_mutex_destroy(usbi_mutex_t *mutex) { - // It is not clear if CloseHandle failure is due to failure to unlock. - // If so, this should be errno=EBUSY. - if(!mutex || !CloseHandle(*mutex)) return ((errno=EINVAL)); - *mutex = NULL; - return 0; -} -int usbi_mutex_trylock(usbi_mutex_t *mutex) { - DWORD result; - if(!mutex) return ((errno=EINVAL)); - result = WaitForSingleObject(*mutex, 0); - if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) - return 0; // acquired (ToDo: check that abandoned is ok) - if(result == WAIT_TIMEOUT) - return ((errno=EBUSY)); - return ((errno=EINVAL)); // don't know how this would happen - // so don't know proper errno -} -int usbi_mutex_lock(usbi_mutex_t *mutex) { - DWORD result; - if(!mutex) return ((errno=EINVAL)); - result = WaitForSingleObject(*mutex, INFINITE); - if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) - return 0; // acquired (ToDo: check that abandoned is ok) - return ((errno=EINVAL)); // don't know how this would happen - // so don't know proper errno -} -int usbi_mutex_unlock(usbi_mutex_t *mutex) { - if(!mutex) return ((errno=EINVAL)); - if(!ReleaseMutex(*mutex)) return ((errno=EPERM )); - return 0; -} - -int usbi_mutex_static_lock(usbi_mutex_static_t *mutex) { - if(!mutex) return ((errno=EINVAL)); - while (InterlockedExchange((LONG *)mutex, 1) == 1) { - SleepEx(0, TRUE); - } - return 0; -} -int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) { - if(!mutex) return ((errno=EINVAL)); - *mutex = 0; - return 0; -} - - - -int usbi_cond_init(usbi_cond_t *cond, - const usbi_condattr_t *attr) { - if(!cond) return ((errno=EINVAL)); - list_init(&cond->waiters ); - list_init(&cond->not_waiting); - return 0; -} -int usbi_cond_destroy(usbi_cond_t *cond) { - // This assumes no one is using this anymore. The check MAY NOT BE safe. - struct usbi_cond_perthread *pos, *prev_pos = NULL; - if(!cond) return ((errno=EINVAL)); - if(!list_empty(&cond->waiters)) return ((errno=EBUSY )); // (!see above!) - list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) { - free(prev_pos); - list_del(&pos->list); - prev_pos = pos; - } - free(prev_pos); - prev_pos = pos = NULL; - - return 0; -} - -int usbi_cond_broadcast(usbi_cond_t *cond) { - // Assumes mutex is locked; this is not in keeping with POSIX spec, but - // libusb does this anyway, so we simplify by not adding more sync - // primitives to the CV definition! - int fail = 0; - struct usbi_cond_perthread *pos; - if(!cond) return ((errno=EINVAL)); - list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread) { - if(!SetEvent(pos->event)) - fail = 1; - } - // The wait function will remove its respective item from the list. - return fail ? ((errno=EINVAL)) : 0; -} -int usbi_cond_signal(usbi_cond_t *cond) { - // Assumes mutex is locked; this is not in keeping with POSIX spec, but - // libusb does this anyway, so we simplify by not adding more sync - // primitives to the CV definition! - struct usbi_cond_perthread *pos; - if(!cond) return ((errno=EINVAL)); - if(list_empty(&cond->waiters)) return 0; // no one to wakeup. - pos = list_entry(&cond->waiters.next, struct usbi_cond_perthread, list); - // The wait function will remove its respective item from the list. - return SetEvent(pos->event) ? 0 : ((errno=EINVAL)); -} -static int __inline usbi_cond_intwait(usbi_cond_t *cond, - usbi_mutex_t *mutex, - DWORD timeout_ms) { - struct usbi_cond_perthread *pos; - int found = 0, r; - DWORD r2,tid = GetCurrentThreadId(); - if(!cond || !mutex) return ((errno=EINVAL)); - list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) { - if(tid == pos->tid) { - found = 1; - break; - } - } - if(!found) { - pos = malloc(sizeof(struct usbi_cond_perthread)); - if(!pos) return ((errno=ENOMEM)); // This errno is not POSIX-allowed. - pos->tid = tid; - pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset. - if(!pos->event) { - free(pos); - return ((errno=ENOMEM)); - } - list_add(&pos->list, &cond->not_waiting); - } - - list_del(&pos->list); // remove from not_waiting list. - list_add(&pos->list, &cond->waiters); - - r = usbi_mutex_unlock(mutex); - if(r) return r; - r2 = WaitForSingleObject(pos->event, timeout_ms); - r = usbi_mutex_lock(mutex); - if(r) return r; - - list_del(&pos->list); - list_add(&pos->list, &cond->not_waiting); - - if(r2 == WAIT_TIMEOUT) return ((errno=ETIMEDOUT)); - - return 0; -} -// N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot! -int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex) { - return usbi_cond_intwait(cond, mutex, INFINITE); -} -int usbi_cond_timedwait(usbi_cond_t *cond, - usbi_mutex_t *mutex, - const struct timespec *abstime) { - FILETIME filetime; - ULARGE_INTEGER rtime; - struct timeval targ_time, cur_time, delta_time; - struct timespec cur_time_ns; - DWORD millis; - extern const uint64_t epoch_time; - - GetSystemTimeAsFileTime(&filetime); - rtime.LowPart = filetime.dwLowDateTime; - rtime.HighPart = filetime.dwHighDateTime; - rtime.QuadPart -= epoch_time; - cur_time_ns.tv_sec = (long)(rtime.QuadPart / 10000000); - cur_time_ns.tv_nsec = (long)((rtime.QuadPart % 10000000)*100); - TIMESPEC_TO_TIMEVAL(&cur_time, &cur_time_ns); - - TIMESPEC_TO_TIMEVAL(&targ_time, abstime); - timersub(&targ_time, &cur_time, &delta_time); - if(delta_time.tv_sec < 0) // abstime already passed? - millis = 0; - else { - millis = delta_time.tv_usec/1000; - millis += delta_time.tv_sec *1000; - if (delta_time.tv_usec % 1000) // round up to next millisecond - millis++; - } - - return usbi_cond_intwait(cond, mutex, millis); -} - diff --git a/include/libusb-1.0/os/threads_windows.h b/include/libusb-1.0/os/threads_windows.h deleted file mode 100644 index 2cd1867..0000000 --- a/include/libusb-1.0/os/threads_windows.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * libusb synchronization on Microsoft Windows - * - * Copyright (C) 2010 Michael Plante <michael.plante@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __LIBUSB_THREADS_WINDOWS_H__ -#define __LIBUSB_THREADS_WINDOWS_H__ - -#define usbi_mutex_static_t volatile LONG -#define USBI_MUTEX_INITIALIZER 0 - -#define usbi_mutex_t HANDLE - -struct usbi_cond_perthread { - struct list_head list; - DWORD tid; - HANDLE event; -}; -struct usbi_cond_t_ { - // Every time a thread touches the CV, it winds up in one of these lists. - // It stays there until the CV is destroyed, even if the thread - // terminates. - struct list_head waiters; - struct list_head not_waiting; -}; -typedef struct usbi_cond_t_ usbi_cond_t; - -// We *were* getting timespec from pthread.h: -#if (!defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED)) -#define HAVE_STRUCT_TIMESPEC 1 -#define _TIMESPEC_DEFINED 1 -struct timespec { - long tv_sec; - long tv_nsec; -}; -#endif /* HAVE_STRUCT_TIMESPEC | _TIMESPEC_DEFINED */ - -// We *were* getting ETIMEDOUT from pthread.h: -#ifndef ETIMEDOUT -# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ -#endif - -#define usbi_mutexattr_t void -#define usbi_condattr_t void - - -int usbi_mutex_static_lock(usbi_mutex_static_t *mutex); -int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex); - - -int usbi_mutex_init(usbi_mutex_t *mutex, - const usbi_mutexattr_t *attr); -int usbi_mutex_lock(usbi_mutex_t *mutex); -int usbi_mutex_unlock(usbi_mutex_t *mutex); -int usbi_mutex_trylock(usbi_mutex_t *mutex); -int usbi_mutex_destroy(usbi_mutex_t *mutex); - -int usbi_cond_init(usbi_cond_t *cond, - const usbi_condattr_t *attr); -int usbi_cond_destroy(usbi_cond_t *cond); -int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex); -int usbi_cond_timedwait(usbi_cond_t *cond, - usbi_mutex_t *mutex, - const struct timespec *abstime); -int usbi_cond_broadcast(usbi_cond_t *cond); -int usbi_cond_signal(usbi_cond_t *cond); - -#endif /* __LIBUSB_THREADS_WINDOWS_H__ */ - diff --git a/include/libusb-1.0/os/windows_usb.c b/include/libusb-1.0/os/windows_usb.c deleted file mode 100644 index e37932a..0000000 --- a/include/libusb-1.0/os/windows_usb.c +++ /dev/null @@ -1,4185 +0,0 @@ -/* - * windows backend for libusb 1.0 - * Copyright (c) 2009-2010 Pete Batard <pbatard@gmail.com> - * With contributions from Michael Plante, Orin Eman et al. - * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer - * HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software - * Major code testing contribution by Xiaofan Chen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -// COMPILATION OPTIONS: -// - Should libusb automatically claim (and release) the interfaces it requires? -#define AUTO_CLAIM -// - Forces instant overlapped completion on timeouts: can prevents extensive -// wait in poll, after a timeout, but might affect subsequent API calls. -// ***USE AT YOUR OWN RISKS*** -//#define FORCE_INSTANT_TIMEOUTS - -#include <config.h> -#include <windows.h> -#include <setupapi.h> -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <process.h> -#include <stdio.h> -#include <inttypes.h> -#include <objbase.h> // for string to GUID conv. requires libole32.a -#include <winioctl.h> - -#include <libusbi.h> -#include "poll_windows.h" -#include "windows_usb.h" - -// The following prevents "banned API" errors when using the MS's WDK OACR/Prefast -#if defined(_PREFAST_) -#pragma warning(disable:28719) -#endif - -// The 2 macros below are used in conjunction with safe loops. -#define LOOP_CHECK(fcall) { r=fcall; if (r != LIBUSB_SUCCESS) continue; } -#define LOOP_BREAK(err) { r=err; continue; } - -extern void usbi_fd_notification(struct libusb_context *ctx); - -// Helper prototypes -static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian); -static int windows_clock_gettime(int clk_id, struct timespec *tp); -unsigned __stdcall windows_clock_gettime_threaded(void* param); -// WinUSB API prototypes -static int winusb_init(struct libusb_context *ctx); -static int winusb_exit(void); -static int winusb_open(struct libusb_device_handle *dev_handle); -static void winusb_close(struct libusb_device_handle *dev_handle); -static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int iface); -static int winusb_release_interface(struct libusb_device_handle *dev_handle, int iface); -static int winusb_submit_control_transfer(struct usbi_transfer *itransfer); -static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting); -static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer); -static int winusb_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint); -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); -// HID API prototypes -static int hid_init(struct libusb_context *ctx); -static int hid_exit(void); -static int hid_open(struct libusb_device_handle *dev_handle); -static void hid_close(struct libusb_device_handle *dev_handle); -static int hid_claim_interface(struct libusb_device_handle *dev_handle, int iface); -static int hid_release_interface(struct libusb_device_handle *dev_handle, int iface); -static int hid_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting); -static int hid_submit_control_transfer(struct usbi_transfer *itransfer); -static int hid_submit_bulk_transfer(struct usbi_transfer *itransfer); -static int hid_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint); -static int hid_abort_transfers(struct usbi_transfer *itransfer); -static int hid_reset_device(struct libusb_device_handle *dev_handle); -static int hid_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size); -// Composite API prototypes -static int composite_init(struct libusb_context *ctx); -static int composite_exit(void); -static int composite_open(struct libusb_device_handle *dev_handle); -static void composite_close(struct libusb_device_handle *dev_handle); -static int composite_claim_interface(struct libusb_device_handle *dev_handle, int iface); -static int composite_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting); -static int composite_release_interface(struct libusb_device_handle *dev_handle, int iface); -static int composite_submit_control_transfer(struct usbi_transfer *itransfer); -static int composite_submit_bulk_transfer(struct usbi_transfer *itransfer); -static int composite_submit_iso_transfer(struct usbi_transfer *itransfer); -static int composite_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint); -static int composite_abort_transfers(struct usbi_transfer *itransfer); -static int composite_abort_control(struct usbi_transfer *itransfer); -static int composite_reset_device(struct libusb_device_handle *dev_handle); -static int composite_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size); - - -// Global variables -struct windows_hcd_priv* hcd_root = NULL; -uint64_t hires_frequency, hires_ticks_to_ps; -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; -#if defined(AUTO_CLAIM) -usbi_mutex_t autoclaim_lock; -#endif -// Timer thread -// NB: index 0 is for monotonic and 1 is for the thread exit event -HANDLE timer_thread = NULL; -HANDLE timer_mutex = NULL; -struct timespec timer_tp; -volatile LONG request_count[2] = {0, 1}; // last one must be > 0 -HANDLE timer_request[2] = { NULL, NULL }; -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_hid_available = false; -#define CHECK_HID_AVAILABLE do { if (!api_hid_available) return LIBUSB_ERROR_ACCESS; } while (0) - - -/* - * Converts a WCHAR string to UTF8 (allocate returned string) - * Returns NULL on error - */ -static char* wchar_to_utf8(LPCWSTR wstr) -{ - int size; - char* str; - - // Find out the size we need to allocate for our converted string - size = wchar_to_utf8_ms(wstr, NULL, 0); - if (size <= 1) // An empty string would be size 1 - return NULL; - - if ((str = malloc(size)) == NULL) - return NULL; - - if (wchar_to_utf8_ms(wstr, str, size) != size) { - safe_free(str); - return NULL; - } - - return str; -} - -static inline BOOLEAN guid_eq(const GUID *guid1, const GUID *guid2) { - if ((guid1 != NULL) && (guid2 != NULL)) { - return (memcmp(guid1, guid2, sizeof(GUID)) == 0); - } - return false; -} - -#if 0 -static char* guid_to_string(const GUID guid) -{ - static char guid_string[MAX_GUID_STRING_LENGTH]; - - sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", - (unsigned int)guid.Data1, guid.Data2, guid.Data3, - guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], - guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); - return guid_string; -} -#endif - -/* - * Converts a windows error to human readable string - * uses retval as errorcode, or, if 0, use GetLastError() - */ -static char *windows_error_str(uint32_t retval) -{ -static char err_string[ERR_BUFFER_SIZE]; - - DWORD size; - size_t i; - uint32_t error_code, format_error; - - error_code = retval?retval:GetLastError(); - - safe_sprintf(err_string, ERR_BUFFER_SIZE, "[%d] ", error_code); - - size = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &err_string[safe_strlen(err_string)], - ERR_BUFFER_SIZE - (DWORD)safe_strlen(err_string), NULL); - if (size == 0) { - format_error = GetLastError(); - if (format_error) - safe_sprintf(err_string, ERR_BUFFER_SIZE, - "Windows error code %u (FormatMessage error code %u)", error_code, format_error); - else - safe_sprintf(err_string, ERR_BUFFER_SIZE, "Unknown error code %u", error_code); - } else { - // Remove CR/LF terminators - for (i=safe_strlen(err_string)-1; ((err_string[i]==0x0A) || (err_string[i]==0x0D)); i--) { - err_string[i] = 0; - } - } - return err_string; -} - -/* - * Sanitize Microsoft's paths: convert to uppercase, add prefix and fix backslashes. - * Return an allocated sanitized string or NULL on error. - */ -static char* sanitize_path(const char* path) -{ - const char root_prefix[] = "\\\\.\\"; - size_t j, size, root_size; - char* ret_path = NULL; - size_t add_root = 0; - - if (path == NULL) - return NULL; - - size = safe_strlen(path)+1; - root_size = sizeof(root_prefix)-1; - - // Microsoft indiscriminatly uses '\\?\', '\\.\', '##?#" or "##.#" for root prefixes. - if (!((size > 3) && (((path[0] == '\\') && (path[1] == '\\') && (path[3] == '\\')) || - ((path[0] == '#') && (path[1] == '#') && (path[3] == '#'))))) { - add_root = root_size; - size += add_root; - } - - if ((ret_path = (char*)calloc(size, 1)) == NULL) - return NULL; - - safe_strcpy(&ret_path[add_root], size-add_root, path); - - // Ensure consistancy with root prefix - for (j=0; j<root_size; j++) - ret_path[j] = root_prefix[j]; - - // Same goes for '\' and '#' after the root prefix. Ensure '#' is used - for(j=root_size; j<size; j++) { - ret_path[j] = (char)toupper((int)ret_path[j]); // Fix case too - if (ret_path[j] == '\\') - ret_path[j] = '#'; - } - - return ret_path; -} - -/* - * Cfgmgr32 API functions - */ -static int Cfgmgr32_init(void) -{ - DLL_LOAD(Cfgmgr32.dll, CM_Get_Parent, TRUE); - DLL_LOAD(Cfgmgr32.dll, CM_Get_Child, TRUE); - DLL_LOAD(Cfgmgr32.dll, CM_Get_Sibling, TRUE); - DLL_LOAD(Cfgmgr32.dll, CM_Get_Device_IDA, TRUE); - DLL_LOAD(Cfgmgr32.dll, CM_Get_Device_IDW, TRUE); - - return LIBUSB_SUCCESS; -} - -/* - * enumerate interfaces for a specific GUID - * - * Parameters: - * dev_info: a pointer to a dev_info list - * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed) - * guid: the GUID for which to retrieve interface details - * index: zero based index of the interface in the device info list - * - * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA - * structure returned and call this function repeatedly using the same guid (with an - * incremented index starting at zero) until all interfaces have been returned. - */ -SP_DEVICE_INTERFACE_DETAIL_DATA *get_interface_details(struct libusb_context *ctx, - HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, GUID guid, unsigned index) -{ - SP_DEVICE_INTERFACE_DATA dev_interface_data; - SP_DEVICE_INTERFACE_DETAIL_DATA *dev_interface_details = NULL; - DWORD size; - - if (index <= 0) { - *dev_info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); - } - if (*dev_info == INVALID_HANDLE_VALUE) { - return NULL; - } - - if (dev_info_data != NULL) { - dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); - if (!SetupDiEnumDeviceInfo(*dev_info, index, dev_info_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) { - usbi_err(ctx, "Could not obtain device info data for index %u: %s", - index, windows_error_str(0)); - } - SetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; - } - } - - dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); - if (!SetupDiEnumDeviceInterfaces(*dev_info, NULL, &guid, index, &dev_interface_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) { - usbi_err(ctx, "Could not obtain interface data for index %u: %s", - index, windows_error_str(0)); - } - SetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; - } - - // Read interface data (dummy + actual) to access the device path - if (!SetupDiGetDeviceInterfaceDetail(*dev_info, &dev_interface_data, NULL, 0, &size, NULL)) { - // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - usbi_err(ctx, "could not access interface data (dummy) for index %u: %s", - index, windows_error_str(0)); - goto err_exit; - } - } - else { - usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong."); - goto err_exit; - } - - if ((dev_interface_details = malloc(size)) == NULL) { - usbi_err(ctx, "could not allocate interface data for index %u.", index); - goto err_exit; - } - - dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - if (!SetupDiGetDeviceInterfaceDetail(*dev_info, &dev_interface_data, - dev_interface_details, size, &size, NULL)) { - usbi_err(ctx, "could not access interface data (actual) for index %u: %s", - index, windows_error_str(0)); - } - - return dev_interface_details; - -err_exit: - SetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; -} - -/* - * Populate the endpoints addresses of the device_priv interface helper structs - */ -static int windows_assign_endpoints(struct libusb_device *dev, int iface, int altsetting) -{ - int i, r; - struct windows_device_priv *priv = __device_priv(dev); - struct libusb_config_descriptor *conf_desc; - const struct libusb_interface_descriptor *if_desc; - - r = libusb_get_config_descriptor(dev, 0, &conf_desc); - if (r != LIBUSB_SUCCESS) { - usbi_warn(NULL, "could not read config descriptor: error %d", r); - return r; - } - - 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 %d", iface); - return LIBUSB_SUCCESS; - } - - priv->usb_interface[iface].endpoint = malloc(if_desc->bNumEndpoints); - if (priv->usb_interface[iface].endpoint == NULL) { - 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 %d", priv->usb_interface[iface].endpoint[i], iface); - } - libusb_free_config_descriptor(conf_desc); - - return LIBUSB_SUCCESS; -} - -// Lookup for a match in the list of API driver names -bool is_api_driver(char* driver, uint8_t api) -{ - uint8_t i; - const char sep_str[2] = {LIST_SEPARATOR, 0}; - char *tok, *tmp_str; - size_t len = safe_strlen(driver); - - if (len == 0) return false; - tmp_str = calloc(len+1, 1); - if (tmp_str == NULL) return false; - memcpy(tmp_str, driver, len+1); - tok = strtok(tmp_str, sep_str); - while (tok != NULL) { - for (i=0; i<usb_api_backend[api].nb_driver_names; i++) { - if (safe_strcmp(tok, usb_api_backend[api].driver_name_list[i]) == 0) { - free(tmp_str); - return true; - } - } - tok = strtok(NULL, sep_str); - } - free (tmp_str); - return false; -} - -/* - * auto-claiming and auto-release helper functions - */ -#if defined(AUTO_CLAIM) -static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type) -{ - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = __device_handle_priv( - transfer->dev_handle); - struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev); - int current_interface = *interface_number; - int r = LIBUSB_SUCCESS; - - switch(api_type) { - case USB_API_WINUSB: - case USB_API_HID: - break; - default: - return LIBUSB_ERROR_INVALID_PARAM; - } - - usbi_mutex_lock(&autoclaim_lock); - if (current_interface < 0) // No serviceable interface was found - { - for (current_interface=0; current_interface<USB_MAXINTERFACES; current_interface++) { - // Must claim an interface of the same API type - if ( (priv->usb_interface[current_interface].apib == &usb_api_backend[api_type]) - && (libusb_claim_interface(transfer->dev_handle, current_interface) == LIBUSB_SUCCESS) ) { - usbi_dbg("auto-claimed interface %d for control request", current_interface); - if (handle_priv->autoclaim_count[current_interface] != 0) { - usbi_warn(ctx, "program assertion failed - autoclaim_count was nonzero"); - } - handle_priv->autoclaim_count[current_interface]++; - break; - } - } - if (current_interface == USB_MAXINTERFACES) { - usbi_err(ctx, "could not auto-claim any interface"); - r = LIBUSB_ERROR_NOT_FOUND; - } - } else { - // If we have a valid interface that was autoclaimed, we must increment - // its autoclaim count so that we can prevent an early release. - if (handle_priv->autoclaim_count[current_interface] != 0) { - handle_priv->autoclaim_count[current_interface]++; - } - } - usbi_mutex_unlock(&autoclaim_lock); - - *interface_number = current_interface; - return r; - -} - -static void auto_release(struct usbi_transfer *itransfer) -{ - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - libusb_device_handle *dev_handle = transfer->dev_handle; - struct windows_device_handle_priv* handle_priv = __device_handle_priv(dev_handle); - int r; - - usbi_mutex_lock(&autoclaim_lock); - if (handle_priv->autoclaim_count[transfer_priv->interface_number] > 0) { - handle_priv->autoclaim_count[transfer_priv->interface_number]--; - 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); - } else { - usbi_dbg("failed to auto-release interface %d (%s)", - transfer_priv->interface_number, libusb_strerror(r)); - } - } - } - usbi_mutex_unlock(&autoclaim_lock); -} -#endif - - -/* - * init: libusb backend init function - * - * This function enumerates the HCDs (Host Controller Drivers) and populates our private HCD list - * In our implementation, we equate Windows' "HCD" to LibUSB's "bus". Note that bus is zero indexed. - * HCDs are not expected to change after init (might not hold true for hot pluggable USB PCI card?) - */ -static int windows_init(struct libusb_context *ctx) -{ - HDEVINFO dev_info; - SP_DEVICE_INTERFACE_DETAIL_DATA *dev_interface_details = NULL; - GUID guid; - libusb_bus_t bus; - int i, r = LIBUSB_ERROR_OTHER; - OSVERSIONINFO os_version; - HANDLE semaphore; - struct windows_hcd_priv** _hcd_cur; - TCHAR sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID) - - sprintf(sem_name, "libusb_init%08X", (unsigned int)GetCurrentProcessId()&0xFFFFFFFF); - semaphore = CreateSemaphore(NULL, 1, 1, sem_name); - if (semaphore == NULL) { - usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0)); - return LIBUSB_ERROR_NO_MEM; - } - - // A successful wait brings our semaphore count to 0 (unsignaled) - // => any concurent wait stalls until the semaphore's release - if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { - usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0)); - CloseHandle(semaphore); - return LIBUSB_ERROR_NO_MEM; - } - - // 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? - _hcd_cur = &hcd_root; - - // Detect OS version - memset(&os_version, 0, sizeof(OSVERSIONINFO)); - 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)) { - windows_version = WINDOWS_XP; - } else if ((os_version.dwMajorVersion == 5) && (os_version.dwMinorVersion == 2)) { - windows_version = WINDOWS_2003; // also includes XP 64 - } else if (os_version.dwMajorVersion >= 6) { - windows_version = WINDOWS_VISTA_AND_LATER; - } - } - if (windows_version == WINDOWS_UNSUPPORTED) { - usbi_err(ctx, "This version of Windows is NOT supported"); - r = LIBUSB_ERROR_NOT_SUPPORTED; - goto init_exit; - } - -#if defined(AUTO_CLAIM) - // We need a lock for proper auto-release - usbi_mutex_init(&autoclaim_lock, NULL); -#endif - - // 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_NOT_FOUND; - } - - // Initialize the low level APIs (we don't care about errors at this stage) - for (i=0; i<USB_API_MAX; i++) { - usb_api_backend[i].init(ctx); - } - - // Because QueryPerformanceCounter might report different values when - // running on different cores, we create a separate thread for the timer - // calls, which we glue to the first core always to prevent timing discrepancies. - r = LIBUSB_ERROR_NO_MEM; - for (i = 0; i < 2; i++) { - timer_request[i] = CreateEvent(NULL, TRUE, FALSE, NULL); - if (timer_request[i] == NULL) { - usbi_err(ctx, "could not create timer request event %d - aborting", i); - goto init_exit; - } - } - timer_response = CreateSemaphore(NULL, 0, MAX_TIMER_SEMAPHORES, NULL); - if (timer_response == NULL) { - usbi_err(ctx, "could not create timer response semaphore - aborting"); - goto init_exit; - } - timer_mutex = CreateMutex(NULL, FALSE, NULL); - if (timer_mutex == NULL) { - usbi_err(ctx, "could not create timer mutex - aborting"); - goto init_exit; - } - timer_thread = (HANDLE)_beginthreadex(NULL, 0, windows_clock_gettime_threaded, NULL, 0, NULL); - if (timer_thread == NULL) { - usbi_err(ctx, "Unable to create timer thread - aborting"); - goto init_exit; - } - SetThreadAffinityMask(timer_thread, 0); - - guid = GUID_DEVINTERFACE_USB_HOST_CONTROLLER; - - r = LIBUSB_SUCCESS; - for (bus = 0; ; bus++) - { - // safe loop: free up any (unprotected) dynamic resource - // NB: this is always executed before breaking the loop - safe_free(dev_interface_details); - safe_free(*_hcd_cur); - - 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)) - break; - - // Will need to change storage and size of libusb_bus_t if this ever occurs - if (bus == LIBUSB_BUS_MAX) { - usbi_warn(ctx, "program assertion failed - found more than %d buses, skipping the rest.", LIBUSB_BUS_MAX); - continue; - } - - // 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 bus %u. aborting.", bus); - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - windows_hcd_priv_init(*_hcd_cur); - (*_hcd_cur)->path = sanitize_path(dev_interface_details->DevicePath); - - _hcd_cur = &((*_hcd_cur)->next); - } - // TODO (2nd official release): thread for hotplug (see darwin source) - } - - if (hcd_root == NULL) - r = LIBUSB_ERROR_NO_DEVICE; - else - r = LIBUSB_SUCCESS; - -init_exit: // Holds semaphore here. - if(!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed? - if (timer_thread) { - SetEvent(timer_request[1]); // actually the signal to quit the thread. - if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) { - usbi_warn(ctx, "could not wait for timer thread to quit"); - TerminateThread(timer_thread, 1); // shouldn't happen, but we're destroying - // all objects it might have held anyway. - } - CloseHandle(timer_thread); - timer_thread = NULL; - } - for (i = 0; i < 2; i++) { - if (timer_request[i]) { - CloseHandle(timer_request[i]); - timer_request[i] = NULL; - } - } - if (timer_response) { - CloseHandle(timer_response); - timer_response = NULL; - } - if (timer_mutex) { - CloseHandle(timer_mutex); - timer_mutex = NULL; - } - } - - if (r != LIBUSB_SUCCESS) - --concurrent_usage; // Not expected to call libusb_exit if we failed. - - ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 - CloseHandle(semaphore); - return r; -} - -/* - * Initialize device structure, including active config - */ -static int initialize_device(struct libusb_device *dev, libusb_bus_t busnum, - libusb_devaddr_t devaddr, char *path, int connection_index, uint8_t active_config, - struct libusb_device *parent_dev) -{ - struct windows_device_priv *priv = __device_priv(dev); - - windows_device_priv_init(priv); - - dev->bus_number = busnum; - dev->device_address = devaddr; - priv->path = path; - priv->connection_index = connection_index; - priv->parent_dev = parent_dev; - - priv->active_config = active_config; - - if (priv->active_config != 0) { - usbi_dbg("active config: %d", priv->active_config); - } else { - // USB devices that don't have a config value are usually missing a driver - // TODO (after first official release): use this for automated driver installation - // NB: SetupDiGetDeviceRegistryProperty w/ SPDRP_INSTALL_STATE would tell us - // if the driver is properly installed, but driverless devices don't seem to - // be enumerable by SetupDi... - usbi_dbg("* This device has no driver => libusb will not be able to access it *"); - } - - return LIBUSB_SUCCESS; -} - -/* - * HCD (root) hubs need to have their device descriptor manually populated - * - * Note that we follow the Linux convention and use the "Linux Foundation root hub" - * vendor ID as well as the product ID to indicate the hub speed - */ -static int force_hcd_device_descriptor(struct libusb_device *dev, HANDLE handle) -{ - DWORD size; - USB_HUB_CAPABILITIES hub_caps; - USB_HUB_CAPABILITIES_EX hub_caps_ex; - struct windows_device_priv *priv = __device_priv(dev); - struct libusb_context *ctx = DEVICE_CTX(dev); - - priv->dev_descriptor.bLength = sizeof(USB_DEVICE_DESCRIPTOR); - priv->dev_descriptor.bDescriptorType = USB_DEVICE_DESCRIPTOR_TYPE; - dev->num_configurations = priv->dev_descriptor.bNumConfigurations = 1; - - // The following is used to set the VIS:PID of root HUBs similarly to what - // Linux does: 1d6b:0001 is for 1x root hubs, 1d6b:0002 for 2x - priv->dev_descriptor.idVendor = 0x1d6b; // Linux Foundation root hub - if (windows_version >= WINDOWS_VISTA_AND_LATER) { - size = sizeof(USB_HUB_CAPABILITIES_EX); - if (DeviceIoControl(handle, IOCTL_USB_GET_HUB_CAPABILITIES_EX, &hub_caps_ex, - size, &hub_caps_ex, size, &size, NULL)) { - // Sanity check. HCD hub should always be root - if (!hub_caps_ex.CapabilityFlags.HubIsRoot) { - usbi_warn(ctx, "program assertion failed - HCD hub is not reported as root hub."); - } - priv->dev_descriptor.idProduct = hub_caps_ex.CapabilityFlags.HubIsHighSpeedCapable?2:1; - } - } else { - size = sizeof(USB_HUB_CAPABILITIES); - if (!DeviceIoControl(handle, IOCTL_USB_GET_HUB_CAPABILITIES, &hub_caps, - 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)); - priv->dev_descriptor.idProduct = 1; // Indicate 1x speed - } else { - priv->dev_descriptor.idProduct = hub_caps.HubIs2xCapable?2:1; - } - } - - return LIBUSB_SUCCESS; -} - -/* - * fetch and cache all the config descriptors through I/O - */ -static int cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle) -{ - DWORD size, ret_size; - struct libusb_context *ctx = DEVICE_CTX(dev); - struct windows_device_priv *priv = __device_priv(dev); - int r; - uint8_t i; - - USB_CONFIGURATION_DESCRIPTOR_SHORT cd_buf_short; // dummy request - PUSB_DESCRIPTOR_REQUEST cd_buf_actual = NULL; // actual request - PUSB_CONFIGURATION_DESCRIPTOR cd_data = NULL; - - if (dev->num_configurations == 0) - return LIBUSB_ERROR_INVALID_PARAM; - - priv->config_descriptor = malloc(dev->num_configurations * sizeof(PUSB_CONFIGURATION_DESCRIPTOR)); - if (priv->config_descriptor == NULL) - return LIBUSB_ERROR_NO_MEM; - for (i=0; i<dev->num_configurations; i++) - priv->config_descriptor[i] = NULL; - - for (i=0, r=LIBUSB_SUCCESS; ; i++) - { - // safe loop: release all dynamic resources - safe_free(cd_buf_actual); - - // safe loop: end of loop condition - if ((i >= dev->num_configurations) || (r != LIBUSB_SUCCESS)) - break; - - size = sizeof(USB_CONFIGURATION_DESCRIPTOR_SHORT); - memset(&cd_buf_short, 0, size); - - cd_buf_short.req.ConnectionIndex = priv->connection_index; - cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN; - cd_buf_short.req.SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR; - cd_buf_short.req.SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i; - cd_buf_short.req.SetupPacket.wIndex = i; - cd_buf_short.req.SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST)); - - // Dummy call to get the required data size - if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &cd_buf_short, size, - &cd_buf_short, size, &ret_size, NULL)) { - usbi_err(ctx, "could not access configuration descriptor (dummy): %s", windows_error_str(0)); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - if ((ret_size != size) || (cd_buf_short.data.wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))) { - usbi_err(ctx, "unexpected configuration descriptor size (dummy)."); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - size = sizeof(USB_DESCRIPTOR_REQUEST) + cd_buf_short.data.wTotalLength; - if ((cd_buf_actual = (PUSB_DESCRIPTOR_REQUEST)malloc(size)) == NULL) { - usbi_err(ctx, "could not allocate configuration descriptor buffer. aborting."); - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - memset(cd_buf_actual, 0, size); - - // Actual call - cd_buf_actual->ConnectionIndex = priv->connection_index; - cd_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN; - cd_buf_actual->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR; - cd_buf_actual->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i; - cd_buf_actual->SetupPacket.wIndex = i; - cd_buf_actual->SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST)); - - if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, cd_buf_actual, size, - cd_buf_actual, size, &ret_size, NULL)) { - usbi_err(ctx, "could not access configuration descriptor (actual): %s", windows_error_str(0)); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR*)cd_buf_actual+sizeof(USB_DESCRIPTOR_REQUEST)); - - if ((size != ret_size) || (cd_data->wTotalLength != cd_buf_short.data.wTotalLength)) { - usbi_err(ctx, "unexpected configuration descriptor size (actual)."); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - if (cd_data->bDescriptorType != USB_CONFIGURATION_DESCRIPTOR_TYPE) { - usbi_err(ctx, "not a configuration descriptor"); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - usbi_dbg("cached config descriptor #%d (%d bytes)", i+1, cd_data->wTotalLength); - - // Sanity check. Ensures that indexes for our list of config desc is in the right order - if (i != (cd_data->bConfigurationValue-1)) { - usbi_warn(ctx, "program assertion failed - config descriptors are being read out of order"); - continue; - } - - // Cache the descriptor - priv->config_descriptor[i] = malloc(cd_data->wTotalLength); - if (priv->config_descriptor[i] == NULL) - return LIBUSB_ERROR_NO_MEM; - - memcpy(priv->config_descriptor[i], cd_data, cd_data->wTotalLength); - } - return LIBUSB_SUCCESS; -} - -/* - * Recursively enumerates and finds all hubs & devices - */ -static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs **_discdevs, - HANDLE hub_handle, libusb_bus_t busnum, struct libusb_device *parent_dev, uint8_t nb_ports) -{ - struct discovered_devs *discdevs = *_discdevs; - struct libusb_device *dev = NULL; - DWORD size, size_initial, size_fixed, getname_ioctl; - HANDLE handle = INVALID_HANDLE_VALUE; - USB_HUB_NAME_FIXED s_hubname; - USB_NODE_CONNECTION_INFORMATION conn_info; - USB_NODE_INFORMATION hub_node; - bool is_hcd, need_unref = false; - int i, r; - LPCWSTR wstr; - char *tmp_str = NULL, *path_str = NULL; - unsigned long session_id; - libusb_devaddr_t devaddr = 0; - struct windows_device_priv *priv, *parent_priv; - - // obviously, root (HCD) hubs have no parent - is_hcd = (parent_dev == NULL); - if (is_hcd) - { - if (nb_ports != 1) { - usbi_warn(ctx, "program assertion failed - invalid number of ports for HCD."); - return LIBUSB_ERROR_INVALID_PARAM; - } - parent_priv = NULL; - size_initial = sizeof(USB_ROOT_HUB_NAME); - size_fixed = sizeof(USB_ROOT_HUB_NAME_FIXED); - getname_ioctl = IOCTL_USB_GET_ROOT_HUB_NAME; - } - else - { - parent_priv = __device_priv(parent_dev); - size_initial = sizeof(USB_NODE_CONNECTION_NAME); - size_fixed = sizeof(USB_NODE_CONNECTION_NAME_FIXED); - getname_ioctl = IOCTL_USB_GET_NODE_CONNECTION_NAME; - } - - // Loop through all the ports on this hub - for (i = 1, r = LIBUSB_SUCCESS; ; i++) - { - // safe loop: release all dynamic resources - if (need_unref) { - safe_unref_device(dev); - need_unref = false; - } - safe_free(tmp_str); - safe_free(path_str); - safe_closehandle(handle); - - // safe loop: end of loop condition - if ((i > nb_ports) || (r != LIBUSB_SUCCESS)) - break; - - memset(&conn_info, 0, sizeof(conn_info)); - // For non HCDs, check if the node on this port is a hub or a regular device - if (!is_hcd) { - size = sizeof(USB_NODE_CONNECTION_INFORMATION); - conn_info.ConnectionIndex = i; - if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, &conn_info, size, - &conn_info, size, &size, NULL)) { - usbi_warn(ctx, "could not get node connection information: %s", windows_error_str(0)); - continue; - } - - if (conn_info.ConnectionStatus == NoDeviceConnected) { - continue; - } - - if (conn_info.DeviceAddress == LIBUSB_DEVADDR_MAX) { - usbi_warn(ctx, "program assertion failed - device address is %d " - "(conflicts with root hub), ignoring device", LIBUSB_DEVADDR_MAX); - continue; - } - - s_hubname.u.node.ConnectionIndex = i; // Only used for non HCDs (s_hubname is an union) - } - else - { - // HCDs have only 1 node, and it's always a hub - conn_info.DeviceAddress = LIBUSB_DEVADDR_MAX; // using 0 can conflict with driverless devices - conn_info.DeviceIsHub = true; - conn_info.CurrentConfigurationValue = 1; - } - - // If this node is a hub (HCD or not), open it - if (conn_info.DeviceIsHub) { - size = size_initial; - if (!DeviceIoControl(hub_handle, getname_ioctl, &s_hubname, size, - &s_hubname, size, &size, NULL)) { - usbi_warn(ctx, "could not get hub path (dummy): %s", windows_error_str(0)); - continue; - } - - size = is_hcd?s_hubname.u.root.ActualLength:s_hubname.u.node.ActualLength; - if (size > size_fixed) { - usbi_warn(ctx, "program assertion failed - hub path is too long"); - continue; - } - - if (!is_hcd) { - // previous call trashes some of the data - s_hubname.u.node.ConnectionIndex = i; - } - if (!DeviceIoControl(hub_handle, getname_ioctl, &s_hubname, size, - &s_hubname, size, &size, NULL)) { - usbi_warn(ctx, "could not get hub path (actual): %s", windows_error_str(0)); - continue; - } - - // Add prefix - wstr = is_hcd?s_hubname.u.root.RootHubName:s_hubname.u.node.NodeName; - tmp_str = wchar_to_utf8(wstr); - if (tmp_str == NULL) { - usbi_err(ctx, "could not convert hub path string."); - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - - path_str = sanitize_path(tmp_str); - if (path_str == NULL) { - usbi_err(ctx, "could not sanitize hub path string."); - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - - // Open Hub - handle = CreateFileA(path_str, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - 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; - } - } - - // Generate a session ID - // Will need to change the session_id computation if this assertion fails - if (conn_info.DeviceAddress > LIBUSB_DEVADDR_MAX) { - usbi_warn(ctx, "program assertion failed - device address is greater than %d, ignoring device", - LIBUSB_DEVADDR_MAX); - continue; - } else { - devaddr = (uint8_t)conn_info.DeviceAddress; - } - // Same trick as linux for session_id, with same caveat - session_id = busnum << (sizeof(libusb_devaddr_t)*8) | devaddr; - usbi_dbg("busnum %d devaddr %d session_id %ld", busnum, devaddr, session_id); - - // Allocate device if needed - dev = usbi_get_device_by_session_id(ctx, session_id); - if (dev) { - usbi_dbg("using existing device for session %ld", session_id); - priv = __device_priv(dev); - // Because we are rebuilding the list, there's no guarantee - // the parent device pointer is still the same. - // Other device data should still be reusable - priv->parent_dev = parent_dev; - } else { - usbi_dbg("allocating new device for session %ld", session_id); - if ((dev = usbi_alloc_device(ctx, session_id)) == NULL) { - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - need_unref = true; - - LOOP_CHECK(initialize_device(dev, busnum, devaddr, path_str, i, - conn_info.CurrentConfigurationValue, parent_dev)); - priv = __device_priv(dev); - - path_str = NULL; // protect our path from being freed - - // Setup the cached descriptors. Note that only non HCDs can fetch descriptors - if (!is_hcd) { - // The device descriptor has been read with conn_info - memcpy(&priv->dev_descriptor, &(conn_info.DeviceDescriptor), sizeof(USB_DEVICE_DESCRIPTOR)); - dev->num_configurations = priv->dev_descriptor.bNumConfigurations; - // If we can't read the config descriptors, just set the number of confs to zero - if (cache_config_descriptors(dev, hub_handle) != LIBUSB_SUCCESS) { - dev->num_configurations = 0; - priv->dev_descriptor.bNumConfigurations = 0; - } - } else { - LOOP_CHECK(force_hcd_device_descriptor(dev, handle)); - } - LOOP_CHECK(usbi_sanitize_device(dev)); - } - - discdevs = discovered_devs_append(*_discdevs, dev); - if (!discdevs) { - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - - *_discdevs = discdevs; - - // Finally, if device is a hub, recurse - if (conn_info.DeviceIsHub) { - // Find number of ports for this hub - size = sizeof(USB_NODE_INFORMATION); - if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_INFORMATION, &hub_node, size, - &hub_node, size, &size, NULL)) { - usbi_warn(ctx, "could not retreive information for hub %s: %s", - priv->path, windows_error_str(0)); - continue; - } - - if (hub_node.NodeType != UsbHub) { - usbi_warn(ctx, "unexpected hub type (%d) for hub %s", hub_node.NodeType, priv->path); - continue; - } - - usbi_dbg("%d ports Hub: %s", hub_node.u.HubInformation.HubDescriptor.bNumberOfPorts, priv->path); - - usb_enumerate_hub(ctx, _discdevs, handle, busnum, dev, - hub_node.u.HubInformation.HubDescriptor.bNumberOfPorts); - } - } - - return r; -} - -/* - * Composite device interfaces are not enumerated using GUID_DEVINTERFACE_USB_DEVICE, - * but instead require a different lookup mechanism - */ -static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, struct windows_device_priv *priv) -{ -// indexes for additional interface GUIDs, not available from "USB" -// SetupDiGetClassDevs enumeration should go here. Typically, these are -// device interfaces that begin with something else than "\\?\usb\" -enum libusb_hid_report_type { - HID_DEVICE_INTERFACE_GUID_INDEX = 0, - MAX_DEVICE_INTERFACE_GUID_INDEX = 1 -}; - - DEVINST child_devinst, parent_devinst; - unsigned i, j, max_guids, nb_paths, interface_number; - uint8_t api; - bool found; - DWORD type, size; - CONFIGRET r; - HDEVINFO dev_info; - SP_DEVINFO_DATA dev_info_data; - SP_DEVICE_INTERFACE_DETAIL_DATA *dev_interface_details = NULL; - HKEY key; - WCHAR guid_string_w[MAX_GUID_STRING_LENGTH]; - GUID guid, class_guid; - GUID guid_table[MAX_USB_DEVICES]; - char* sanitized_path[MAX_USB_DEVICES]; - char* hid_path[MAX_USB_DEVICES]; // An extra path is needed for HID - uint8_t api_type[MAX_USB_DEVICES]; - char* sanitized_short = NULL; - char path[MAX_PATH_LENGTH]; - char driver[MAX_KEY_LENGTH]; - - dev_info = SetupDiGetClassDevs(NULL, "USB", NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES); - if (dev_info == INVALID_HANDLE_VALUE) { - return LIBUSB_ERROR_NOT_FOUND; - } - - // Manually add the HID GUID as it cannot be read with DeviceInterfaceGUIDs reg key) - // NB the value returned by HidD_GetHidGuid, which is for interface class is different - // from GUID_HID, which is the device class GUID - HidD_GetHidGuid(&guid_table[HID_DEVICE_INTERFACE_GUID_INDEX]); - // NB: for other interface guids, SetupDiClassGuidsFromName can be used - max_guids = MAX_DEVICE_INTERFACE_GUID_INDEX; - - // First, retrieve all the device interface GUIDs - for (i = 0; ; i++) - { - dev_info_data.cbSize = sizeof(dev_info_data); - if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) { - break; - } - - key = SetupDiOpenDevRegKey(dev_info, &dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); - if (key == INVALID_HANDLE_VALUE) { - usbi_dbg("could not open registry key"); - continue; - } - - size = sizeof(guid_string_w); - r = RegQueryValueExW(key, L"DeviceInterfaceGUIDs", NULL, &type, - (BYTE*)guid_string_w, &size); - RegCloseKey(key); - if (r != ERROR_SUCCESS) { - continue; - } - CLSIDFromString(guid_string_w, &guid); - - // identical device interface GUIDs are not supposed to happen, but are a real possibility - // => check and ignore duplicates - found = false; - for (j=0; j<max_guids; j++) { - if (memcmp(&guid_table[j], &guid, sizeof(GUID)) == 0) { - found = true; - break; - } - } - if (!found) { - guid_table[max_guids++] = guid; - if (max_guids > MAX_USB_DEVICES) { - usbi_warn(ctx, "more than %d devices - ignoring the rest", MAX_USB_DEVICES); - break; - } - } - } - SetupDiDestroyDeviceInfoList(dev_info); - - // Now let's find the device interface paths for all these devices - nb_paths = 0; - for (j=0; j<max_guids; j++) - { - guid = guid_table[j]; - - for (i = 0; ; i++) - { - safe_free(dev_interface_details); - dev_interface_details = get_interface_details(ctx, &dev_info, &dev_info_data, guid, i); - if (dev_interface_details == NULL) - break; - - // HID devices (and possibly other classes) have an extra indirection - // for an USB path we can recognize - if (j == HID_DEVICE_INTERFACE_GUID_INDEX) { - if (CM_Get_Parent(&parent_devinst, dev_info_data.DevInst, 0) != CR_SUCCESS) { - usbi_warn(ctx, "could not retrieve HID parent info data for device %s, skipping: %s", - dev_interface_details->DevicePath, windows_error_str(0)); - continue; - } - - if (CM_Get_Device_ID(parent_devinst, path, MAX_PATH_LENGTH, 0) != CR_SUCCESS) { - usbi_warn(ctx, "could not retrieve HID parent's path for device %s, skipping: %s", - dev_interface_details->DevicePath, windows_error_str(0)); - continue; - } - } - - // In case we can't read the driver string through SPDRP_SERVICE (which is - // the case for HID), we need the ClassGUID for comparison. - if(!SetupDiGetDeviceRegistryPropertyW(dev_info, &dev_info_data, SPDRP_CLASSGUID, - NULL, (BYTE*)guid_string_w, sizeof(guid_string_w), &size)) { - usbi_warn(ctx, "could not read class GUID for device %s, skipping: %s", - dev_interface_details->DevicePath, windows_error_str(0)); - continue; - } - CLSIDFromString(guid_string_w, &class_guid); - - // Attempt to read the driver string - if(!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, SPDRP_SERVICE, - NULL, (BYTE*)driver, MAX_KEY_LENGTH, &size)) { - driver[0] = 0; - } - - for (api=USB_API_WINUSB; api<USB_API_MAX; api++) { - if ( (is_api_driver(driver, api)) - || (guid_eq(&class_guid, usb_api_backend[api].class_guid)) ) { - api_type[nb_paths] = api; - if (j == HID_DEVICE_INTERFACE_GUID_INDEX) { - hid_path[nb_paths] = sanitize_path(path); - } else { - hid_path[nb_paths] = NULL; - } - sanitized_path[nb_paths++] = sanitize_path(dev_interface_details->DevicePath); - if (nb_paths > MAX_USB_DEVICES) { - usbi_warn(ctx, "more than %d devices - ignoring the rest", MAX_USB_DEVICES); - break; - } - } - } - } - } - - // Finally, match the interface paths with the interfaces. We do that - // by looking at the children of the composite device - // NB: if the interfaces are not found in their expected position, - // claim_interface will issue a warning - found = false; - memset(&child_devinst, 0, sizeof(DEVINST)); // prevents /W4 warning - for (i = 0; i<USB_MAXINTERFACES; i++) - { - if (i == 0) { - r = CM_Get_Child(&child_devinst, devinst, 0); - } else { - r = CM_Get_Sibling(&child_devinst, child_devinst, 0); - } - if (r == CR_NO_SUCH_DEVNODE) { // end of the siblings - break; - } else if (r != CR_SUCCESS) { - usbi_dbg("unable to find interface sibling #%d, error = %X", i, r); - break; - } - - r = CM_Get_Device_ID(child_devinst, path, MAX_PATH_LENGTH, 0); - if (r != CR_SUCCESS) { - usbi_err(ctx, "could not retrieve simple path for interface %d: CR error %d", - i, r); - continue; - } - sanitized_short = sanitize_path(path); - if (sanitized_short == NULL) { - usbi_err(ctx, "could not sanitize path for interface %d", i); - continue; - } - - // Because MI_## are not necessarily in sequential order (some composite HID - // devices will have only MI_00 & MI_03 for instance), we retrieve the actual - // interface number from the path's MI value - interface_number = i; - for (j=0; sanitized_short[j] != 0; ) { - if ( (sanitized_short[j++] == 'M') && (sanitized_short[j++] == 'I') - && (sanitized_short[j++] == '_') ) { - interface_number = (sanitized_short[j++] - '0')*10; - interface_number += sanitized_short[j] - '0'; - break; - } - } - if (sanitized_short[j] == 0) { - usbi_warn(ctx, "failure to read interface number for %s. Using default value %d", - sanitized_short, interface_number); - } - - for (j=0; j<nb_paths; j++) { - if ( (safe_strncmp(sanitized_path[j], sanitized_short, safe_strlen(sanitized_short)) == 0) - || (safe_strcmp(hid_path[j], sanitized_short) == 0 ) ) { - // HID devices can have multiple collections (COL##) for each MI_## interface - if (priv->usb_interface[interface_number].path != NULL) { - usbi_dbg("interface_path[%d] already set - ignoring HID collection: %s", - interface_number, sanitized_path[j]); - if (api_type[j] != USB_API_HID) { - usbi_warn(ctx, "program assertion failed - not an HID collection"); - } - } else { - priv->usb_interface[interface_number].path = sanitized_path[j]; - priv->usb_interface[interface_number].apib = &usb_api_backend[api_type[j]]; - if ((api_type[j] == USB_API_HID) && (priv->hid == NULL)) { - priv->hid = calloc(1, sizeof(struct hid_device_priv)); - } - priv->composite_api_flags |= 1<<api_type[j]; - sanitized_path[j] = NULL; - } - } - } - safe_free(sanitized_short); - - if (priv->usb_interface[interface_number].path == NULL) { - usbi_warn(ctx, "interface_path[%d]: unhandled API - interface will be disabled", - interface_number); - continue; - } - usbi_dbg("interface_path[%d]: %s", interface_number, priv->usb_interface[interface_number].path); - found = true; - } - - for (j=0; j<nb_paths; j++) { - safe_free(sanitized_path[j]); - safe_free(hid_path[j]); - } - - if (found == 0) { - usbi_warn(ctx, "composite device: no interfaces were found"); - return LIBUSB_ERROR_NOT_FOUND; - } - - return LIBUSB_SUCCESS; -} - -/* - * Likewise, HID device interfaces's path (\\.\HID\...) are not enumerated through the - * generic USB devices GUID, but are actually children of one such device - */ -static int set_hid_device(struct libusb_context *ctx, struct windows_device_priv *priv) - { - char path[MAX_PATH_LENGTH]; - char *sanitized_path = NULL; - HDEVINFO dev_info; - SP_DEVICE_INTERFACE_DETAIL_DATA *dev_interface_details = NULL; - SP_DEVINFO_DATA dev_info_data; - DEVINST parent_devinst; - GUID guid; - int r = LIBUSB_SUCCESS; - unsigned i, interface_number; - - interface_number = 0; - HidD_GetHidGuid(&guid); - for (i = 0; ; i++) - { - // safe loop: free up any (unprotected) dynamic resource - safe_free(dev_interface_details); - safe_free(sanitized_path); - - dev_interface_details = get_interface_details(ctx, &dev_info, &dev_info_data, guid, i); - // safe loop: end of loop condition - if ( (dev_interface_details == NULL) - || (r != LIBUSB_SUCCESS) ) - break; - - // Retrieve parent's path using PnP Configuration Manager (CM) - if (CM_Get_Parent(&parent_devinst, dev_info_data.DevInst, 0) != CR_SUCCESS) { - usbi_warn(ctx, "could not retrieve parent info data for device %s, skipping: %s", - dev_interface_details->DevicePath, windows_error_str(0)); - continue; - } - - if (CM_Get_Device_ID(parent_devinst, path, MAX_PATH_LENGTH, 0) != CR_SUCCESS) { - usbi_warn(ctx, "could not retrieve parent's path for device %s, skipping: %s", - dev_interface_details->DevicePath, windows_error_str(0)); - continue; - } - - // Fix parent's path inconsistencies before attempting to compare - sanitized_path = sanitize_path(path); - if (sanitized_path == NULL) { - usbi_warn(ctx, "could not sanitize parent's path for device %s, skipping.", - dev_interface_details->DevicePath); - continue; - } - - // NB: we compare strings of different lengths below => strncmp - if (safe_strncmp(priv->path, sanitized_path, safe_strlen(sanitized_path)) == 0) { - priv->usb_interface[interface_number].path = sanitize_path(dev_interface_details->DevicePath); - priv->usb_interface[interface_number].apib = &usb_api_backend[USB_API_HID]; - usbi_dbg("interface_path[%d]: %s", interface_number, priv->usb_interface[interface_number].path); - interface_number++; - } - } - - return LIBUSB_SUCCESS; -} - -/* - * This function retrieves and sets the paths of all non-hub devices - * NB: No I/O with device is required during this call - */ -static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *discdevs) -{ - // Precedence for filter drivers vs driver is in the order of this array - struct driver_lookup lookup[3] = { - {"\0\0", SPDRP_SERVICE, "driver"}, - {"\0\0", SPDRP_UPPERFILTERS, "upper filter driver"}, - {"\0\0", SPDRP_LOWERFILTERS, "lower filter driver"} - }; - struct windows_device_priv *priv; - struct windows_device_priv *parent_priv; - char path[MAX_PATH_LENGTH]; - char *sanitized_path = NULL; - HDEVINFO dev_info; - SP_DEVICE_INTERFACE_DETAIL_DATA *dev_interface_details = NULL; - SP_DEVINFO_DATA dev_info_data; - DEVINST parent_devinst; - GUID guid; - DWORD size, reg_type, install_state, port_nr; - int r = LIBUSB_SUCCESS; - unsigned i, j, k, l; - uint8_t api; - bool found; - - // TODO (after first official release): MI_## automated driver installation - guid = GUID_DEVINTERFACE_USB_DEVICE; - for (i = 0; ; i++) - { - // safe loop: free up any (unprotected) dynamic resource - safe_free(dev_interface_details); - safe_free(sanitized_path); - - dev_interface_details = get_interface_details(ctx, &dev_info, &dev_info_data, guid, i); - // safe loop: end of loop condition - if ( (dev_interface_details == NULL) - || (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; - } - - // The SPDRP_ADDRESS for USB devices should be the device port number on the hub - if ( (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, SPDRP_ADDRESS, - ®_type, (BYTE*)&port_nr, 4, &size)) - && (size != 4) ){ - usbi_warn(ctx, "could not retrieve port number for device %s, skipping: %s", - dev_interface_details->DevicePath, windows_error_str(0)); - continue; - } - - // Retrieve parent's path using PnP Configuration Manager (CM) - if (CM_Get_Parent(&parent_devinst, dev_info_data.DevInst, 0) != CR_SUCCESS) { - usbi_warn(ctx, "could not retrieve parent info data for device %s, skipping: %s", - dev_interface_details->DevicePath, windows_error_str(0)); - continue; - } - - if (CM_Get_Device_ID(parent_devinst, path, MAX_PATH_LENGTH, 0) != CR_SUCCESS) { - usbi_warn(ctx, "could not retrieve parent's path for device %s, skipping: %s", - dev_interface_details->DevicePath, windows_error_str(0)); - continue; - } - - // Fix parent's path inconsistencies before attempting to compare - sanitized_path = sanitize_path(path); - if (sanitized_path == NULL) { - usbi_warn(ctx, "could not sanitize parent's path for device %s, skipping.", - dev_interface_details->DevicePath); - continue; - } - - // With the parent path and port number, we should be able to locate our device - // by comparing these values to the ones we got when enumerating hubs - found = false; - for (j=0; j<discdevs->len; j++) { - priv = __device_priv(discdevs->devices[j]); - - if (priv->parent_dev == NULL) { - continue; // ignore HCDs - } - - parent_priv = __device_priv(priv->parent_dev); - - // NB: we compare strings of different lengths below => strncmp - if ( (safe_strncmp(parent_priv->path, sanitized_path, safe_strlen(sanitized_path)) == 0) - && (port_nr == priv->connection_index) ) { - - priv->path = sanitize_path(dev_interface_details->DevicePath); - - usbi_dbg("path (%d:%d): %s", discdevs->devices[j]->bus_number, - discdevs->devices[j]->device_address, priv->path); - - // Check the service & filter names to know the API we should use - for (k=0; k<3; k++) { - if (SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, lookup[k].reg_prop, - ®_type, (BYTE*)lookup[k].list, MAX_KEY_LENGTH, &size)) { - // Turn the REG_SZ SPDRP_SERVICE into REG_MULTI_SZ - if (lookup[k].reg_prop == SPDRP_SERVICE) { - // our buffers are MAX_KEY_LENGTH+1 so we can overflow if needed - lookup[k].list[safe_strlen(lookup[k].list)+1] = 0; - } - // MULTI_SZ is a pain to work with. Turn it into something much more manageable - // NB: none of the driver names we check against contain LIST_SEPARATOR, - // (currently ';'), so even if an unsuported one does, it's not an issue - for (l=0; (lookup[k].list[l] != 0) || (lookup[k].list[l+1] != 0); l++) { - if (lookup[k].list[l] == 0) { - lookup[k].list[l] = LIST_SEPARATOR; - } - } - upperize(lookup[k].list); - usbi_dbg("%s(s): %s", lookup[k].designation, lookup[k].list); - found = true; - } else { - if (GetLastError() != ERROR_INVALID_DATA) { - usbi_dbg("could not access %s: %s", lookup[k].designation, windows_error_str(0)); - } - lookup[k].list[0] = 0; - } - } - - for (api=0; api<USB_API_MAX; api++) { - for (k=0; k<3; k++) { - if (is_api_driver(lookup[k].list, api)) { - usbi_dbg("matched %s name against %s", lookup[k].designation, usb_api_backend[api].designation); - break; - } - } - if (k >= 3) continue; - priv->apib = &usb_api_backend[api]; - switch(api) { - case USB_API_COMPOSITE: - set_composite_device(ctx, dev_info_data.DevInst, priv); - break; - case USB_API_HID: - safe_free(priv->hid); - priv->hid = calloc(1, sizeof(struct hid_device_priv)); - if (priv->hid == NULL) { - usbi_err(ctx, "could not allocate HID data for %s, skipping", - dev_interface_details->DevicePath); - priv->apib = &usb_api_backend[USB_API_UNSUPPORTED]; - safe_free(priv->path); - } else { - set_hid_device(ctx, priv); - } - break; - default: - // For other devices, the first interface is the same as the device - priv->usb_interface[0].path = malloc(safe_strlen(priv->path)+1); - if (priv->usb_interface[0].path != NULL) { - safe_strcpy(priv->usb_interface[0].path, safe_strlen(priv->path)+1, priv->path); - } - // The following is needed if we want to API calls to work for both simple - // and composite devices, as - for(k=0; k<USB_MAXINTERFACES; k++) { - priv->usb_interface[k].apib = &usb_api_backend[api]; - } - break; - } - } - break; - } - } - if (!found) { - usbi_warn(ctx, "could not match %s with a libusb device.", dev_interface_details->DevicePath); - continue; - } - } - - return LIBUSB_SUCCESS; -} - -/* - * get_device_list: libusb backend device enumeration function - */ -static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs) -{ - struct windows_hcd_priv* hcd; - HANDLE handle = INVALID_HANDLE_VALUE; - int r = LIBUSB_SUCCESS; - libusb_bus_t bus; - - // Use the index of the HCD in the chained list as bus # - for (hcd = hcd_root, bus = 0; ; hcd = hcd->next, bus++) - { - safe_closehandle(handle); - - if ( (hcd == NULL) || (r != LIBUSB_SUCCESS) ) - break; - - if (bus == LIBUSB_BUS_MAX) { - usbi_warn(ctx, "program assertion failed - got more than %d buses, skipping the rest.", LIBUSB_BUS_MAX); - continue; - } - - handle = CreateFileA(hcd->path, GENERIC_WRITE, FILE_SHARE_WRITE, - 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)); - continue; - } - - LOOP_CHECK(usb_enumerate_hub(ctx, _discdevs, handle, bus, NULL, 1)); - } - - // Set the interface path for non-hubs - r = set_device_paths(ctx, *_discdevs); - - return r; -} - -/* - * exit: libusb backend deinitialization function - */ -static void windows_exit(void) -{ - struct windows_hcd_priv* hcd_tmp; - int i; - HANDLE semaphore; - TCHAR sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID) - - sprintf(sem_name, "libusb_init%08X", (unsigned int)GetCurrentProcessId()&0xFFFFFFFF); - semaphore = CreateSemaphore(NULL, 1, 1, sem_name); - if (semaphore == NULL) { - return; - } - - // A successful wait brings our semaphore count to 0 (unsignaled) - // => any concurent wait stalls until the semaphore release - if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { - CloseHandle(semaphore); - return; - } - - // Only works if exits and inits are balanced exactly - if (--concurrent_usage < 0) { // Last exit - while (hcd_root != NULL) - { - hcd_tmp = hcd_root; // Keep a copy for free - hcd_root = hcd_root->next; - windows_hcd_priv_release(hcd_tmp); - safe_free(hcd_tmp); - } - - for (i=0; i<USB_API_MAX; i++) { - usb_api_backend[i].exit(); - } - exit_polling(); - - if (timer_thread) { - SetEvent(timer_request[1]); // actually the signal to quit the thread. - if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) { - usbi_dbg("could not wait for timer thread to quit"); - TerminateThread(timer_thread, 1); - } - CloseHandle(timer_thread); - timer_thread = NULL; - } - for (i = 0; i < 2; i++) { - if (timer_request[i]) { - CloseHandle(timer_request[i]); - timer_request[i] = NULL; - } - } - if (timer_response) { - CloseHandle(timer_response); - timer_response = NULL; - } - if (timer_mutex) { - CloseHandle(timer_mutex); - timer_mutex = NULL; - } - } - - ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 - CloseHandle(semaphore); -} - -static int windows_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian) -{ - struct windows_device_priv *priv = __device_priv(dev); - - memcpy(buffer, &(priv->dev_descriptor), DEVICE_DESC_LENGTH); - *host_endian = 0; - - return LIBUSB_SUCCESS; -} - -static int windows_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) -{ - struct windows_device_priv *priv = __device_priv(dev); - PUSB_CONFIGURATION_DESCRIPTOR config_header; - size_t size; - - // config index is zero based - if (config_index >= dev->num_configurations) - return LIBUSB_ERROR_INVALID_PARAM; - - if ((priv->config_descriptor == NULL) || (priv->config_descriptor[config_index] == NULL)) - return LIBUSB_ERROR_NOT_FOUND; - - config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptor[config_index]; - - size = min(config_header->wTotalLength, len); - memcpy(buffer, priv->config_descriptor[config_index], size); - - return LIBUSB_SUCCESS; -} - -/* - * return the cached copy of the active config descriptor - */ -static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) -{ - struct windows_device_priv *priv = __device_priv(dev); - - if (priv->active_config == 0) - return LIBUSB_ERROR_NOT_FOUND; - - // config index is zero based - return windows_get_config_descriptor(dev, (uint8_t)(priv->active_config-1), buffer, len, host_endian); -} - -static int windows_open(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - - if (priv->apib == NULL) { - usbi_err(ctx, "program assertion failed - device is not initialized"); - return LIBUSB_ERROR_NO_DEVICE; - } - - return priv->apib->open(dev_handle); -} - -static void windows_close(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - - priv->apib->close(dev_handle); -} - -static int windows_get_configuration(struct libusb_device_handle *dev_handle, int *config) -{ - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - - if (priv->active_config == 0) { - *config = 0; - return LIBUSB_ERROR_NOT_FOUND; - } - - *config = priv->active_config; - return LIBUSB_SUCCESS; -} - -/* - * from http://msdn.microsoft.com/en-us/library/ms793522.aspx: "The port driver - * does not currently expose a service that allows higher-level drivers to set - * the configuration." - */ -static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config) -{ - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - int r = LIBUSB_SUCCESS; - - if (config >= USB_MAXCONFIG) - return LIBUSB_ERROR_INVALID_PARAM; - - r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_OUT | - LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, - LIBUSB_REQUEST_SET_CONFIGURATION, (uint16_t)config, - 0, NULL, 0, 1000); - - if (r == LIBUSB_SUCCESS) { - priv->active_config = (uint8_t)config; - } - return r; -} - -static int windows_claim_interface(struct libusb_device_handle *dev_handle, int iface) -{ - int r = LIBUSB_SUCCESS; - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - - if (iface >= USB_MAXINTERFACES) - return LIBUSB_ERROR_INVALID_PARAM; - - safe_free(priv->usb_interface[iface].endpoint); - priv->usb_interface[iface].nb_endpoints= 0; - - r = priv->apib->claim_interface(dev_handle, iface); - - if (r == LIBUSB_SUCCESS) { - r = windows_assign_endpoints(dev_handle->dev, iface, 0); - } - - return r; -} - -static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - int r = LIBUSB_SUCCESS; - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - - safe_free(priv->usb_interface[iface].endpoint); - priv->usb_interface[iface].nb_endpoints= 0; - - r = priv->apib->set_interface_altsetting(dev_handle, iface, altsetting); - - if (r == LIBUSB_SUCCESS) { - r = windows_assign_endpoints(dev_handle->dev, iface, altsetting); - } - - return r; -} - -static int windows_release_interface(struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - - windows_set_interface_altsetting(dev_handle, iface, 0); - return priv->apib->release_interface(dev_handle, iface); -} - -static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) -{ - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - return priv->apib->clear_halt(dev_handle, endpoint); -} - -static int windows_reset_device(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - return priv->apib->reset_device(dev_handle); -} - -// The 3 functions below are unlikely to ever get supported on Windows -static int windows_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface) -{ - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static int windows_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) -{ - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static int windows_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) -{ - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static void windows_destroy_device(struct libusb_device *dev) -{ - struct windows_device_priv *priv = __device_priv(dev); - windows_device_priv_release(priv, dev->num_configurations); -} - -static void windows_clear_transfer_priv(struct usbi_transfer *itransfer) -{ - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - - usbi_free_fd(transfer_priv->pollable_fd.fd); - safe_free(transfer_priv->hid_buffer); -#if defined(AUTO_CLAIM) - // When auto claim is in use, attempt to release the auto-claimed interface - auto_release(itransfer); -#endif -} - -static int 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_priv *priv = __device_priv(transfer->dev_handle->dev); - int r; - - r = priv->apib->submit_bulk_transfer(itransfer); - if (r != LIBUSB_SUCCESS) { - return r; - } - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, - (short)((transfer->endpoint & LIBUSB_ENDPOINT_IN)?POLLIN:POLLOUT)); -#if !defined(DYNAMIC_FDS) - usbi_fd_notification(ctx); -#endif - - return LIBUSB_SUCCESS; -} - -static int 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_priv *priv = __device_priv(transfer->dev_handle->dev); - int r; - - r = priv->apib->submit_iso_transfer(itransfer); - if (r != LIBUSB_SUCCESS) { - return r; - } - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, - (short)((transfer->endpoint & LIBUSB_ENDPOINT_IN)?POLLIN:POLLOUT)); -#if !defined(DYNAMIC_FDS) - usbi_fd_notification(ctx); -#endif - - return LIBUSB_SUCCESS; -} - -static int 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_priv *priv = __device_priv(transfer->dev_handle->dev); - int r; - - r = priv->apib->submit_control_transfer(itransfer); - if (r != LIBUSB_SUCCESS) { - return r; - } - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN); -#if !defined(DYNAMIC_FDS) - usbi_fd_notification(ctx); -#endif - - return LIBUSB_SUCCESS; - -} - -static int windows_submit_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return submit_control_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - return submit_bulk_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return submit_iso_transfer(itransfer); - default: - usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static int windows_abort_control(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev); - - return priv->apib->abort_control(itransfer); -} - -static int windows_abort_transfers(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev); - - return priv->apib->abort_transfers(itransfer); -} - -static int windows_cancel_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); -#if defined(FORCE_INSTANT_TIMEOUTS) - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - - // Forces instant overlapped completion on timeouts - use at your own risks - if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) { - transfer_priv->pollable_fd.overlapped->Internal &= ~STATUS_PENDING; - } -#endif - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return windows_abort_control(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return windows_abort_transfers(itransfer); - default: - usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static void windows_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size) -{ - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev); - int status; - - usbi_dbg("handling I/O completion with errcode %d", io_result); - - switch(io_result) { - case NO_ERROR: - status = priv->apib->copy_transfer_data(itransfer, io_size); - break; - case ERROR_GEN_FAILURE: - usbi_dbg("detected endpoint stall"); - status = LIBUSB_TRANSFER_STALL; - break; - case ERROR_SEM_TIMEOUT: - usbi_dbg("detected semaphore timeout"); - status = LIBUSB_TRANSFER_TIMED_OUT; - break; - case ERROR_OPERATION_ABORTED: - if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) { - usbi_dbg("detected timeout"); - status = LIBUSB_TRANSFER_TIMED_OUT; - } else { - usbi_dbg("detected operation aborted"); - status = LIBUSB_TRANSFER_CANCELLED; - } - break; - default: - usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error: %s", windows_error_str(0)); - status = LIBUSB_TRANSFER_ERROR; - break; - } - windows_clear_transfer_priv(itransfer); // Cancel polling - usbi_handle_transfer_completion(itransfer, status); -} - -static void windows_handle_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size) -{ - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - windows_transfer_callback (itransfer, io_result, io_size); - break; - default: - usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); - } -} - -static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, nfds_t nfds, int num_ready) -{ - struct windows_transfer_priv* transfer_priv = NULL; - nfds_t i = 0; - bool found = false; - struct usbi_transfer *transfer; - DWORD io_size, io_result; - - usbi_mutex_lock(&ctx->open_devs_lock); - for (i = 0; i < nfds && num_ready > 0; i++) { - - usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents); - - if (!fds[i].revents) { - continue; - } - - num_ready--; - - // Because a Windows OVERLAPPED is used for poll emulation, - // a pollable fd is created and stored with each transfer - usbi_mutex_lock(&ctx->flying_transfers_lock); - list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { - transfer_priv = usbi_transfer_get_os_priv(transfer); - if (transfer_priv->pollable_fd.fd == fds[i].fd) { - found = true; - break; - } - } - usbi_mutex_unlock(&ctx->flying_transfers_lock); - - if (found) { - // Handle async requests that completed synchronously first - if (HasOverlappedIoCompletedSync(transfer_priv->pollable_fd.overlapped)) { - io_result = NO_ERROR; - io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh; - // Regular async overlapped - } else if (GetOverlappedResult(transfer_priv->pollable_fd.handle, - transfer_priv->pollable_fd.overlapped, &io_size, false)) { - io_result = NO_ERROR; - } else { - io_result = GetLastError(); - } - usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd); - // let handle_callback free the event using the transfer wfd - // If you don't use the transfer wfd, you run a risk of trying to free a - // newly allocated wfd that took the place of the one from the transfer. - windows_handle_callback(transfer, io_result, io_size); - } else { - usbi_err(ctx, "could not find a matching transfer for fd %x", fds[i]); - return LIBUSB_ERROR_NOT_FOUND; - } - } - - usbi_mutex_unlock(&ctx->open_devs_lock); - return LIBUSB_SUCCESS; -} - -/* - * Monotonic and real time functions - */ -unsigned __stdcall windows_clock_gettime_threaded(void* param) -{ - LARGE_INTEGER hires_counter, li_frequency; - LONG nb_responses; - int timer_index; - - // Init - find out if we have access to a monotonic (hires) timer - if (!QueryPerformanceFrequency(&li_frequency)) { - usbi_dbg("no hires timer available on this platform"); - hires_frequency = 0; - hires_ticks_to_ps = UINT64_C(0); - } else { - 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 = UINT64_C(1000000000000) / hires_frequency; - usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency); - } - - // Main loop - wait for requests - while (1) { - timer_index = WaitForMultipleObjects(2, timer_request, FALSE, INFINITE) - WAIT_OBJECT_0; - if ( (timer_index != 0) && (timer_index != 1) ) { - usbi_dbg("failure to wait on requests: %s", windows_error_str(0)); - continue; - } - if (request_count[timer_index] == 0) { - // Request already handled - ResetEvent(timer_request[timer_index]); - // There's still a possiblity that a thread sends a request between the - // time we test request_count[] == 0 and we reset the event, in which case - // the request would be ignored. The simple solution to that is to test - // request_count again and process requests if non zero. - if (request_count[timer_index] == 0) - continue; - } - switch (timer_index) { - case 0: - WaitForSingleObject(timer_mutex, INFINITE); - // Requests to this thread are for hires always - if (QueryPerformanceCounter(&hires_counter) != 0) { - timer_tp.tv_sec = (long)(hires_counter.QuadPart / hires_frequency); - timer_tp.tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency)/1000) * hires_ticks_to_ps); - } else { - // Fallback to real-time if we can't get monotonic value - // Note that real-time clock does not wait on the mutex or this thread. - windows_clock_gettime(USBI_CLOCK_REALTIME, &timer_tp); - } - ReleaseMutex(timer_mutex); - - nb_responses = InterlockedExchange((LONG*)&request_count[0], 0); - if ( (nb_responses) - && (ReleaseSemaphore(timer_response, nb_responses, NULL) == 0) ) { - usbi_dbg("unable to release timer semaphore %d: %s", windows_error_str(0)); - } - continue; - case 1: // time to quit - usbi_dbg("timer thread quitting"); - return 0; - } - } - usbi_dbg("ERROR: broken timer thread"); - return 1; -} - -static int windows_clock_gettime(int clk_id, struct timespec *tp) -{ - FILETIME filetime; - ULARGE_INTEGER rtime; - DWORD r; - switch(clk_id) { - case USBI_CLOCK_MONOTONIC: - if (hires_frequency != 0) { - while (1) { - InterlockedIncrement((LONG*)&request_count[0]); - SetEvent(timer_request[0]); - r = WaitForSingleObject(timer_response, TIMER_REQUEST_RETRY_MS); - switch(r) { - case WAIT_OBJECT_0: - WaitForSingleObject(timer_mutex, INFINITE); - *tp = timer_tp; - ReleaseMutex(timer_mutex); - return LIBUSB_SUCCESS; - case WAIT_TIMEOUT: - usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?"); - break; // Retry until successful - default: - usbi_dbg("WaitForSingleObject failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_OTHER; - } - } - } - // Fall through and return real-time if monotonic was not detected @ timer init - case USBI_CLOCK_REALTIME: - // We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx - // with a predef epoch_time to have an epoch that starts at 1970.01.01 00:00 - // Note however that our resolution is bounded by the Windows system time - // functions and is at best of the order of 1 ms (or, usually, worse) - GetSystemTimeAsFileTime(&filetime); - rtime.LowPart = filetime.dwLowDateTime; - rtime.HighPart = filetime.dwHighDateTime; - rtime.QuadPart -= epoch_time; - tp->tv_sec = (long)(rtime.QuadPart / 10000000); - tp->tv_nsec = (long)((rtime.QuadPart % 10000000)*100); - return LIBUSB_SUCCESS; - default: - return LIBUSB_ERROR_INVALID_PARAM; - } -} - - -// NB: MSVC6 does not support named initializers. -const struct usbi_os_backend windows_backend = { - "Windows", - windows_init, - windows_exit, - - windows_get_device_list, - windows_open, - windows_close, - - windows_get_device_descriptor, - windows_get_active_config_descriptor, - windows_get_config_descriptor, - - windows_get_configuration, - windows_set_configuration, - windows_claim_interface, - windows_release_interface, - - windows_set_interface_altsetting, - windows_clear_halt, - windows_reset_device, - - windows_kernel_driver_active, - windows_detach_kernel_driver, - windows_attach_kernel_driver, - - windows_destroy_device, - - windows_submit_transfer, - windows_cancel_transfer, - windows_clear_transfer_priv, - - windows_handle_events, - - windows_clock_gettime, -#if defined(USBI_TIMERFD_AVAILABLE) - NULL, -#endif - sizeof(struct windows_device_priv), - sizeof(struct windows_device_handle_priv), - sizeof(struct windows_transfer_priv), - 0, -}; - - -/* - * USB API backends - */ -static int unsupported_init(struct libusb_context *ctx) { - return LIBUSB_SUCCESS; -} -static int unsupported_exit(void) { - return LIBUSB_SUCCESS; -} -static int unsupported_open(struct libusb_device_handle *dev_handle) { - PRINT_UNSUPPORTED_API(open); -} -static void unsupported_close(struct libusb_device_handle *dev_handle) { - usbi_dbg("unsupported API call for 'close'"); -} -static int unsupported_claim_interface(struct libusb_device_handle *dev_handle, int iface) { - PRINT_UNSUPPORTED_API(claim_interface); -} -static int unsupported_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) { - PRINT_UNSUPPORTED_API(set_interface_altsetting); -} -static int unsupported_release_interface(struct libusb_device_handle *dev_handle, int iface) { - PRINT_UNSUPPORTED_API(release_interface); -} -static int unsupported_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) { - PRINT_UNSUPPORTED_API(clear_halt); -} -static int unsupported_reset_device(struct libusb_device_handle *dev_handle) { - PRINT_UNSUPPORTED_API(reset_device); -} -static int unsupported_submit_bulk_transfer(struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(submit_bulk_transfer); -} -static int unsupported_submit_iso_transfer(struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(submit_iso_transfer); -} -static int unsupported_submit_control_transfer(struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(submit_control_transfer); -} -static int unsupported_abort_control(struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(abort_control); -} -static int unsupported_abort_transfers(struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(abort_transfers); -} -static int unsupported_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) { - PRINT_UNSUPPORTED_API(copy_transfer_data); -} - -// These names must be uppercase -const char* composite_driver_names[] = {"USBCCGP"}; -const char* winusb_driver_names[] = {"WINUSB"}; -const char* hid_driver_names[] = {"HIDUSB", "MOUHID", "KBDHID"}; -const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { - { - USB_API_UNSUPPORTED, - "Unsupported API", - &CLASS_GUID_UNSUPPORTED, - NULL, - 0, - unsupported_init, - unsupported_exit, - unsupported_open, - unsupported_close, - unsupported_claim_interface, - unsupported_set_interface_altsetting, - unsupported_release_interface, - unsupported_clear_halt, - unsupported_reset_device, - unsupported_submit_bulk_transfer, - unsupported_submit_iso_transfer, - unsupported_submit_control_transfer, - unsupported_abort_control, - unsupported_abort_transfers, - unsupported_copy_transfer_data, - }, { - USB_API_COMPOSITE, - "Composite API", - &CLASS_GUID_COMPOSITE, - composite_driver_names, - sizeof(composite_driver_names)/sizeof(composite_driver_names[0]), - composite_init, - composite_exit, - composite_open, - composite_close, - composite_claim_interface, - composite_set_interface_altsetting, - composite_release_interface, - composite_clear_halt, - composite_reset_device, - composite_submit_bulk_transfer, - composite_submit_iso_transfer, - composite_submit_control_transfer, - composite_abort_control, - composite_abort_transfers, - composite_copy_transfer_data, - }, { - USB_API_WINUSB, - "WinUSB API", - &CLASS_GUID_LIBUSB_WINUSB, - winusb_driver_names, - sizeof(winusb_driver_names)/sizeof(winusb_driver_names[0]), - winusb_init, - winusb_exit, - winusb_open, - winusb_close, - winusb_claim_interface, - winusb_set_interface_altsetting, - winusb_release_interface, - winusb_clear_halt, - winusb_reset_device, - winusb_submit_bulk_transfer, - unsupported_submit_iso_transfer, - winusb_submit_control_transfer, - winusb_abort_control, - winusb_abort_transfers, - winusb_copy_transfer_data, - }, { - USB_API_HID, - "HID API", - &CLASS_GUID_HID, - hid_driver_names, - sizeof(hid_driver_names)/sizeof(hid_driver_names[0]), - hid_init, - hid_exit, - hid_open, - hid_close, - hid_claim_interface, - hid_set_interface_altsetting, - hid_release_interface, - hid_clear_halt, - hid_reset_device, - hid_submit_bulk_transfer, - unsupported_submit_iso_transfer, - hid_submit_control_transfer, - hid_abort_transfers, - hid_abort_transfers, - hid_copy_transfer_data, - }, -}; - - -/* - * WinUSB API functions - */ -static int winusb_init(struct libusb_context *ctx) -{ - DLL_LOAD(winusb.dll, WinUsb_Initialize, TRUE); - DLL_LOAD(winusb.dll, WinUsb_Free, TRUE); - DLL_LOAD(winusb.dll, WinUsb_GetAssociatedInterface, TRUE); - DLL_LOAD(winusb.dll, WinUsb_GetDescriptor, TRUE); - DLL_LOAD(winusb.dll, WinUsb_QueryInterfaceSettings, TRUE); - DLL_LOAD(winusb.dll, WinUsb_QueryDeviceInformation, TRUE); - DLL_LOAD(winusb.dll, WinUsb_SetCurrentAlternateSetting, TRUE); - DLL_LOAD(winusb.dll, WinUsb_GetCurrentAlternateSetting, TRUE); - DLL_LOAD(winusb.dll, WinUsb_QueryPipe, TRUE); - DLL_LOAD(winusb.dll, WinUsb_SetPipePolicy, TRUE); - DLL_LOAD(winusb.dll, WinUsb_GetPipePolicy, TRUE); - DLL_LOAD(winusb.dll, WinUsb_ReadPipe, TRUE); - DLL_LOAD(winusb.dll, WinUsb_WritePipe, TRUE); - DLL_LOAD(winusb.dll, WinUsb_ControlTransfer, TRUE); - DLL_LOAD(winusb.dll, WinUsb_ResetPipe, TRUE); - DLL_LOAD(winusb.dll, WinUsb_AbortPipe, TRUE); - DLL_LOAD(winusb.dll, WinUsb_FlushPipe, TRUE); - - api_winusb_available = true; - return LIBUSB_SUCCESS; -} - -static int winusb_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 winusb_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 = __device_handle_priv(dev_handle); - - HANDLE file_handle; - int i; - - CHECK_WINUSB_AVAILABLE; - - // WinUSB requires a seperate handle for each interface - for (i = 0; i < USB_MAXINTERFACES; i++) { - if ( (priv->usb_interface[i].path != NULL) - && (priv->usb_interface[i].apib->id == USB_API_WINUSB) ) { - file_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); - if (file_handle == INVALID_HANDLE_VALUE) { - usbi_err(ctx, "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, 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[i].dev_handle = file_handle; - } - } - - return LIBUSB_SUCCESS; -} - -static void winusb_close(struct libusb_device_handle *dev_handle) -{ - struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle); - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - HANDLE file_handle; - int i; - - if (!api_winusb_available) - return; - - for (i = 0; i < USB_MAXINTERFACES; i++) { - if (priv->usb_interface[i].apib->id == USB_API_WINUSB) { - file_handle = handle_priv->interface_handle[i].dev_handle; - if ( (file_handle != 0) && (file_handle != INVALID_HANDLE_VALUE)) { - CloseHandle(file_handle); - } - } - } -} - -static int winusb_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 = __device_handle_priv(dev_handle); - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - bool is_composite = (priv->apib->id == USB_API_COMPOSITE); - HANDLE file_handle, winusb_handle; - USB_INTERFACE_DESCRIPTOR if_desc; - UCHAR policy; - uint8_t endpoint_address; - int i; - - CHECK_WINUSB_AVAILABLE; - - // interfaces for composite devices are always independent, therefore - // "alt" interfaces are only found on non-composite - if ((!is_composite) && (iface != 0)) { - winusb_handle = handle_priv->interface_handle[0].api_handle; - // 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 ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) { -#if defined(AUTO_CLAIM) - file_handle = handle_priv->interface_handle[0].dev_handle; - if (WinUsb_Initialize(file_handle, &winusb_handle)) { - handle_priv->interface_handle[0].api_handle = winusb_handle; - usbi_warn(ctx, "auto-claimed interface 0 (required to claim %d with WinUSB)", iface); - } else { - usbi_warn(ctx, "failed to auto-claim interface 0 (required to claim %d with WinUSB)", iface); - return LIBUSB_ERROR_ACCESS; - } -#else - usbi_warn(ctx, "you must claim interface 0 before you can claim %d with WinUSB", iface); - return LIBUSB_ERROR_ACCESS; -#endif - } - if (!WinUsb_GetAssociatedInterface(winusb_handle, (UCHAR)(iface-1), - &handle_priv->interface_handle[iface].api_handle)) { - handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; - switch(GetLastError()) { - case ERROR_NO_MORE_ITEMS: // invalid iface - return LIBUSB_ERROR_NOT_FOUND; - case ERROR_BAD_COMMAND: // The device was disconnected - return LIBUSB_ERROR_NO_DEVICE; - case ERROR_ALREADY_EXISTS: // already claimed - return LIBUSB_ERROR_BUSY; - default: - usbi_err(ctx, "could not claim interface %d: %s", iface, windows_error_str(0)); - return LIBUSB_ERROR_ACCESS; - } - } - } else { - // composite device (independent interfaces) or interface 0 - winusb_handle = handle_priv->interface_handle[iface].api_handle; - file_handle = handle_priv->interface_handle[iface].dev_handle; - if ((file_handle == 0) || (file_handle == INVALID_HANDLE_VALUE)) { - return LIBUSB_ERROR_NOT_FOUND; - } - - if (!WinUsb_Initialize(file_handle, &winusb_handle)) { - usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(0)); - handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; - - switch(GetLastError()) { - case ERROR_BAD_COMMAND: // The device was disconnected - return LIBUSB_ERROR_NO_DEVICE; - default: - usbi_err(ctx, "could not claim interface %d: %s", iface, windows_error_str(0)); - return LIBUSB_ERROR_ACCESS; - } - } - handle_priv->interface_handle[iface].api_handle = winusb_handle; - } - if (!WinUsb_QueryInterfaceSettings(winusb_handle, 0, &if_desc)) { - usbi_err(ctx, "could not query interface settings for interface %d: %s", iface, windows_error_str(0)); - } else if (if_desc.bInterfaceNumber != iface) { - usbi_warn(ctx, "program assertion failed - WinUSB interface %d found at position %d", - if_desc.bInterfaceNumber, iface); - } - - usbi_dbg("claimed interface %d", iface); - handle_priv->active_interface = iface; - - // With handle and enpoints set (in parent), we can setup the default - // pipe properties (copied from libusb-win32-v1) - // see http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DVC-T705_DDC08.pptx - for (i=0; i<priv->usb_interface[iface].nb_endpoints; i++) { - endpoint_address = priv->usb_interface[iface].endpoint[i]; - policy = false; - if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address, - SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy)) { - usbi_dbg("failed to disable SHORT_PACKET_TERMINATE for endpoint %02X", endpoint_address); - } - if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address, - IGNORE_SHORT_PACKETS, sizeof(UCHAR), &policy)) { - usbi_dbg("failed to disable IGNORE_SHORT_PACKETS for endpoint %02X", endpoint_address); - } - if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address, - ALLOW_PARTIAL_READS, sizeof(UCHAR), &policy)) { - usbi_dbg("failed to disable ALLOW_PARTIAL_READS for endpoint %02X", endpoint_address); - } - policy = true; - if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address, - AUTO_CLEAR_STALL, sizeof(UCHAR), &policy)) { - usbi_dbg("failed to enable AUTO_CLEAR_STALL for endpoint %02X", endpoint_address); - } - } - - return LIBUSB_SUCCESS; -} - -static int winusb_release_interface(struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle); - HANDLE winusb_handle; - - CHECK_WINUSB_AVAILABLE; - - winusb_handle = handle_priv->interface_handle[iface].api_handle; - if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) { - return LIBUSB_ERROR_NOT_FOUND; - } - - WinUsb_Free(winusb_handle); - handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; - - return LIBUSB_SUCCESS; -} - -/* - * Return the first valid interface (of the same API type), for control transfers - */ -static int get_valid_interface(struct libusb_device_handle *dev_handle, int api_id) -{ - struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle); - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - int i; - - if ((api_id < USB_API_WINUSB) || (api_id > USB_API_HID)) { - usbi_dbg("unsupported API ID"); - return -1; - } - - for (i=0; i<USB_MAXINTERFACES; i++) { - if ( (handle_priv->interface_handle[i].dev_handle != 0) - && (handle_priv->interface_handle[i].dev_handle != INVALID_HANDLE_VALUE) - && (handle_priv->interface_handle[i].api_handle != 0) - && (handle_priv->interface_handle[i].api_handle != INVALID_HANDLE_VALUE) - && (priv->usb_interface[i].apib == &usb_api_backend[api_id]) ) { - return i; - } - } - return -1; -} - -/* - * Lookup interface by endpoint address. -1 if not found - */ -static int interface_by_endpoint(struct windows_device_priv *priv, - struct windows_device_handle_priv *handle_priv, uint8_t endpoint_address) -{ - int i, j; - for (i=0; i<USB_MAXINTERFACES; i++) { - if (handle_priv->interface_handle[i].api_handle == INVALID_HANDLE_VALUE) - continue; - if (handle_priv->interface_handle[i].api_handle == 0) - continue; - if (priv->usb_interface[i].endpoint == NULL) - continue; - for (j=0; j<priv->usb_interface[i].nb_endpoints; j++) { - if (priv->usb_interface[i].endpoint[j] == endpoint_address) { - return i; - } - } - } - return -1; -} - -static int winusb_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 = __device_handle_priv( - transfer->dev_handle); - WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *) transfer->buffer; - ULONG size; - HANDLE winusb_handle; - int current_interface; - struct winfd wfd; - - CHECK_WINUSB_AVAILABLE; - - transfer_priv->pollable_fd = INVALID_WINFD; - 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, USB_API_WINUSB); - if (current_interface < 0) { -#if defined(AUTO_CLAIM) - if (auto_claim(transfer, ¤t_interface, USB_API_WINUSB) != LIBUSB_SUCCESS) { - return LIBUSB_ERROR_NOT_FOUND; - } -#else - usbi_warn(ctx, "no interface available for control transfer"); - return LIBUSB_ERROR_NOT_FOUND; -#endif - } - - usbi_dbg("will use interface %d", current_interface); - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - wfd = usbi_create_fd(winusb_handle, _O_RDONLY); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) { - return LIBUSB_ERROR_NO_MEM; - } - - if (!WinUsb_ControlTransfer(wfd.handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, wfd.overlapped)) { - if(GetLastError() != ERROR_IO_PENDING) { - usbi_err(ctx, "WinUsb_ControlTransfer failed: %s", windows_error_str(0)); - usbi_free_fd(wfd.fd); - return LIBUSB_ERROR_IO; - } - } else { - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - 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 winusb_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 = __device_handle_priv(dev_handle); - HANDLE winusb_handle; - - CHECK_WINUSB_AVAILABLE; - - if (altsetting > 255) { - return LIBUSB_ERROR_INVALID_PARAM; - } - - winusb_handle = handle_priv->interface_handle[iface].api_handle; - if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) { - usbi_err(ctx, "interface must be claimed first"); - return LIBUSB_ERROR_NOT_FOUND; - } - - if (!WinUsb_SetCurrentAlternateSetting(winusb_handle, (UCHAR)altsetting)) { - usbi_err(ctx, "WinUsb_SetCurrentAlternateSetting failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_IO; - } - - return LIBUSB_SUCCESS; -} - -static int winusb_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 = __device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev); - HANDLE winusb_handle; - bool direction_in, ret; - int current_interface; - struct winfd wfd; - - CHECK_WINUSB_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); - - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN; - - wfd = usbi_create_fd(winusb_handle, direction_in?_O_RDONLY:_O_WRONLY); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) { - return LIBUSB_ERROR_NO_MEM; - } - - if (direction_in) { - usbi_dbg("reading %d bytes", transfer->length); - ret = WinUsb_ReadPipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); - } else { - usbi_dbg("writing %d bytes", transfer->length); - ret = WinUsb_WritePipe(wfd.handle, transfer->endpoint, 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.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = (DWORD)transfer->length; - } - - transfer_priv->pollable_fd = wfd; - transfer_priv->interface_number = (uint8_t)current_interface; - - return LIBUSB_SUCCESS; -} - -static int winusb_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 = __device_handle_priv(dev_handle); - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - HANDLE winusb_handle; - int current_interface; - - CHECK_WINUSB_AVAILABLE; - - current_interface = interface_by_endpoint(priv, handle_priv, endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface); - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - if (!WinUsb_ResetPipe(winusb_handle, endpoint)) { - usbi_err(ctx, "WinUsb_ResetPipe failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_NO_DEVICE; - } - - return LIBUSB_SUCCESS; -} - -/* - * from http://www.winvistatips.com/winusb-bugchecks-t335323.html (confirmed - * through testing as well): - * "You can not call WinUsb_AbortPipe on control pipe. You can possibly cancel - * the control transfer using CancelIo" - */ -static int winusb_abort_control(struct usbi_transfer *itransfer) -{ - // Cancelling of the I/O is done in the parent - return LIBUSB_SUCCESS; -} - -static int winusb_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 = __device_handle_priv(transfer->dev_handle); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - HANDLE winusb_handle; - int current_interface; - - CHECK_WINUSB_AVAILABLE; - - current_interface = transfer_priv->interface_number; - if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) { - usbi_err(ctx, "program assertion failed: invalid interface_number"); - return LIBUSB_ERROR_NOT_FOUND; - } - usbi_dbg("will use interface %d", current_interface); - - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - if (!WinUsb_AbortPipe(winusb_handle, transfer->endpoint)) { - usbi_err(ctx, "WinUsb_AbortPipe failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_NO_DEVICE; - } - - return LIBUSB_SUCCESS; -} - -/* - * from the "How to Use WinUSB to Communicate with a USB Device" Microsoft white paper - * (http://www.microsoft.com/whdc/connect/usb/winusb_howto.mspx): - * "WinUSB does not support host-initiated reset port and cycle port operations" and - * IOCTL_INTERNAL_USB_CYCLE_PORT is only available in kernel mode and the - * IOCTL_USB_HUB_CYCLE_PORT ioctl was removed from Vista => the best we can do is - * cycle the pipes (and even then, the control pipe can not be reset using WinUSB) - */ -// TODO (2nd official release): see if we can force eject the device and redetect it (reuse hotplug?) -static int winusb_reset_device(struct libusb_device_handle *dev_handle) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle); - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - struct winfd wfd; - HANDLE winusb_handle; - int i, j; - - CHECK_WINUSB_AVAILABLE; - - // Reset any available pipe (except control) - for (i=0; i<USB_MAXINTERFACES; i++) { - winusb_handle = handle_priv->interface_handle[i].api_handle; - for (wfd = handle_to_winfd(winusb_handle); wfd.fd > 0;) - { - // Cancel any pollable I/O - usbi_remove_pollfd(ctx, wfd.fd); - usbi_free_fd(wfd.fd); - wfd = handle_to_winfd(winusb_handle); - } - - if ( (winusb_handle != 0) && (winusb_handle != INVALID_HANDLE_VALUE)) { - for (j=0; j<priv->usb_interface[i].nb_endpoints; j++) { - usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]); - if (!WinUsb_AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) { - usbi_err(ctx, "WinUsb_AbortPipe (pipe address %02X) failed: %s", - priv->usb_interface[i].endpoint[j], windows_error_str(0)); - } - // FlushPipe seems to fail on OUT pipes - if ( (priv->usb_interface[i].endpoint[j] & LIBUSB_ENDPOINT_IN) - && (!WinUsb_FlushPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) ) { - usbi_err(ctx, "WinUsb_FlushPipe (pipe address %02X) failed: %s", - priv->usb_interface[i].endpoint[j], windows_error_str(0)); - } - if (!WinUsb_ResetPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) { - usbi_err(ctx, "WinUsb_ResetPipe (pipe address %02X) failed: %s", - priv->usb_interface[i].endpoint[j], windows_error_str(0)); - } - } - } - } - - return LIBUSB_SUCCESS; -} - -static int winusb_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 - * LIBUSB_COMPLETED instead of LIBUSB_SUCCESS - */ -static int _hid_get_hid_descriptor(struct hid_device_priv* dev, void *data, size_t *size); -static int _hid_get_report_descriptor(struct hid_device_priv* dev, void *data, size_t *size); - -static int _hid_wcslen(WCHAR *str) -{ - int i = 0; - while (str[i] && (str[i] != 0x409)) { - i++; - } - return i; -} - -static int _hid_get_device_descriptor(struct hid_device_priv* dev, void *data, size_t *size) -{ - struct libusb_device_descriptor d; - - d.bLength = LIBUSB_DT_DEVICE_SIZE; - d.bDescriptorType = LIBUSB_DT_DEVICE; - d.bcdUSB = 0x0200; /* 2.00 */ - d.bDeviceClass = 0; - d.bDeviceSubClass = 0; - d.bDeviceProtocol = 0; - d.bMaxPacketSize0 = 64; /* fix this! */ - d.idVendor = (uint16_t)dev->vid; - d.idProduct = (uint16_t)dev->pid; - d.bcdDevice = 0x0100; - d.iManufacturer = dev->string_index[0]; - d.iProduct = dev->string_index[1]; - d.iSerialNumber = dev->string_index[2]; - d.bNumConfigurations = 1; - - if (*size > LIBUSB_DT_DEVICE_SIZE) - *size = LIBUSB_DT_DEVICE_SIZE; - memcpy(data, &d, *size); - return LIBUSB_COMPLETED; -} - -static int _hid_get_config_descriptor(struct hid_device_priv* dev, void *data, size_t *size) -{ - char num_endpoints = 0; - size_t config_total_len = 0; - char tmp[HID_MAX_CONFIG_DESC_SIZE]; - struct libusb_config_descriptor *cd; - struct libusb_interface_descriptor *id; - struct libusb_hid_descriptor *hd; - struct libusb_endpoint_descriptor *ed; - size_t tmp_size; - - if (dev->input_report_size) - num_endpoints++; - if (dev->output_report_size) - num_endpoints++; - - config_total_len = LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE - + LIBUSB_DT_HID_SIZE + num_endpoints * LIBUSB_DT_ENDPOINT_SIZE; - - - cd = (struct libusb_config_descriptor *)tmp; - id = (struct libusb_interface_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE); - hd = (struct libusb_hid_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE - + LIBUSB_DT_INTERFACE_SIZE); - ed = (struct libusb_endpoint_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE - + LIBUSB_DT_INTERFACE_SIZE - + LIBUSB_DT_HID_SIZE); - - cd->bLength = LIBUSB_DT_CONFIG_SIZE; - cd->bDescriptorType = LIBUSB_DT_CONFIG; - cd->wTotalLength = (uint16_t) config_total_len; - cd->bNumInterfaces = 1; - cd->bConfigurationValue = 1; - cd->iConfiguration = 0; - cd->bmAttributes = 1 << 7; /* bus powered */ - cd->MaxPower = 50; - - id->bLength = LIBUSB_DT_INTERFACE_SIZE; - id->bDescriptorType = LIBUSB_DT_INTERFACE; - id->bInterfaceNumber = 0; - id->bAlternateSetting = 0; - id->bNumEndpoints = num_endpoints; - id->bInterfaceClass = 3; - id->bInterfaceSubClass = 0; - id->bInterfaceProtocol = 0; - id->iInterface = 0; - - tmp_size = LIBUSB_DT_HID_SIZE; - _hid_get_hid_descriptor(dev, hd, &tmp_size); - - if (dev->input_report_size) { - ed->bLength = LIBUSB_DT_ENDPOINT_SIZE; - ed->bDescriptorType = LIBUSB_DT_ENDPOINT; - ed->bEndpointAddress = HID_IN_EP; - ed->bmAttributes = 3; - ed->wMaxPacketSize = dev->input_report_size - 1; - ed->bInterval = 10; - - ed++; - } - - if (dev->output_report_size) { - ed->bLength = LIBUSB_DT_ENDPOINT_SIZE; - ed->bDescriptorType = LIBUSB_DT_ENDPOINT; - ed->bEndpointAddress = HID_OUT_EP; - ed->bmAttributes = 3; - ed->wMaxPacketSize = dev->output_report_size - 1; - ed->bInterval = 10; - } - - if (*size > config_total_len) - *size = config_total_len; - memcpy(data, tmp, *size); - return LIBUSB_COMPLETED; -} - -static int _hid_get_string_descriptor(struct hid_device_priv* dev, int index, - void *data, size_t *size) -{ - void *tmp = NULL; - size_t tmp_size = 0; - int i; - - /* language ID, EN-US */ - char string_langid[] = { - 0x09, - 0x04 - }; - - if ((*size < 2) || (*size > 255)) { - return LIBUSB_ERROR_OVERFLOW; - } - - if (index == 0) { - tmp = string_langid; - tmp_size = sizeof(string_langid)+2; - } else { - for (i=0; i<3; i++) { - if (index == (dev->string_index[i])) { - tmp = dev->string[i]; - tmp_size = (_hid_wcslen(dev->string[i])+1) * sizeof(WCHAR); - break; - } - } - if (i == 3) { // not found - return LIBUSB_ERROR_INVALID_PARAM; - } - } - - if(!tmp_size) { - return LIBUSB_ERROR_INVALID_PARAM; - } - - if (tmp_size < *size) { - *size = tmp_size; - } - // 2 byte header - ((uint8_t*)data)[0] = (uint8_t)*size; - ((uint8_t*)data)[1] = LIBUSB_DT_STRING; - memcpy((uint8_t*)data+2, tmp, *size-2); - return LIBUSB_COMPLETED; -} - -static int _hid_get_hid_descriptor(struct hid_device_priv* dev, void *data, size_t *size) -{ - struct libusb_hid_descriptor d; - uint8_t tmp[MAX_HID_DESCRIPTOR_SIZE]; - size_t report_len = MAX_HID_DESCRIPTOR_SIZE; - - _hid_get_report_descriptor(dev, tmp, &report_len); - - d.bLength = LIBUSB_DT_HID_SIZE; - d.bDescriptorType = LIBUSB_DT_HID; - d.bcdHID = 0x0110; /* 1.10 */ - d.bCountryCode = 0; - d.bNumDescriptors = 1; - d.bClassDescriptorType = LIBUSB_DT_REPORT; - d.wClassDescriptorLength = (uint16_t)report_len; - - if (*size > LIBUSB_DT_HID_SIZE) - *size = LIBUSB_DT_HID_SIZE; - memcpy(data, &d, *size); - return LIBUSB_COMPLETED; -} - -static int _hid_get_report_descriptor(struct hid_device_priv* dev, void *data, size_t *size) -{ - uint8_t d[MAX_HID_DESCRIPTOR_SIZE]; - size_t i = 0; - - /* usage page (0xFFA0 == vendor defined) */ - d[i++] = 0x06; d[i++] = 0xA0; d[i++] = 0xFF; - /* usage (vendor defined) */ - d[i++] = 0x09; d[i++] = 0x01; - /* start collection (application) */ - d[i++] = 0xA1; d[i++] = 0x01; - /* input report */ - if (dev->input_report_size) { - /* usage (vendor defined) */ - d[i++] = 0x09; d[i++] = 0x01; - /* logical minimum (0) */ - d[i++] = 0x15; d[i++] = 0x00; - /* logical maximum (255) */ - d[i++] = 0x25; d[i++] = 0xFF; - /* report size (8 bits) */ - d[i++] = 0x75; d[i++] = 0x08; - /* report count */ - d[i++] = 0x95; d[i++] = (uint8_t)dev->input_report_size - 1; - /* input (data, variable, absolute) */ - d[i++] = 0x81; d[i++] = 0x00; - } - /* output report */ - if (dev->output_report_size) { - /* usage (vendor defined) */ - d[i++] = 0x09; d[i++] = 0x02; - /* logical minimum (0) */ - d[i++] = 0x15; d[i++] = 0x00; - /* logical maximum (255) */ - d[i++] = 0x25; d[i++] = 0xFF; - /* report size (8 bits) */ - d[i++] = 0x75; d[i++] = 0x08; - /* report count */ - d[i++] = 0x95; d[i++] = (uint8_t)dev->output_report_size - 1; - /* output (data, variable, absolute) */ - d[i++] = 0x91; d[i++] = 0x00; - } - /* feature report */ - if (dev->feature_report_size) { - /* usage (vendor defined) */ - d[i++] = 0x09; d[i++] = 0x03; - /* logical minimum (0) */ - d[i++] = 0x15; d[i++] = 0x00; - /* logical maximum (255) */ - d[i++] = 0x25; d[i++] = 0xFF; - /* report size (8 bits) */ - d[i++] = 0x75; d[i++] = 0x08; - /* report count */ - d[i++] = 0x95; d[i++] = (uint8_t)dev->feature_report_size - 1; - /* feature (data, variable, absolute) */ - d[i++] = 0xb2; d[i++] = 0x02; d[i++] = 0x01; - } - - /* end collection */ - d[i++] = 0xC0; - - if (*size > i) - *size = i; - memcpy(data, d, *size); - return LIBUSB_COMPLETED; -} - -static int _hid_get_descriptor(struct hid_device_priv* dev, HANDLE hid_handle, int recipient, - int type, int index, void *data, size_t *size) -{ - switch(type) { - case LIBUSB_DT_DEVICE: - usbi_dbg("LIBUSB_DT_DEVICE"); - return _hid_get_device_descriptor(dev, data, size); - case LIBUSB_DT_CONFIG: - usbi_dbg("LIBUSB_DT_CONFIG"); - if (!index) - return _hid_get_config_descriptor(dev, data, size); - return LIBUSB_ERROR_INVALID_PARAM; - case LIBUSB_DT_STRING: - usbi_dbg("LIBUSB_DT_STRING"); - return _hid_get_string_descriptor(dev, index, data, size); - case LIBUSB_DT_HID: - usbi_dbg("LIBUSB_DT_HID"); - if (!index) - return _hid_get_hid_descriptor(dev, data, size); - return LIBUSB_ERROR_INVALID_PARAM; - case LIBUSB_DT_REPORT: - usbi_dbg("LIBUSB_DT_REPORT"); - if (!index) - return _hid_get_report_descriptor(dev, data, size); - return LIBUSB_ERROR_INVALID_PARAM; - case LIBUSB_DT_PHYSICAL: - usbi_dbg("LIBUSB_DT_PHYSICAL"); - if (HidD_GetPhysicalDescriptor(hid_handle, data, (ULONG)*size)) - return LIBUSB_COMPLETED; - return LIBUSB_ERROR_OTHER; - } - usbi_dbg("unsupported"); - return LIBUSB_ERROR_INVALID_PARAM; -} - -static int _hid_get_report(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data, - struct windows_transfer_priv *tp, size_t *size, OVERLAPPED* overlapped, - int report_type) -{ - uint8_t *buf; - DWORD ioctl_code, read_size, expected_size = (DWORD)*size; - int r = LIBUSB_SUCCESS; - - if (tp->hid_buffer != NULL) { - usbi_dbg("program assertion failed: hid_buffer is not NULL"); - } - - if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) { - usbi_dbg("invalid size (%d)", *size); - return LIBUSB_ERROR_INVALID_PARAM; - } - - switch (report_type) { - case HID_REPORT_TYPE_INPUT: - ioctl_code = IOCTL_HID_GET_INPUT_REPORT; - break; - case HID_REPORT_TYPE_FEATURE: - ioctl_code = IOCTL_HID_GET_FEATURE; - break; - default: - usbi_dbg("unknown HID report type %d", report_type); - return LIBUSB_ERROR_INVALID_PARAM; - } - - // When report IDs are not in use, add an extra byte for the report ID - if (id==0) { - expected_size++; - } - - // Add a trailing byte to detect overflows - buf = (uint8_t*)calloc(expected_size+1, 1); - if (buf == NULL) { - return LIBUSB_ERROR_NO_MEM; - } - buf[0] = (uint8_t)id; // Must be set always - usbi_dbg("report ID: 0x%02X", buf[0]); - - tp->hid_expected_size = expected_size; - - if (!DeviceIoControl(hid_handle, ioctl_code, buf, expected_size+1, - buf, expected_size+1, &read_size, overlapped)) { - if (GetLastError() != ERROR_IO_PENDING) { - usbi_dbg("Failed to Read HID Report: %s", windows_error_str(0)); - safe_free(buf); - return LIBUSB_ERROR_IO; - } - // Asynchronous wait - tp->hid_buffer = buf; - tp->hid_dest = data; // copy dest, as not necessarily the start of the transfer buffer - return LIBUSB_SUCCESS; - } - - // Transfer completed synchronously => copy and discard extra buffer - if (read_size == 0) { - usbi_dbg("program assertion failed - read completed synchronously, but no data was read"); - *size = 0; - } else { - if (buf[0] != id) { - usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id); - } - if ((size_t)read_size > expected_size) { - r = LIBUSB_ERROR_OVERFLOW; - usbi_dbg("OVERFLOW!"); - } else { - r = LIBUSB_COMPLETED; - } - - if (id == 0) { - // Discard report ID - *size = MIN((size_t)read_size-1, *size); - memcpy(data, buf+1, *size); - } else { - *size = MIN((size_t)read_size, *size); - memcpy(data, buf, *size); - } - } - safe_free(buf); - return r; -} - -static int _hid_set_report(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data, - struct windows_transfer_priv *tp, size_t *size, OVERLAPPED* overlapped, - int report_type) -{ - uint8_t *buf = NULL; - DWORD ioctl_code, write_size= (DWORD)*size; - - if (tp->hid_buffer != NULL) { - usbi_dbg("program assertion failed: hid_buffer is not NULL"); - } - - if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) { - usbi_dbg("invalid size (%d)", *size); - return LIBUSB_ERROR_INVALID_PARAM; - } - - switch (report_type) { - case HID_REPORT_TYPE_OUTPUT: - ioctl_code = IOCTL_HID_SET_OUTPUT_REPORT; - break; - case HID_REPORT_TYPE_FEATURE: - ioctl_code = IOCTL_HID_SET_FEATURE; - break; - default: - usbi_dbg("unknown HID report type %d", report_type); - return LIBUSB_ERROR_INVALID_PARAM; - } - - usbi_dbg("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) { - write_size++; - } - buf = malloc(write_size); - if (buf == NULL) { - return LIBUSB_ERROR_NO_MEM; - } - if (id == 0) { - buf[0] = 0; - memcpy(buf + 1, data, *size); - } else { - // This seems like a waste, but if we don't duplicate the - // data, we'll get issues when freeing hid_buffer - memcpy(buf, data, *size); - if (buf[0] != id) { - usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id); - } - } - - if (!DeviceIoControl(hid_handle, ioctl_code, buf, write_size, - buf, write_size, &write_size, overlapped)) { - if (GetLastError() != ERROR_IO_PENDING) { - usbi_dbg("Failed to Write HID Output Report: %s", windows_error_str(0)); - safe_free(buf); - return LIBUSB_ERROR_IO; - } - tp->hid_buffer = buf; - tp->hid_dest = NULL; - return LIBUSB_SUCCESS; - } - - // Transfer completed synchronously - if (write_size == 0) { - usbi_dbg("program assertion failed - write completed synchronously, but no data was written"); - *size = 0; - } else { - *size = write_size - ((id == 0)?1:0); - } - safe_free(buf); - return LIBUSB_COMPLETED; -} - -static int _hid_class_request(struct hid_device_priv* dev, HANDLE hid_handle, int request_type, - int request, int value, int index, void *data, struct windows_transfer_priv *tp, - size_t *size, OVERLAPPED* overlapped) -{ - int report_type = (value >> 8) & 0xFF; - int report_id = value & 0xFF; - - if ( (LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_INTERFACE) - && (LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_DEVICE) ) - return LIBUSB_ERROR_INVALID_PARAM; - - if (LIBUSB_REQ_OUT(request_type) && request == HID_REQ_SET_REPORT) - return _hid_set_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type); - - if (LIBUSB_REQ_IN(request_type) && request == HID_REQ_GET_REPORT) - return _hid_get_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type); - - return LIBUSB_ERROR_INVALID_PARAM; -} - - -/* - * HID API functions - */ -static int hid_init(struct libusb_context *ctx) -{ - DLL_LOAD(hid.dll, HidD_GetAttributes, TRUE); - DLL_LOAD(hid.dll, HidD_GetHidGuid, TRUE); - DLL_LOAD(hid.dll, HidD_GetPreparsedData, TRUE); - DLL_LOAD(hid.dll, HidD_FreePreparsedData, TRUE); - DLL_LOAD(hid.dll, HidD_GetManufacturerString, TRUE); - DLL_LOAD(hid.dll, HidD_GetProductString, TRUE); - DLL_LOAD(hid.dll, HidD_GetSerialNumberString, TRUE); - DLL_LOAD(hid.dll, HidP_GetCaps, TRUE); - DLL_LOAD(hid.dll, HidD_SetNumInputBuffers, TRUE); - DLL_LOAD(hid.dll, HidD_SetFeature, TRUE); - DLL_LOAD(hid.dll, HidD_GetFeature, TRUE); - DLL_LOAD(hid.dll, HidD_GetPhysicalDescriptor, TRUE); - DLL_LOAD(hid.dll, HidD_GetInputReport, FALSE); - DLL_LOAD(hid.dll, HidD_SetOutputReport, FALSE); - DLL_LOAD(hid.dll, HidD_FlushQueue, TRUE); - DLL_LOAD(hid.dll, HidP_GetValueCaps, TRUE); - - api_hid_available = true; - return LIBUSB_SUCCESS; -} - -static int hid_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 hid_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 = __device_handle_priv(dev_handle); - - HIDD_ATTRIBUTES hid_attributes; - PHIDP_PREPARSED_DATA preparsed_data = NULL; - HIDP_CAPS capabilities; - HIDP_VALUE_CAPS *value_caps; - - HANDLE hid_handle = INVALID_HANDLE_VALUE; - int i, j; - // report IDs handling - ULONG size[3]; - char* type[3] = {"input", "output", "feature"}; - int nb_ids[2]; // zero and nonzero report IDs - - CHECK_HID_AVAILABLE; - if (priv->hid == NULL) { - usbi_err(ctx, "program assertion failed - private HID structure is unitialized"); - return LIBUSB_ERROR_NOT_FOUND; - } - - 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 = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); - /* - * 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 - * keyboards or mice. An application can obtain a handle to a system keyboard or mouse by not - * requesting READ or WRITE access with CreateFile. Applications can then use HidD_SetFeature and - * HidD_GetFeature (if the device supports Feature reports)." - */ - if (hid_handle == INVALID_HANDLE_VALUE) { - usbi_warn(ctx, "could not open HID device in R/W mode (keyboard or mouse?) - trying without"); - hid_handle = CreateFileA(priv->usb_interface[i].path, 0, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); - if (hid_handle == INVALID_HANDLE_VALUE) { - usbi_err(ctx, "could not open device %s (interface %d): %s", priv->path, i, 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; - } - } - priv->usb_interface[i].restricted_functionality = true; - } - handle_priv->interface_handle[i].api_handle = hid_handle; - } - } - - hid_attributes.Size = sizeof(hid_attributes); - do { - if (!HidD_GetAttributes(hid_handle, &hid_attributes)) { - usbi_err(ctx, "could not gain access to HID top collection (HidD_GetAttributes)"); - break; - } - - priv->hid->vid = hid_attributes.VendorID; - priv->hid->pid = hid_attributes.ProductID; - - // 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); - - // Get the maximum input and output report size - if (!HidD_GetPreparsedData(hid_handle, &preparsed_data) || !preparsed_data) { - usbi_err(ctx, "could not read HID preparsed data (HidD_GetPreparsedData)"); - break; - } - if (HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) { - usbi_err(ctx, "could not parse HID capabilities (HidP_GetCaps)"); - break; - } - - // Find out if interrupt will need report IDs - size[0] = capabilities.NumberInputValueCaps; - size[1] = capabilities.NumberOutputValueCaps; - size[2] = capabilities.NumberFeatureValueCaps; - for (j=0; j<3; j++) { - usbi_dbg("%d HID %s report value(s) found", size[j], type[j]); - priv->hid->uses_report_ids[j] = false; - if (size[j] > 0) { - value_caps = malloc(size[j] * sizeof(HIDP_VALUE_CAPS)); - if ( (value_caps != NULL) - && (HidP_GetValueCaps(j, value_caps, &size[j], preparsed_data) == HIDP_STATUS_SUCCESS) - && (size[j] >= 1) ) { - 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); - if (value_caps[i].ReportID != 0) { - nb_ids[1]++; - } else { - nb_ids[0]++; - } - } - if (nb_ids[1] != 0) { - if (nb_ids[0] != 0) { - usbi_warn(ctx, "program assertion failed: zero and nonzero report IDs used for %s", - type[j]); - } - priv->hid->uses_report_ids[j] = true; - } - } else { - usbi_warn(ctx, " could not process %s report IDs", type[j]); - } - safe_free(value_caps); - } - } - - // Set the report sizes - priv->hid->input_report_size = capabilities.InputReportByteLength; - priv->hid->output_report_size = capabilities.OutputReportByteLength; - priv->hid->feature_report_size = capabilities.FeatureReportByteLength; - - // Fetch string descriptors - priv->hid->string_index[0] = priv->dev_descriptor.iManufacturer; - if (priv->hid->string_index[0] != 0) { - HidD_GetManufacturerString(hid_handle, priv->hid->string[0], - sizeof(priv->hid->string[0])); - } else { - priv->hid->string[0][0] = 0; - } - priv->hid->string_index[1] = priv->dev_descriptor.iProduct; - if (priv->hid->string_index[1] != 0) { - HidD_GetProductString(hid_handle, priv->hid->string[1], - sizeof(priv->hid->string[1])); - } else { - priv->hid->string[1][0] = 0; - } - priv->hid->string_index[2] = priv->dev_descriptor.iSerialNumber; - if (priv->hid->string_index[2] != 0) { - HidD_GetSerialNumberString(hid_handle, priv->hid->string[2], - sizeof(priv->hid->string[2])); - } else { - priv->hid->string[2][0] = 0; - } - } while(0); - - if (preparsed_data) { - HidD_FreePreparsedData(preparsed_data); - } - - return LIBUSB_SUCCESS; -} - -static void hid_close(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle); - HANDLE file_handle; - int i; - - if (!api_hid_available) - return; - - for (i = 0; i < USB_MAXINTERFACES; i++) { - if (priv->usb_interface[i].apib->id == USB_API_HID) { - file_handle = handle_priv->interface_handle[i].api_handle; - if ( (file_handle != 0) && (file_handle != INVALID_HANDLE_VALUE)) { - CloseHandle(file_handle); - } - } - } -} - -static int hid_claim_interface(struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle); - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - - CHECK_HID_AVAILABLE; - - // NB: Disconnection detection is not possible in this function - if (priv->usb_interface[iface].path == NULL) { - return LIBUSB_ERROR_NOT_FOUND; // invalid iface - } - - // We use dev_handle as a flag for interface claimed - if (handle_priv->interface_handle[iface].dev_handle == INTERFACE_CLAIMED) { - return LIBUSB_ERROR_BUSY; // already claimed - } - - handle_priv->interface_handle[iface].dev_handle = INTERFACE_CLAIMED; - - usbi_dbg("claimed interface %d", iface); - handle_priv->active_interface = iface; - - return LIBUSB_SUCCESS; -} - -static int hid_release_interface(struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle); - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - - CHECK_HID_AVAILABLE; - - if (priv->usb_interface[iface].path == NULL) { - return LIBUSB_ERROR_NOT_FOUND; // invalid iface - } - - if (handle_priv->interface_handle[iface].dev_handle != INTERFACE_CLAIMED) { - return LIBUSB_ERROR_NOT_FOUND; // invalid iface - } - - handle_priv->interface_handle[iface].dev_handle = INVALID_HANDLE_VALUE; - - return LIBUSB_SUCCESS; -} - -static int hid_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - - CHECK_HID_AVAILABLE; - - if (altsetting > 255) { - return LIBUSB_ERROR_INVALID_PARAM; - } - - if (altsetting != 0) { - usbi_err(ctx, "set interface altsetting not supported for altsetting >0"); - return LIBUSB_ERROR_NOT_SUPPORTED; - } - - return LIBUSB_SUCCESS; -} - -static int hid_submit_control_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_handle_priv *handle_priv = __device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *) transfer->buffer; - HANDLE hid_handle; - struct winfd wfd; - int current_interface, config; - size_t size; - int r = LIBUSB_ERROR_INVALID_PARAM; - - CHECK_HID_AVAILABLE; - - transfer_priv->pollable_fd = INVALID_WINFD; - safe_free(transfer_priv->hid_buffer); - transfer_priv->hid_dest = NULL; - 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, USB_API_HID); - if (current_interface < 0) { -#if defined(AUTO_CLAIM) - if (auto_claim(transfer, ¤t_interface, USB_API_HID) != LIBUSB_SUCCESS) { - return LIBUSB_ERROR_NOT_FOUND; - } -#else - usbi_warn(ctx, "no interface available for control transfer"); - return LIBUSB_ERROR_NOT_FOUND; -#endif - } - - usbi_dbg("will use interface %d", current_interface); - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - // Always use the handle returned from usbi_create_fd (wfd.handle) - wfd = usbi_create_fd(hid_handle, _O_RDONLY); - if (wfd.fd < 0) { - return LIBUSB_ERROR_NO_MEM; - } - - switch(LIBUSB_REQ_TYPE(setup->request_type)) { - case LIBUSB_REQUEST_TYPE_STANDARD: - switch(setup->request) { - case LIBUSB_REQUEST_GET_DESCRIPTOR: - r = _hid_get_descriptor(priv->hid, wfd.handle, LIBUSB_REQ_RECIPIENT(setup->request_type), - (setup->value >> 8) & 0xFF, setup->value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size); - break; - case LIBUSB_REQUEST_GET_CONFIGURATION: - r = windows_get_configuration(transfer->dev_handle, &config); - if (r == LIBUSB_SUCCESS) { - size = 1; - ((uint8_t*)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = (uint8_t)config; - r = LIBUSB_COMPLETED; - } - break; - case LIBUSB_REQUEST_SET_CONFIGURATION: - if (setup->value == priv->active_config) { - r = LIBUSB_COMPLETED; - } else { - usbi_warn(ctx, "cannot set configuration other than the default one"); - r = LIBUSB_ERROR_INVALID_PARAM; - } - break; - case LIBUSB_REQUEST_GET_INTERFACE: - size = 1; - ((uint8_t*)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = 0; - r = LIBUSB_COMPLETED; - break; - case LIBUSB_REQUEST_SET_INTERFACE: - r = hid_set_interface_altsetting(transfer->dev_handle, setup->index, setup->value); - if (r == LIBUSB_SUCCESS) { - r = LIBUSB_COMPLETED; - } - break; - default: - usbi_warn(ctx, "unsupported HID control request"); - r = LIBUSB_ERROR_INVALID_PARAM; - break; - } - break; - case LIBUSB_REQUEST_TYPE_CLASS: - r =_hid_class_request(priv->hid, wfd.handle, setup->request_type, setup->request, setup->value, - setup->index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer_priv, - &size, wfd.overlapped); - break; - default: - usbi_warn(ctx, "unsupported HID control request"); - r = LIBUSB_ERROR_INVALID_PARAM; - break; - } - - if (r == LIBUSB_COMPLETED) { - // Force request to be completed synchronously. Transferred size has been set by previous call - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - // http://msdn.microsoft.com/en-us/library/ms684342%28VS.85%29.aspx - // set InternalHigh to the number of bytes transferred - wfd.overlapped->InternalHigh = (DWORD)size; - r = LIBUSB_SUCCESS; - } - - if (r == LIBUSB_SUCCESS) { - // Use priv_transfer to store data needed for async polling - transfer_priv->pollable_fd = wfd; - transfer_priv->interface_number = (uint8_t)current_interface; - } else { - usbi_free_fd(wfd.fd); - } - - return r; -} - -static int hid_submit_bulk_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = __device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev); - struct winfd wfd; - HANDLE hid_handle; - bool direction_in, ret; - int current_interface, length; - DWORD size; - int r = LIBUSB_SUCCESS; - - CHECK_HID_AVAILABLE; - - transfer_priv->pollable_fd = INVALID_WINFD; - transfer_priv->hid_dest = NULL; - safe_free(transfer_priv->hid_buffer); - - 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); - - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN; - - wfd = usbi_create_fd(hid_handle, direction_in?_O_RDONLY:_O_WRONLY); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) { - return LIBUSB_ERROR_NO_MEM; - } - - // If report IDs are not in use, an extra prefix byte must be added - if ( ((direction_in) && (!priv->hid->uses_report_ids[0])) - || ((!direction_in) && (!priv->hid->uses_report_ids[1])) ) { - length = transfer->length+1; - } else { - length = transfer->length; - } - // Add a trailing byte to detect overflows on input - transfer_priv->hid_buffer = (uint8_t*)calloc(length+1, 1); - if (transfer_priv->hid_buffer == NULL) { - return LIBUSB_ERROR_NO_MEM; - } - transfer_priv->hid_expected_size = length; - - if (direction_in) { - transfer_priv->hid_dest = transfer->buffer; - usbi_dbg("reading %d bytes (report ID: 0x%02X)", length, transfer_priv->hid_buffer[0]); - ret = ReadFile(wfd.handle, transfer_priv->hid_buffer, length+1, &size, wfd.overlapped); - } else { - if (!priv->hid->uses_report_ids[1]) { - memcpy(transfer_priv->hid_buffer+1, transfer->buffer, transfer->length); - } else { - // 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]); - ret = WriteFile(wfd.handle, transfer_priv->hid_buffer, length, &size, wfd.overlapped); - } - if (!ret) { - if (GetLastError() != ERROR_IO_PENDING) { - usbi_err(ctx, "HID transfer failed: %s", windows_error_str(0)); - usbi_free_fd(wfd.fd); - safe_free(transfer_priv->hid_buffer); - return LIBUSB_ERROR_IO; - } - } else { - // Only write operations that completed synchronously need to free up - // hid_buffer. For reads, copy_transfer_data() handles that process. - if (!direction_in) { - safe_free(transfer_priv->hid_buffer); - } - if (size == 0) { - usbi_err(ctx, "program assertion failed - no data was transferred"); - size = 1; - } - if (size > (size_t)length) { - usbi_err(ctx, "OVERFLOW!"); - r = LIBUSB_ERROR_OVERFLOW; - } - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = size; - } - - transfer_priv->pollable_fd = wfd; - transfer_priv->interface_number = (uint8_t)current_interface; - - return r; -} - -static int hid_abort_transfers(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_handle_priv *handle_priv = __device_handle_priv(transfer->dev_handle); - HANDLE hid_handle; - int current_interface; - - CHECK_HID_AVAILABLE; - - current_interface = transfer_priv->interface_number; - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - CancelIo(hid_handle); - - return LIBUSB_SUCCESS; -} - -static int hid_reset_device(struct libusb_device_handle *dev_handle) -{ - struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle); - HANDLE hid_handle; - int current_interface; - - CHECK_HID_AVAILABLE; - - // Flushing the queues on all interfaces is the best we can achieve - for (current_interface = 0; current_interface < USB_MAXINTERFACES; current_interface++) { - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - if ((hid_handle != 0) && (hid_handle != INVALID_HANDLE_VALUE)) { - HidD_FlushQueue(hid_handle); - } - } - return LIBUSB_SUCCESS; -} - -static int hid_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 = __device_handle_priv(dev_handle); - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - HANDLE hid_handle; - int current_interface; - - CHECK_HID_AVAILABLE; - - current_interface = interface_by_endpoint(priv, handle_priv, endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("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 - // whole interface. Should be OK for most case scenarios - if (!HidD_FlushQueue(hid_handle)) { - usbi_err(ctx, "Flushing of HID queue failed: %s", windows_error_str(0)); - // Device was probably disconnected - return LIBUSB_ERROR_NO_DEVICE; - } - - return LIBUSB_SUCCESS; -} - -// This extra function is only needed for HID -static int hid_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) { - 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); - int r = LIBUSB_TRANSFER_COMPLETED; - uint32_t corrected_size = io_size; - - if (transfer_priv->hid_buffer != NULL) { - // If we have a valid hid_buffer, it means the transfer was async - if (transfer_priv->hid_dest != NULL) { // Data readout - // First, check for overflow - if (corrected_size > transfer_priv->hid_expected_size) { - usbi_err(ctx, "OVERFLOW!"); - corrected_size = (uint32_t)transfer_priv->hid_expected_size; - r = LIBUSB_TRANSFER_OVERFLOW; - } - - if (transfer_priv->hid_buffer[0] == 0) { - // Discard the 1 byte report ID prefix - corrected_size--; - memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer+1, corrected_size); - } else { - memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer, corrected_size); - } - transfer_priv->hid_dest = NULL; - } - // For write, we just need to free the hid buffer - safe_free(transfer_priv->hid_buffer); - } - itransfer->transferred += corrected_size; - return r; -} - - -/* - * Composite API functions - */ -static int composite_init(struct libusb_context *ctx) -{ - return LIBUSB_SUCCESS; -} - -static int composite_exit(void) -{ - return LIBUSB_SUCCESS; -} - -static int composite_open(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - unsigned api; - int r; - uint8_t flag = 1<<USB_API_WINUSB; - - for (api=USB_API_WINUSB; api<USB_API_MAX; api++) { - if (priv->composite_api_flags & flag) { - r = usb_api_backend[api].open(dev_handle); - if (r != LIBUSB_SUCCESS) { - return r; - } - } - flag <<= 1; - } - return LIBUSB_SUCCESS; -} - -static void composite_close(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - unsigned api; - uint8_t flag = 1<<USB_API_WINUSB; - - for (api=USB_API_WINUSB; api<USB_API_MAX; api++) { - if (priv->composite_api_flags & flag) { - usb_api_backend[api].close(dev_handle); - } - flag <<= 1; - } -} - -static int composite_claim_interface(struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - return priv->usb_interface[iface].apib->claim_interface(dev_handle, iface); -} - -static int composite_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - return priv->usb_interface[iface].apib->set_interface_altsetting(dev_handle, iface, altsetting); -} - -static int composite_release_interface(struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - return priv->usb_interface[iface].apib->release_interface(dev_handle, iface); -} - -static int composite_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_device_priv *priv = __device_priv(transfer->dev_handle->dev); - int i, pass; - - // Interface shouldn't matter for control, but it does in practice, with Windows' - // restrictions with regards to accessing HID keyboards and mice. Try a 2 pass approach - for (pass = 0; pass < 2; pass++) { - for (i=0; i<USB_MAXINTERFACES; i++) { - if (priv->usb_interface[i].path != NULL) { - if ((pass == 0) && (priv->usb_interface[i].restricted_functionality)) { - usbi_dbg("trying to skip restricted interface #%d (HID keyboard or mouse?)", i); - continue; - } - usbi_dbg("using interface %d", i); - return priv->usb_interface[i].apib->submit_control_transfer(itransfer); - } - } - } - - usbi_err(ctx, "no libusb supported interfaces to complete request"); - return LIBUSB_ERROR_NOT_FOUND; -} - -static int composite_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_device_handle_priv *handle_priv = __device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev); - int current_interface; - - 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; - } - - return priv->usb_interface[current_interface].apib->submit_bulk_transfer(itransfer); -} - -static int composite_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_device_handle_priv *handle_priv = __device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev); - int current_interface; - - 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; - } - - return priv->usb_interface[current_interface].apib->submit_iso_transfer(itransfer); -} - -static int composite_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 = __device_handle_priv(dev_handle); - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - int current_interface; - - current_interface = interface_by_endpoint(priv, handle_priv, endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); - return LIBUSB_ERROR_NOT_FOUND; - } - - return priv->usb_interface[current_interface].apib->clear_halt(dev_handle, endpoint); -} - -static int composite_abort_control(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev); - - return priv->usb_interface[transfer_priv->interface_number].apib->abort_control(itransfer); -} - -static int composite_abort_transfers(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev); - - return priv->usb_interface[transfer_priv->interface_number].apib->abort_transfers(itransfer); -} - -static int composite_reset_device(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = __device_priv(dev_handle->dev); - unsigned api; - int r; - uint8_t flag = 1<<USB_API_WINUSB; - - for (api=USB_API_WINUSB; api<USB_API_MAX; api++) { - if (priv->composite_api_flags & flag) { - r = usb_api_backend[api].reset_device(dev_handle); - if (r != LIBUSB_SUCCESS) { - return r; - } - } - flag <<= 1; - } - return LIBUSB_SUCCESS; -} - -static int composite_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) -{ - struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev); - - return priv->usb_interface[transfer_priv->interface_number].apib->copy_transfer_data(itransfer, io_size); -} diff --git a/include/libusb-1.0/os/windows_usb.h b/include/libusb-1.0/os/windows_usb.h deleted file mode 100644 index dc90a64..0000000 --- a/include/libusb-1.0/os/windows_usb.h +++ /dev/null @@ -1,784 +0,0 @@ -/* - * Windows backend for libusb 1.0 - * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com> - * With contributions from Michael Plante, Orin Eman et al. - * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer - * Major code testing contribution by Xiaofan Chen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#pragma once - -#if defined(_MSC_VER) -// disable /W4 MSVC warnings that are benign -#pragma warning(disable:4127) // conditional expression is constant -#pragma warning(disable:4100) // unreferenced formal parameter -#pragma warning(disable:4214) // bit field types other than int -#pragma warning(disable:4201) // nameless struct/union -#endif - -// Windows API default is uppercase - ugh! -#if !defined(bool) -#define bool BOOL -#endif -#if !defined(true) -#define true TRUE -#endif -#if !defined(false) -#define false FALSE -#endif - -#if !defined(libusb_bus_t) -#define libusb_bus_t uint8_t -#define LIBUSB_BUS_MAX UINT8_MAX -#endif -#if !defined(libusb_devaddr_t) -#define libusb_devaddr_t uint8_t -#define LIBUSB_DEVADDR_MAX UINT8_MAX -#endif - -// Missing from MSVC6 setupapi.h -#if !defined(SPDRP_ADDRESS) -#define SPDRP_ADDRESS 28 -#endif -#if !defined(SPDRP_INSTALL_STATE) -#define SPDRP_INSTALL_STATE 34 -#endif - -#if defined(__CYGWIN__ ) -// cygwin produces a warning unless these prototypes are defined -extern int _snprintf(char *buffer, size_t count, const char *format, ...); -extern char *_strdup(const char *strSource); -// _beginthreadex is MSVCRT => unavailable for cygwin. Fallback to using CreateThread -#define _beginthreadex(a, b, c, d, e, f) CreateThread(a, b, (LPTHREAD_START_ROUTINE)c, d, e, f) -#endif -#define safe_free(p) do {if (p != NULL) {free((void*)p); p = NULL;}} while(0) -#define safe_closehandle(h) do {if (h != INVALID_HANDLE_VALUE) {CloseHandle(h); h = INVALID_HANDLE_VALUE;}} while(0) -#define safe_min(a, b) min((size_t)(a), (size_t)(b)) -#define safe_strcp(dst, dst_max, src, count) do {memcpy(dst, src, safe_min(count, dst_max)); \ - ((char*)dst)[safe_min(count, dst_max)-1] = 0;} while(0) -#define safe_strcpy(dst, dst_max, src) safe_strcp(dst, dst_max, src, safe_strlen(src)+1) -#define safe_strncat(dst, dst_max, src, count) strncat(dst, src, safe_min(count, dst_max - safe_strlen(dst) - 1)) -#define safe_strcat(dst, dst_max, src) safe_strncat(dst, dst_max, src, safe_strlen(src)+1) -#define safe_strcmp(str1, str2) strcmp(((str1==NULL)?"<NULL>":str1), ((str2==NULL)?"<NULL>":str2)) -#define safe_strncmp(str1, str2, count) strncmp(((str1==NULL)?"<NULL>":str1), ((str2==NULL)?"<NULL>":str2), count) -#define safe_strlen(str) ((str==NULL)?0:strlen(str)) -#define safe_sprintf _snprintf -#define safe_unref_device(dev) do {if (dev != NULL) {libusb_unref_device(dev); dev = NULL;}} while(0) -#define wchar_to_utf8_ms(wstr, str, strlen) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, strlen, NULL, NULL) -inline void upperize(char* str) { - size_t i; - if (str == NULL) return; - for (i=0; i<safe_strlen(str); i++) - str[i] = (char)toupper((int)str[i]); -} - -#define MAX_CTRL_BUFFER_LENGTH 4096 -#define MAX_USB_DEVICES 256 -#define MAX_USB_STRING_LENGTH 128 -#define MAX_HID_REPORT_SIZE 1024 -#define MAX_HID_DESCRIPTOR_SIZE 256 -#define MAX_GUID_STRING_LENGTH 40 -#define MAX_PATH_LENGTH 128 -#define MAX_KEY_LENGTH 256 -#define MAX_TIMER_SEMAPHORES 128 -#define TIMER_REQUEST_RETRY_MS 100 -#define ERR_BUFFER_SIZE 256 -#define LIST_SEPARATOR ';' - -// Handle code for HID interface that have been claimed ("dibs") -#define INTERFACE_CLAIMED ((HANDLE)(intptr_t)0xD1B5) -// Additional return code for HID operations that completed synchronously -#define LIBUSB_COMPLETED (LIBUSB_SUCCESS + 1) - -// http://msdn.microsoft.com/en-us/library/bb663109.aspx -// http://msdn.microsoft.com/en-us/library/bb663093.aspx -#if !defined(GUID_DEVINTERFACE_USB_HOST_CONTROLLER) -const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = { 0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27} }; -#endif -#if !defined(GUID_DEVINTERFACE_USB_DEVICE) -const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED} }; -#endif - - -/* - * Multiple USB API backend support - */ -#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 - -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} }; - -struct windows_usb_api_backend { - const uint8_t id; - const char* designation; - 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; - int (*init)(struct libusb_context *ctx); - int (*exit)(void); - int (*open)(struct libusb_device_handle *dev_handle); - void (*close)(struct libusb_device_handle *dev_handle); - int (*claim_interface)(struct libusb_device_handle *dev_handle, int iface); - int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle, int iface, int altsetting); - int (*release_interface)(struct libusb_device_handle *dev_handle, int iface); - int (*clear_halt)(struct libusb_device_handle *dev_handle, unsigned char endpoint); - int (*reset_device)(struct libusb_device_handle *dev_handle); - int (*submit_bulk_transfer)(struct usbi_transfer *itransfer); - int (*submit_iso_transfer)(struct usbi_transfer *itransfer); - int (*submit_control_transfer)(struct usbi_transfer *itransfer); - int (*abort_control)(struct usbi_transfer *itransfer); - int (*abort_transfers)(struct usbi_transfer *itransfer); - int (*copy_transfer_data)(struct usbi_transfer *itransfer, uint32_t io_size); -}; - -extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX]; - -#define PRINT_UNSUPPORTED_API(fname) \ - usbi_dbg("unsupported API call for '" \ - #fname "' (unrecognized device driver)"); \ - return LIBUSB_ERROR_NOT_SUPPORTED; - -/* - * private structures definition - * with inline pseudo constructors/destructors - */ - -// HCDs -struct windows_hcd_priv { - char *path; - struct windows_hcd_priv *next; -}; - -static inline void windows_hcd_priv_init(struct windows_hcd_priv* p) { - p->path = NULL; - p->next = NULL; -} - -static inline void windows_hcd_priv_release(struct windows_hcd_priv* p) { - safe_free(p->path); -} - -// TODO (v2+): move hid desc to libusb.h? -struct libusb_hid_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t bcdHID; - uint8_t bCountryCode; - uint8_t bNumDescriptors; - uint8_t bClassDescriptorType; - uint16_t wClassDescriptorLength; -}; -#define LIBUSB_DT_HID_SIZE 9 -#define HID_MAX_CONFIG_DESC_SIZE (LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE \ - + LIBUSB_DT_HID_SIZE + 2 * LIBUSB_DT_ENDPOINT_SIZE) -#define HID_MAX_REPORT_SIZE 1024 -#define HID_IN_EP 0x81 -#define HID_OUT_EP 0x02 -#define LIBUSB_REQ_RECIPIENT(request_type) ((request_type) & 0x1F) -#define LIBUSB_REQ_TYPE(request_type) ((request_type) & (0x03 << 5)) -#define LIBUSB_REQ_IN(request_type) ((request_type) & LIBUSB_ENDPOINT_IN) -#define LIBUSB_REQ_OUT(request_type) (!LIBUSB_REQ_IN(request_type)) - -// The following are used for HID reports IOCTLs -#define HID_CTL_CODE(id) \ - CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_NEITHER, FILE_ANY_ACCESS) -#define HID_BUFFER_CTL_CODE(id) \ - CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_BUFFERED, FILE_ANY_ACCESS) -#define HID_IN_CTL_CODE(id) \ - CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_IN_DIRECT, FILE_ANY_ACCESS) -#define HID_OUT_CTL_CODE(id) \ - CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS) - -#define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100) -#define IOCTL_HID_GET_INPUT_REPORT HID_OUT_CTL_CODE(104) -#define IOCTL_HID_SET_FEATURE HID_IN_CTL_CODE(100) -#define IOCTL_HID_SET_OUTPUT_REPORT HID_IN_CTL_CODE(101) - -enum libusb_hid_request_type { - HID_REQ_GET_REPORT = 0x01, - HID_REQ_GET_IDLE = 0x02, - HID_REQ_GET_PROTOCOL = 0x03, - HID_REQ_SET_REPORT = 0x09, - HID_REQ_SET_IDLE = 0x0A, - HID_REQ_SET_PROTOCOL = 0x0B -}; - -enum libusb_hid_report_type { - HID_REPORT_TYPE_INPUT = 0x01, - HID_REPORT_TYPE_OUTPUT = 0x02, - HID_REPORT_TYPE_FEATURE = 0x03 -}; - -struct hid_device_priv { - uint16_t vid; - uint16_t pid; - uint8_t config; - bool uses_report_ids[3]; // input, ouptput, feature - uint16_t input_report_size; - uint16_t output_report_size; - uint16_t feature_report_size; - WCHAR string[3][MAX_USB_STRING_LENGTH]; - uint8_t string_index[3]; // man, prod, ser -}; - -typedef struct libusb_device_descriptor USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR; -struct windows_device_priv { - struct libusb_device *parent_dev; // access to parent is required for usermode ops - ULONG connection_index; // also required for some usermode ops - char *path; // path used by Windows to reference the USB node - struct windows_usb_api_backend const *apib; - struct { - char *path; // each interface needs a Windows device interface path, - struct windows_usb_api_backend const *apib; // an API backend (multiple drivers support), - int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS) - uint8_t *endpoint; - bool restricted_functionality; // indicates if the interface functionality is restricted - // by Windows (eg. HID keyboards or mice cannot do R/W) - } usb_interface[USB_MAXINTERFACES]; - uint8_t composite_api_flags; // HID and composite devices require additional data - struct hid_device_priv *hid; - uint8_t active_config; - USB_DEVICE_DESCRIPTOR dev_descriptor; - unsigned char **config_descriptor; // list of pointers to the cached config descriptors -}; - -static inline void windows_device_priv_init(struct windows_device_priv* p) { - int i; - p->parent_dev = NULL; - p->connection_index = 0; - p->path = NULL; - p->apib = &usb_api_backend[USB_API_UNSUPPORTED]; - p->composite_api_flags = 0; - p->hid = NULL; - p->active_config = 0; - p->config_descriptor = NULL; - memset(&(p->dev_descriptor), 0, sizeof(USB_DEVICE_DESCRIPTOR)); - for (i=0; i<USB_MAXINTERFACES; i++) { - p->usb_interface[i].path = NULL; - p->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED]; - p->usb_interface[i].nb_endpoints = 0; - p->usb_interface[i].endpoint = NULL; - p->usb_interface[i].restricted_functionality = false; - } -} - -static inline void windows_device_priv_release(struct windows_device_priv* p, int num_configurations) { - int i; - safe_free(p->path); - if ((num_configurations > 0) && (p->config_descriptor != NULL)) { - for (i=0; i < num_configurations; i++) - safe_free(p->config_descriptor[i]); - } - safe_free(p->config_descriptor); - safe_free(p->hid); - for (i=0; i<USB_MAXINTERFACES; i++) { - safe_free(p->usb_interface[i].path); - safe_free(p->usb_interface[i].endpoint); - } -} - -static inline struct windows_device_priv *__device_priv(struct libusb_device *dev) { - return (struct windows_device_priv *)dev->os_priv; -} - -struct interface_handle_t { - HANDLE dev_handle; // WinUSB needs an extra handle for the file - HANDLE api_handle; // used by the API to communicate with the device -}; - -struct windows_device_handle_priv { - int active_interface; - struct interface_handle_t interface_handle[USB_MAXINTERFACES]; -#if defined(AUTO_CLAIM) - int autoclaim_count[USB_MAXINTERFACES]; // For auto-release -#endif -}; - -static inline struct windows_device_handle_priv *__device_handle_priv( - struct libusb_device_handle *handle) -{ - return (struct windows_device_handle_priv *) handle->os_priv; -} - -// used for async polling functions -struct windows_transfer_priv { - struct winfd pollable_fd; - uint8_t interface_number; - uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID - uint8_t *hid_dest; // transfer buffer destination, required for HID - size_t hid_expected_size; -}; - -// used to match a device driver (including filter drivers) against a supported API -struct driver_lookup { - char list[MAX_KEY_LENGTH+1];// REG_MULTI_SZ list of services (driver) names - const DWORD reg_prop; // SPDRP registry key to use to retreive list - const char* designation; // internal designation (for debug output) -}; - -/* - * 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 = NULL - -#define DLL_LOAD(dll, name, ret_on_failure) \ - do { \ - HMODULE h = GetModuleHandle(#dll); \ - if (!h) \ - h = LoadLibrary(#dll); \ - if (!h) { \ - if (ret_on_failure) { return LIBUSB_ERROR_NOT_FOUND; }\ - else { break; } \ - } \ - name = (__dll_##name##_t)GetProcAddress(h, #name); \ - if (name) break; \ - name = (__dll_##name##_t)GetProcAddress(h, #name "A"); \ - if (name) break; \ - name = (__dll_##name##_t)GetProcAddress(h, #name "W"); \ - if (name) break; \ - if(ret_on_failure) \ - return LIBUSB_ERROR_NOT_FOUND; \ - } while(0) - - -/* - * Windows DDK API definitions. Most of it copied from MinGW's includes - */ -typedef DWORD DEVNODE, DEVINST; -typedef DEVNODE *PDEVNODE, *PDEVINST; -typedef DWORD RETURN_TYPE; -typedef RETURN_TYPE CONFIGRET; - -#define CR_SUCCESS 0x00000000 -#define CR_NO_SUCH_DEVNODE 0x0000000D - -#define USB_DEVICE_DESCRIPTOR_TYPE LIBUSB_DT_DEVICE -#define USB_CONFIGURATION_DESCRIPTOR_TYPE LIBUSB_DT_CONFIG -#define USB_STRING_DESCRIPTOR_TYPE LIBUSB_DT_STRING -#define USB_INTERFACE_DESCRIPTOR_TYPE LIBUSB_DT_INTERFACE -#define USB_ENDPOINT_DESCRIPTOR_TYPE LIBUSB_DT_ENDPOINT - -#define USB_REQUEST_GET_STATUS LIBUSB_REQUEST_GET_STATUS -#define USB_REQUEST_CLEAR_FEATURE LIBUSB_REQUEST_CLEAR_FEATURE -#define USB_REQUEST_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE -#define USB_REQUEST_SET_ADDRESS LIBUSB_REQUEST_SET_ADDRESS -#define USB_REQUEST_GET_DESCRIPTOR LIBUSB_REQUEST_GET_DESCRIPTOR -#define USB_REQUEST_SET_DESCRIPTOR LIBUSB_REQUEST_SET_DESCRIPTOR -#define USB_REQUEST_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION -#define USB_REQUEST_SET_CONFIGURATION LIBUSB_REQUEST_SET_CONFIGURATION -#define USB_REQUEST_GET_INTERFACE LIBUSB_REQUEST_GET_INTERFACE -#define USB_REQUEST_SET_INTERFACE LIBUSB_REQUEST_SET_INTERFACE -#define USB_REQUEST_SYNC_FRAME LIBUSB_REQUEST_SYNCH_FRAME - -#define HCD_GET_ROOT_HUB_NAME 258 -#define USB_GET_NODE_INFORMATION 258 -#define USB_GET_NODE_CONNECTION_INFORMATION 259 -#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260 -#define USB_GET_NODE_CONNECTION_NAME 261 -#define USB_GET_HUB_CAPABILITIES 271 -#if !defined(USB_GET_HUB_CAPABILITIES_EX) -#define USB_GET_HUB_CAPABILITIES_EX 276 -#endif - -#ifndef METHOD_BUFFERED -#define METHOD_BUFFERED 0 -#endif -#ifndef FILE_ANY_ACCESS -#define FILE_ANY_ACCESS 0x00000000 -#endif -#ifndef FILE_DEVICE_UNKNOWN -#define FILE_DEVICE_UNKNOWN 0x00000022 -#endif -#ifndef FILE_DEVICE_USB -#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN -#endif - -#ifndef CTL_CODE -#define CTL_CODE(DeviceType, Function, Method, Access)( \ - ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) -#endif - -typedef enum _USB_CONNECTION_STATUS { - NoDeviceConnected, - DeviceConnected, - DeviceFailedEnumeration, - DeviceGeneralFailure, - DeviceCausedOvercurrent, - DeviceNotEnoughPower, - DeviceNotEnoughBandwidth, - DeviceHubNestedTooDeeply, - DeviceInLegacyHub -} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS; - -typedef enum _USB_HUB_NODE { - UsbHub, - UsbMIParent -} 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)); -DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG)); -DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Device_IDW, (DEVINST, PWCHAR, ULONG, ULONG)); - -#ifdef UNICODE -#define CM_Get_Device_ID CM_Get_Device_IDW -#else -#define CM_Get_Device_ID CM_Get_Device_IDA -#endif /* UNICODE */ - -#define IOCTL_USB_GET_HUB_CAPABILITIES_EX \ - CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_HUB_CAPABILITIES \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_ROOT_HUB_NAME \ - CTL_CODE(FILE_DEVICE_USB, HCD_GET_ROOT_HUB_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_INFORMATION \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_ATTRIBUTES, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_CONNECTION_NAME \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// Most of the structures below need to be packed -#pragma pack(push, 1) - -typedef struct _USB_INTERFACE_DESCRIPTOR { - UCHAR bLength; - UCHAR bDescriptorType; - UCHAR bInterfaceNumber; - UCHAR bAlternateSetting; - UCHAR bNumEndpoints; - UCHAR bInterfaceClass; - UCHAR bInterfaceSubClass; - UCHAR bInterfaceProtocol; - UCHAR iInterface; -} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR; - -typedef struct _USB_CONFIGURATION_DESCRIPTOR { - UCHAR bLength; - UCHAR bDescriptorType; - USHORT wTotalLength; - UCHAR bNumInterfaces; - UCHAR bConfigurationValue; - UCHAR iConfiguration; - UCHAR bmAttributes; - UCHAR MaxPower; -} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR; - -typedef struct _USB_CONFIGURATION_DESCRIPTOR_SHORT { - struct { - ULONG ConnectionIndex; - struct { - UCHAR bmRequest; - UCHAR bRequest; - USHORT wValue; - USHORT wIndex; - USHORT wLength; - } SetupPacket; - } req; - USB_CONFIGURATION_DESCRIPTOR data; -} USB_CONFIGURATION_DESCRIPTOR_SHORT; - -typedef struct _USB_ENDPOINT_DESCRIPTOR { - UCHAR bLength; - UCHAR bDescriptorType; - UCHAR bEndpointAddress; - UCHAR bmAttributes; - USHORT wMaxPacketSize; - UCHAR bInterval; -} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR; - -typedef struct _USB_DESCRIPTOR_REQUEST { - ULONG ConnectionIndex; - struct { - UCHAR bmRequest; - UCHAR bRequest; - USHORT wValue; - USHORT wIndex; - USHORT wLength; - } SetupPacket; -// UCHAR Data[0]; -} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; - -typedef struct _USB_HUB_DESCRIPTOR { - UCHAR bDescriptorLength; - UCHAR bDescriptorType; - UCHAR bNumberOfPorts; - USHORT wHubCharacteristics; - UCHAR bPowerOnToPowerGood; - UCHAR bHubControlCurrent; - UCHAR bRemoveAndPowerMask[64]; -} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR; - -typedef struct _USB_ROOT_HUB_NAME { - ULONG ActualLength; - WCHAR RootHubName[1]; -} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME; - -typedef struct _USB_ROOT_HUB_NAME_FIXED { - ULONG ActualLength; - WCHAR RootHubName[MAX_PATH_LENGTH]; -} USB_ROOT_HUB_NAME_FIXED; - -typedef struct _USB_NODE_CONNECTION_NAME { - ULONG ConnectionIndex; - ULONG ActualLength; - WCHAR NodeName[1]; -} USB_NODE_CONNECTION_NAME, *PUSB_NODE_CONNECTION_NAME; - -typedef struct _USB_NODE_CONNECTION_NAME_FIXED { - ULONG ConnectionIndex; - ULONG ActualLength; - WCHAR NodeName[MAX_PATH_LENGTH]; -} USB_NODE_CONNECTION_NAME_FIXED; - -typedef struct _USB_HUB_NAME_FIXED { - union { - USB_ROOT_HUB_NAME_FIXED root; - USB_NODE_CONNECTION_NAME_FIXED node; - } u; -} USB_HUB_NAME_FIXED; - - -typedef struct _USB_HUB_INFORMATION { - USB_HUB_DESCRIPTOR HubDescriptor; - BOOLEAN HubIsBusPowered; -} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION; - -typedef struct _USB_MI_PARENT_INFORMATION { - ULONG NumberOfInterfaces; -} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION; - -typedef struct _USB_NODE_INFORMATION { - USB_HUB_NODE NodeType; - union { - USB_HUB_INFORMATION HubInformation; - USB_MI_PARENT_INFORMATION MiParentInformation; - } u; -} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION; - -typedef struct _USB_PIPE_INFO { - USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; - ULONG ScheduleOffset; -} USB_PIPE_INFO, *PUSB_PIPE_INFO; - -typedef struct _USB_NODE_CONNECTION_INFORMATION { - ULONG ConnectionIndex; - USB_DEVICE_DESCRIPTOR DeviceDescriptor; - UCHAR CurrentConfigurationValue; - BOOLEAN LowSpeed; - BOOLEAN DeviceIsHub; - USHORT DeviceAddress; - ULONG NumberOfOpenPipes; - USB_CONNECTION_STATUS ConnectionStatus; -// USB_PIPE_INFO PipeList[0]; -} USB_NODE_CONNECTION_INFORMATION, *PUSB_NODE_CONNECTION_INFORMATION; - -typedef struct _USB_HUB_CAP_FLAGS { - ULONG HubIsHighSpeedCapable:1; - ULONG HubIsHighSpeed:1; - ULONG HubIsMultiTtCapable:1; - ULONG HubIsMultiTt:1; - ULONG HubIsRoot:1; - ULONG HubIsArmedWakeOnConnect:1; - ULONG ReservedMBZ:26; -} USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS; - -typedef struct _USB_HUB_CAPABILITIES { - ULONG HubIs2xCapable : 1; -} USB_HUB_CAPABILITIES, *PUSB_HUB_CAPABILITIES; - -typedef struct _USB_HUB_CAPABILITIES_EX { - USB_HUB_CAP_FLAGS CapabilityFlags; -} USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX; - -#pragma pack(pop) - -/* winusb.dll interface */ - -#define SHORT_PACKET_TERMINATE 0x01 -#define AUTO_CLEAR_STALL 0x02 -#define PIPE_TRANSFER_TIMEOUT 0x03 -#define IGNORE_SHORT_PACKETS 0x04 -#define ALLOW_PARTIAL_READS 0x05 -#define AUTO_FLUSH 0x06 -#define RAW_IO 0x07 -#define MAXIMUM_TRANSFER_SIZE 0x08 -#define AUTO_SUSPEND 0x81 -#define SUSPEND_DELAY 0x83 -#define DEVICE_SPEED 0x01 -#define LowSpeed 0x01 -#define FullSpeed 0x02 -#define HighSpeed 0x03 - -typedef enum _USBD_PIPE_TYPE { - UsbdPipeTypeControl, - UsbdPipeTypeIsochronous, - UsbdPipeTypeBulk, - UsbdPipeTypeInterrupt -} USBD_PIPE_TYPE; - -typedef struct { - USBD_PIPE_TYPE PipeType; - UCHAR PipeId; - USHORT MaximumPacketSize; - UCHAR Interval; -} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION; - -#pragma pack(1) -typedef struct { - UCHAR request_type; - UCHAR request; - USHORT value; - USHORT index; - USHORT length; -} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET; -#pragma pack() - -typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; - -DLL_DECLARE(WINAPI, BOOL, WinUsb_Initialize, (HANDLE, PWINUSB_INTERFACE_HANDLE)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_Free, (WINUSB_INTERFACE_HANDLE)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_GetAssociatedInterface, (WINUSB_INTERFACE_HANDLE, UCHAR, PWINUSB_INTERFACE_HANDLE)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_GetDescriptor, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, USHORT, PUCHAR, ULONG, PULONG)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryInterfaceSettings, (WINUSB_INTERFACE_HANDLE, UCHAR, PUSB_INTERFACE_DESCRIPTOR)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryDeviceInformation, (WINUSB_INTERFACE_HANDLE, ULONG, PULONG, PVOID)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_SetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, UCHAR)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_GetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, PUCHAR)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, PWINUSB_PIPE_INFORMATION)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_SetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, ULONG, PVOID)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_GetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, PULONG, PVOID)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_ReadPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_WritePipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_ControlTransfer, (WINUSB_INTERFACE_HANDLE, WINUSB_SETUP_PACKET, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); -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)); - -/* hid.dll interface */ - -#define HIDP_STATUS_SUCCESS 0x110000 -typedef void* PHIDP_PREPARSED_DATA; - -#pragma pack(1) -typedef struct { - ULONG Size; - USHORT VendorID; - USHORT ProductID; - USHORT VersionNumber; -} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; -#pragma pack() - -typedef USHORT USAGE; -typedef struct { - USAGE Usage; - USAGE UsagePage; - USHORT InputReportByteLength; - USHORT OutputReportByteLength; - USHORT FeatureReportByteLength; - USHORT Reserved[17]; - USHORT NumberLinkCollectionNodes; - USHORT NumberInputButtonCaps; - USHORT NumberInputValueCaps; - USHORT NumberInputDataIndices; - USHORT NumberOutputButtonCaps; - USHORT NumberOutputValueCaps; - USHORT NumberOutputDataIndices; - USHORT NumberFeatureButtonCaps; - USHORT NumberFeatureValueCaps; - USHORT NumberFeatureDataIndices; -} HIDP_CAPS, *PHIDP_CAPS; - -typedef enum _HIDP_REPORT_TYPE { - HidP_Input, - HidP_Output, - HidP_Feature -} HIDP_REPORT_TYPE; - -typedef struct _HIDP_VALUE_CAPS { - USAGE UsagePage; - UCHAR ReportID; - BOOLEAN IsAlias; - USHORT BitField; - USHORT LinkCollection; - USAGE LinkUsage; - USAGE LinkUsagePage; - BOOLEAN IsRange; - BOOLEAN IsStringRange; - BOOLEAN IsDesignatorRange; - BOOLEAN IsAbsolute; - BOOLEAN HasNull; - UCHAR Reserved; - USHORT BitSize; - USHORT ReportCount; - USHORT Reserved2[5]; - ULONG UnitsExp; - ULONG Units; - LONG LogicalMin, LogicalMax; - LONG PhysicalMin, PhysicalMax; - union { - struct { - USAGE UsageMin, UsageMax; - USHORT StringMin, StringMax; - USHORT DesignatorMin, DesignatorMax; - USHORT DataIndexMin, DataIndexMax; - } Range; - struct { - USAGE Usage, Reserved1; - USHORT StringIndex, Reserved2; - USHORT DesignatorIndex, Reserved3; - USHORT DataIndex, Reserved4; - } NotRange; - } u; -} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS; - -DLL_DECLARE(WINAPI, BOOL, HidD_GetAttributes, (HANDLE, PHIDD_ATTRIBUTES)); -DLL_DECLARE(WINAPI, VOID, HidD_GetHidGuid, (LPGUID)); -DLL_DECLARE(WINAPI, BOOL, HidD_GetPreparsedData, (HANDLE, PHIDP_PREPARSED_DATA *)); -DLL_DECLARE(WINAPI, BOOL, HidD_FreePreparsedData, (PHIDP_PREPARSED_DATA)); -DLL_DECLARE(WINAPI, BOOL, HidD_GetManufacturerString, (HANDLE, PVOID, ULONG)); -DLL_DECLARE(WINAPI, BOOL, HidD_GetProductString, (HANDLE, PVOID, ULONG)); -DLL_DECLARE(WINAPI, BOOL, HidD_GetSerialNumberString, (HANDLE, PVOID, ULONG)); -DLL_DECLARE(WINAPI, LONG, HidP_GetCaps, (PHIDP_PREPARSED_DATA, PHIDP_CAPS)); -DLL_DECLARE(WINAPI, BOOL, HidD_SetNumInputBuffers, (HANDLE, ULONG)); -DLL_DECLARE(WINAPI, BOOL, HidD_SetFeature, (HANDLE, PVOID, ULONG)); -DLL_DECLARE(WINAPI, BOOL, HidD_GetFeature, (HANDLE, PVOID, ULONG)); -DLL_DECLARE(WINAPI, BOOL, HidD_GetPhysicalDescriptor, (HANDLE, PVOID, ULONG)); -DLL_DECLARE(WINAPI, BOOL, HidD_GetInputReport, (HANDLE, PVOID, ULONG)); -DLL_DECLARE(WINAPI, BOOL, HidD_SetOutputReport, (HANDLE, PVOID, ULONG)); -DLL_DECLARE(WINAPI, BOOL, HidD_FlushQueue, (HANDLE)); -DLL_DECLARE(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA)); |