summaryrefslogtreecommitdiffstats
path: root/libusb-1.0/libusb/os
diff options
context:
space:
mode:
authorBenjamin Dobell <benjamin.dobell@glassechidna.com.au>2011-07-17 11:50:07 +0200
committerBenjamin Dobell <benjamin.dobell@glassechidna.com.au>2011-07-17 11:50:07 +0200
commit8cb7f6ee8f872938e257541c07d0e4b2ad0e3f35 (patch)
tree7b40d7e1a5c28b2e05b01cd9e348aabd60f2d19c /libusb-1.0/libusb/os
parentAltered the user interface slightly to prevent clipping on certain OS. (diff)
downloadHeimdall-8cb7f6ee8f872938e257541c07d0e4b2ad0e3f35.tar
Heimdall-8cb7f6ee8f872938e257541c07d0e4b2ad0e3f35.tar.gz
Heimdall-8cb7f6ee8f872938e257541c07d0e4b2ad0e3f35.tar.bz2
Heimdall-8cb7f6ee8f872938e257541c07d0e4b2ad0e3f35.tar.lz
Heimdall-8cb7f6ee8f872938e257541c07d0e4b2ad0e3f35.tar.xz
Heimdall-8cb7f6ee8f872938e257541c07d0e4b2ad0e3f35.tar.zst
Heimdall-8cb7f6ee8f872938e257541c07d0e4b2ad0e3f35.zip
Diffstat (limited to '')
-rw-r--r--libusb-1.0/libusb/os/darwin_usb.c1545
-rw-r--r--libusb-1.0/libusb/os/darwin_usb.h167
-rw-r--r--libusb-1.0/libusb/os/linux_usbfs.c2220
-rw-r--r--libusb-1.0/libusb/os/linux_usbfs.h138
-rw-r--r--libusb-1.0/libusb/os/poll_posix.h12
-rw-r--r--libusb-1.0/libusb/os/poll_windows.c857
-rw-r--r--libusb-1.0/libusb/os/poll_windows.h122
-rw-r--r--libusb-1.0/libusb/os/threads_posix.h46
-rw-r--r--libusb-1.0/libusb/os/threads_windows.c221
-rw-r--r--libusb-1.0/libusb/os/threads_windows.h84
-rw-r--r--libusb-1.0/libusb/os/windows_usb.c4204
-rw-r--r--libusb-1.0/libusb/os/windows_usb.h784
12 files changed, 0 insertions, 10400 deletions
diff --git a/libusb-1.0/libusb/os/darwin_usb.c b/libusb-1.0/libusb/os/darwin_usb.c
deleted file mode 100644
index 646c938..0000000
--- a/libusb-1.0/libusb/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/libusb-1.0/libusb/os/darwin_usb.h b/libusb-1.0/libusb/os/darwin_usb.h
deleted file mode 100644
index a71d464..0000000
--- a/libusb-1.0/libusb/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/libusb-1.0/libusb/os/linux_usbfs.c b/libusb-1.0/libusb/os/linux_usbfs.c
deleted file mode 100644
index 5c2a6e8..0000000
--- a/libusb-1.0/libusb/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, 0);
- 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, 1);
- 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/libusb-1.0/libusb/os/linux_usbfs.h b/libusb-1.0/libusb/os/linux_usbfs.h
deleted file mode 100644
index bd02edc..0000000
--- a/libusb-1.0/libusb/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/libusb-1.0/libusb/os/poll_posix.h b/libusb-1.0/libusb/os/poll_posix.h
deleted file mode 100644
index 17298a5..0000000
--- a/libusb-1.0/libusb/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/libusb-1.0/libusb/os/poll_windows.c b/libusb-1.0/libusb/os/poll_windows.c
deleted file mode 100644
index 55dbc18..0000000
--- a/libusb-1.0/libusb/os/poll_windows.c
+++ /dev/null
@@ -1,857 +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 _open(char* name, int flags);
-extern int _close(int fd);
-extern int _snprintf(char *buffer, size_t count, const char *format, ...);
-#define NUL_DEVICE "/dev/null"
-#else
-#define NUL_DEVICE "NUL"
-#endif
-
-#define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0)
-
-// Workaround for MinGW-w64 multilib bug
-#if defined(_MSC_VER) || defined(_WIN64)
-#define INIT_INTERLOCKEDEXCHANGE
-#define pInterlockedExchange InterlockedExchange
-#else
-static LONG (WINAPI *pInterlockedExchange)(LONG volatile *, LONG) = NULL;
-#define INIT_INTERLOCKEDEXCHANGE if (pInterlockedExchange == NULL) { \
- pInterlockedExchange = (LONG (WINAPI *)(LONG volatile *, LONG)) \
- GetProcAddress(GetModuleHandle("KERNEL32"), "InterlockedExchange"); \
- if (pInterlockedExchange == NULL) { \
- usbi_err(NULL, "InterlockedExchange is unavailable"); \
- return; \
- } \
-}
-#endif
-
-// 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;
-
- INIT_INTERLOCKEDEXCHANGE;
- while (pInterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
- SleepEx(0, TRUE);
- }
- if (!is_polling_set) {
- pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED))
- GetProcAddress(GetModuleHandleA("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;
-
- INIT_INTERLOCKEDEXCHANGE;
- while (pInterlockedExchange((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;
- 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"
- filedes[0] = _open(NUL_DEVICE, _O_WRONLY);
- if (filedes[0] < 0) {
- usbi_err(NULL, "could not create pipe: errno %d", errno);
- goto out1;
- }
- // 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 = DUMMY_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:
- _close(filedes[0]);
-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, using
- // the same fd attribution system as the pipe ends
- fd = _open(NUL_DEVICE, _O_WRONLY);
- 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);
- }
- r = _close(poll_fd[_index].fd);
- if (r != 0) {
- errno = EIO;
- }
- 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/libusb-1.0/libusb/os/poll_windows.h b/libusb-1.0/libusb/os/poll_windows.h
deleted file mode 100644
index 36e3915..0000000
--- a/libusb-1.0/libusb/os/poll_windows.h
+++ /dev/null
@@ -1,122 +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)
-
-#define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2)
-
-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/libusb-1.0/libusb/os/threads_posix.h b/libusb-1.0/libusb/os/threads_posix.h
deleted file mode 100644
index dc558d4..0000000
--- a/libusb-1.0/libusb/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/libusb-1.0/libusb/os/threads_windows.c b/libusb-1.0/libusb/os/threads_windows.c
deleted file mode 100644
index fe84ec0..0000000
--- a/libusb-1.0/libusb/os/threads_windows.c
+++ /dev/null
@@ -1,221 +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"
-
-// Workaround for MinGW-w64 multilib bug
-#if defined(_MSC_VER) || defined(_WIN64)
-#define INIT_INTERLOCKEDEXCHANGE
-#define pInterlockedExchange InterlockedExchange
-#else
-static LONG (WINAPI *pInterlockedExchange)(LONG volatile *, LONG) = NULL;
-#define INIT_INTERLOCKEDEXCHANGE if (pInterlockedExchange == NULL) { \
- pInterlockedExchange = (LONG (WINAPI *)(LONG volatile *, LONG)) \
- GetProcAddress(GetModuleHandle("KERNEL32"), "InterlockedExchange"); \
- if (pInterlockedExchange == NULL) return ((errno=ENOENT)); \
- }
-#endif
-
-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));
- INIT_INTERLOCKEDEXCHANGE;
- while (pInterlockedExchange((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/libusb-1.0/libusb/os/threads_windows.h b/libusb-1.0/libusb/os/threads_windows.h
deleted file mode 100644
index 2cd1867..0000000
--- a/libusb-1.0/libusb/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/libusb-1.0/libusb/os/windows_usb.c b/libusb-1.0/libusb/os/windows_usb.c
deleted file mode 100644
index 9223afb..0000000
--- a/libusb-1.0/libusb/os/windows_usb.c
+++ /dev/null
@@ -1,4204 +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
- * Hash table functions adapted from glibc, by Ulrich Drepper et al.
- * 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
-
-// TODO: move all the assertion failures to usbi_err
-
-#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>
-#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);
-// HUB (limited) API prototypes
-static int hub_open(struct libusb_device_handle *dev_handle);
-static void hub_close(struct libusb_device_handle *dev_handle);
-// 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_configure_endpoints(struct libusb_device_handle *dev_handle, int iface);
-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);
-
-// Workaround for MinGW-w64 multilib bug
-#if defined(_MSC_VER) || defined(_WIN64)
-#define INIT_INTERLOCKEDEXCHANGE
-#define INIT_INTERLOCKEDINCREMENT
-#define pInterlockedExchange InterlockedExchange
-#define pInterlockedIncrement InterlockedIncrement
-#else
-static LONG (WINAPI *pInterlockedExchange)(LONG volatile *, LONG) = NULL;
-#define INIT_INTERLOCKEDEXCHANGE if (pInterlockedExchange == NULL) { \
- pInterlockedExchange = (LONG (WINAPI *)(LONG volatile *, LONG)) \
- GetProcAddress(GetModuleHandle("KERNEL32"), "InterlockedExchange"); \
- if (pInterlockedExchange == NULL) { \
- usbi_err(NULL, "InterlockedExchange is unavailable"); \
- return 1; \
- } \
-}
-static LONG (WINAPI *pInterlockedIncrement)(LONG volatile *) = NULL;
-#define INIT_INTERLOCKEDINCREMENT if (pInterlockedIncrement == NULL) { \
- pInterlockedIncrement = (LONG (WINAPI *)(LONG volatile *)) \
- GetProcAddress(GetModuleHandle("KERNEL32"), "InterlockedIncrement");\
- if (pInterlockedIncrement == NULL) { \
- usbi_err(NULL, "IInterlockedIncrement is unavailable"); \
- return LIBUSB_ERROR_NOT_FOUND; \
- } \
-}
-#endif
-
-// Global variables
-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)
-
-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 defined(ENABLE_DEBUG_LOGGING) || defined(INCLUDE_DEBUG_LOGGING)
-static char* guid_to_string(const GUID* guid)
-{
- static char guid_string[MAX_GUID_STRING_LENGTH];
-
- if (guid == NULL) return NULL;
- 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), &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, OLE32 and SetupAPI DLL functions
- */
-static int init_dlls(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);
- // Prefixed to avoid conflict with header files
- DLL_LOAD_PREFIXED(OLE32.dll, p, CLSIDFromString, TRUE);
- DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiGetClassDevsA, TRUE);
- DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiEnumDeviceInfo, TRUE);
- DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiEnumDeviceInterfaces, TRUE);
- DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiGetDeviceInterfaceDetailA, TRUE);
- DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiDestroyDeviceInfoList, TRUE);
- DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiOpenDevRegKey, TRUE);
- DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiGetDeviceRegistryPropertyA, TRUE);
- DLL_LOAD_PREFIXED(AdvAPI32.dll, p, RegQueryValueExW, TRUE);
- DLL_LOAD_PREFIXED(AdvAPI32.dll, p, RegCloseKey, TRUE);
- return LIBUSB_SUCCESS;
-}
-
-/*
- * enumerate interfaces for the whole USB class
- *
- * 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.
- */
-bool get_devinfo_data(struct libusb_context *ctx,
- HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, unsigned _index)
-{
- if (_index <= 0) {
- *dev_info = pSetupDiGetClassDevsA(NULL, "USB", NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES);
- if (*dev_info == INVALID_HANDLE_VALUE) {
- return false;
- }
- }
-
- dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
- if (!pSetupDiEnumDeviceInfo(*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));
- }
- pSetupDiDestroyDeviceInfoList(*dev_info);
- *dev_info = INVALID_HANDLE_VALUE;
- return false;
- }
- return true;
-}
-
-/*
- * 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_A *get_interface_details(struct libusb_context *ctx,
- HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const GUID* guid, unsigned _index)
-{
- SP_DEVICE_INTERFACE_DATA dev_interface_data;
- SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL;
- DWORD size;
-
- if (_index <= 0) {
- *dev_info = pSetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
- }
-
- if (dev_info_data != NULL) {
- dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
- if (!pSetupDiEnumDeviceInfo(*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));
- }
- pSetupDiDestroyDeviceInfoList(*dev_info);
- *dev_info = INVALID_HANDLE_VALUE;
- return NULL;
- }
- }
-
- dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- if (!pSetupDiEnumDeviceInterfaces(*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));
- }
- pSetupDiDestroyDeviceInfoList(*dev_info);
- *dev_info = INVALID_HANDLE_VALUE;
- return NULL;
- }
-
- // Read interface data (dummy + actual) to access the device path
- if (!pSetupDiGetDeviceInterfaceDetailA(*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_A);
- if (!pSetupDiGetDeviceInterfaceDetailA(*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:
- pSetupDiDestroyDeviceInfoList(*dev_info);
- *dev_info = INVALID_HANDLE_VALUE;
- return NULL;
-}
-
-/* Hash table functions - modified From glibc 2.3.2:
- [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
- [Knuth] The Art of Computer Programming, part 3 (6.4) */
-typedef struct htab_entry {
- unsigned long used;
- char* str;
-} htab_entry;
-htab_entry* htab_table = NULL;
-usbi_mutex_t htab_write_mutex = NULL;
-unsigned long htab_size, htab_filled;
-
-/* For the used double hash method the table size has to be a prime. To
- correct the user given table size we need a prime test. This trivial
- algorithm is adequate because the code is called only during init and
- the number is likely to be small */
-static int isprime(unsigned long number)
-{
- // no even number will be passed
- unsigned int divider = 3;
-
- while((divider * divider < number) && (number % divider != 0))
- divider += 2;
-
- return (number % divider != 0);
-}
-
-/* Before using the hash table we must allocate memory for it.
- We allocate one element more as the found prime number says.
- This is done for more effective indexing as explained in the
- comment for the hash function. */
-int htab_create(struct libusb_context *ctx, unsigned long nel)
-{
- if (htab_table != NULL) {
- usbi_err(ctx, "hash table already allocated");
- }
-
- // Create a mutex
- usbi_mutex_init(&htab_write_mutex, NULL);
-
- // Change nel to the first prime number not smaller as nel.
- nel |= 1;
- while(!isprime(nel))
- nel += 2;
-
- htab_size = nel;
- usbi_dbg("using %d entries hash table", nel);
- htab_filled = 0;
-
- // allocate memory and zero out.
- htab_table = (htab_entry*)calloc(htab_size + 1, sizeof(htab_entry));
- if (htab_table == NULL) {
- usbi_err(ctx, "could not allocate space for hash table");
- return 0;
- }
-
- return 1;
-}
-
-/* After using the hash table it has to be destroyed. */
-void htab_destroy(void)
-{
- size_t i;
- if (htab_table == NULL) {
- return;
- }
-
- for (i=0; i<htab_size; i++) {
- if (htab_table[i].used) {
- safe_free(htab_table[i].str);
- }
- }
- usbi_mutex_destroy(&htab_write_mutex);
- safe_free(htab_table);
-}
-
-/* This is the search function. It uses double hashing with open addressing.
- We use an trick to speed up the lookup. The table is created with one
- more element available. This enables us to use the index zero special.
- This index will never be used because we store the first hash index in
- the field used where zero means not used. Every other value means used.
- The used field can be used as a first fast comparison for equality of
- the stored and the parameter value. This helps to prevent unnecessary
- expensive calls of strcmp. */
-unsigned long htab_hash(char* str)
-{
- unsigned long hval, hval2;
- unsigned long idx;
- unsigned long r = 5381;
- int c;
- char* sz = str;
-
- // Compute main hash value (algorithm suggested by Nokia)
- while ((c = *sz++))
- r = ((r << 5) + r) + c;
- if (r == 0)
- ++r;
-
- // compute table hash: simply take the modulus
- hval = r % htab_size;
- if (hval == 0)
- ++hval;
-
- // Try the first index
- idx = hval;
-
- if (htab_table[idx].used) {
- if ( (htab_table[idx].used == hval)
- && (safe_strcmp(str, htab_table[idx].str) == 0) ) {
- // existing hash
- return idx;
- }
- usbi_dbg("hash collision ('%s' vs '%s')", str, htab_table[idx].str);
-
- // Second hash function, as suggested in [Knuth]
- hval2 = 1 + hval % (htab_size - 2);
-
- do {
- // Because size is prime this guarantees to step through all available indexes
- if (idx <= hval2) {
- idx = htab_size + idx - hval2;
- } else {
- idx -= hval2;
- }
-
- // If we visited all entries leave the loop unsuccessfully
- if (idx == hval) {
- break;
- }
-
- // If entry is found use it.
- if ( (htab_table[idx].used == hval)
- && (safe_strcmp(str, htab_table[idx].str) == 0) ) {
- return idx;
- }
- }
- while (htab_table[idx].used);
- }
-
- // Not found => New entry
-
- // If the table is full return an error
- if (htab_filled >= htab_size) {
- usbi_err(NULL, "hash table is full (%d entries)", htab_size);
- return 0;
- }
-
- // Concurrent threads might be storing the same entry at the same time
- // (eg. "simultaneous" enums from different threads) => use a mutex
- usbi_mutex_lock(&htab_write_mutex);
- // Just free any previously allocated string (which should be the same as
- // new one). The possibility of concurrent threads storing a collision
- // string (same hash, different string) at the same time is extremely low
- safe_free(htab_table[idx].str);
- htab_table[idx].used = hval;
- htab_table[idx].str = malloc(safe_strlen(str)+1);
- if (htab_table[idx].str == NULL) {
- usbi_err(NULL, "could not duplicate string for hash table");
- usbi_mutex_unlock(&htab_write_mutex);
- return 0;
- }
- memcpy(htab_table[idx].str, str, safe_strlen(str)+1);
- ++htab_filled;
- usbi_mutex_unlock(&htab_write_mutex);
-
- return idx;
-}
-
-/*
- * Returns the session ID of a device's nth level ancestor
- * If there's no device at the nth level, return 0
- */
-static unsigned long get_ancestor_session_id(DWORD devinst, unsigned level)
-{
- DWORD parent_devinst;
- unsigned long session_id = 0;
- char* sanitized_path = NULL;
- char path[MAX_PATH_LENGTH];
- unsigned i;
-
- if (level < 1) return 0;
- for (i = 0; i<level; i++) {
- if (CM_Get_Parent(&parent_devinst, devinst, 0) != CR_SUCCESS) {
- return 0;
- }
- devinst = parent_devinst;
- }
- if (CM_Get_Device_IDA(devinst, path, MAX_PATH_LENGTH, 0) != CR_SUCCESS) {
- return 0;
- }
- // TODO (post hotplug): try without sanitizing
- sanitized_path = sanitize_path(path);
- if (sanitized_path == NULL) {
- return 0;
- }
- session_id = htab_hash(sanitized_path);
- safe_free(sanitized_path);
- return session_id;
-}
-
-/*
- * Populate the endpoints addresses of the device_priv interface helper structs
- */
-static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, int iface, int altsetting)
-{
- int i, r;
- struct windows_device_priv *priv = __device_priv(dev_handle->dev);
- struct libusb_config_descriptor *conf_desc;
- const struct libusb_interface_descriptor *if_desc;
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
-
- r = libusb_get_config_descriptor(dev_handle->dev, 0, &conf_desc);
- if (r != LIBUSB_SUCCESS) {
- usbi_warn(ctx, "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);
-
- // Extra init is required for WinUSB endpoints
- if (priv->apib->id == USB_API_WINUSB) {
- return winusb_configure_endpoints(dev_handle, iface);
- }
-
- 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->id == 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)
-{
- int i, r = LIBUSB_ERROR_OTHER;
- OSVERSIONINFO os_version;
- HANDLE semaphore;
- char sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID)
-
- sprintf(sem_name, "libusb_init%08X", (unsigned int)GetCurrentProcessId()&0xFFFFFFFF);
- semaphore = CreateSemaphoreA(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?
- // 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 DLL imports
- if (init_dlls() != LIBUSB_SUCCESS) {
- usbi_err(ctx, "could not resolve 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);
-
- // Create a hash table to store session ids. Second parameter is better if prime
- htab_create(ctx, HTAB_SIZE);
-
- 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;
- }
- htab_destroy();
- }
-
- 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;
-}
-
-/*
- * HCD (root) hubs need to have their device descriptor manually populated
- *
- * Note that, like Microsoft does in the device manager, we populate the
- * Vendor and Device ID for HCD hubs with the ones from the PCI HCD device.
- */
-static int force_hcd_device_descriptor(struct libusb_device *dev)
-{
- struct windows_device_priv *parent_priv, *priv = __device_priv(dev);
- struct libusb_context *ctx = DEVICE_CTX(dev);
- int vid, pid;
-
- dev->num_configurations = 1;
- priv->dev_descriptor.bLength = sizeof(USB_DEVICE_DESCRIPTOR);
- priv->dev_descriptor.bDescriptorType = USB_DEVICE_DESCRIPTOR_TYPE;
- priv->dev_descriptor.bNumConfigurations = 1;
- priv->active_config = 1;
-
- if (priv->parent_dev == NULL) {
- usbi_err(ctx, "program assertion failed - HCD hub has no parent");
- return LIBUSB_ERROR_NO_DEVICE;
- }
- parent_priv = __device_priv(priv->parent_dev);
- if (sscanf(parent_priv->path, "\\\\.\\PCI#VEN_%04x&DEV_%04x%*s", &vid, &pid) == 2) {
- priv->dev_descriptor.idVendor = (uint16_t)vid;
- priv->dev_descriptor.idProduct = (uint16_t)pid;
- } else {
- usbi_warn(ctx, "could not infer VID/PID of HCD hub from '%s'", parent_priv->path);
- priv->dev_descriptor.idVendor = 0x1d6b; // Linux Foundation root hub
- priv->dev_descriptor.idProduct = 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, char* device_id)
-{
- 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 = (ULONG)priv->port;
- 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) for '%s': %s", device_id, 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) for '%s'.", device_id);
- 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 for '%s'.", device_id);
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- }
- memset(cd_buf_actual, 0, size);
-
- // Actual call
- cd_buf_actual->ConnectionIndex = (ULONG)priv->port;
- 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) for '%s': %s", device_id, 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) for '%s'.", device_id);
- LOOP_BREAK(LIBUSB_ERROR_IO);
- }
-
- if (cd_data->bDescriptorType != USB_CONFIGURATION_DESCRIPTOR_TYPE) {
- usbi_err(ctx, "not a configuration descriptor for '%s'", device_id);
- LOOP_BREAK(LIBUSB_ERROR_IO);
- }
-
- usbi_dbg("cached config descriptor %d (bConfigurationValue=%d, %d bytes)",
- i, cd_data->bConfigurationValue, cd_data->wTotalLength);
-
- // 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;
-}
-
-/*
- * Populate a libusb device structure
- */
-static int init_device(struct libusb_device* dev, struct libusb_device* parent_dev,
- uint8_t port_number, char* device_id, DWORD devinst)
-{
- HANDLE handle;
- DWORD size;
- USB_NODE_CONNECTION_INFORMATION conn_info;
- struct windows_device_priv *priv, *parent_priv;
- struct libusb_context *ctx = DEVICE_CTX(dev);
- struct libusb_device* tmp_dev;
- unsigned i;
-
- if ((dev == NULL) || (parent_dev == NULL)) {
- return LIBUSB_ERROR_NOT_FOUND;
- }
- priv = __device_priv(dev);
- parent_priv = __device_priv(parent_dev);
- if (parent_priv->apib->id != USB_API_HUB) {
- usbi_warn(ctx, "parent for device '%s' is not a hub", device_id);
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- // It is possible for the parent hub not to have been initialized yet
- // If that's the case, lookup the ancestors to set the bus number
- if (parent_dev->bus_number == 0) {
- for (i=2; ; i++) {
- tmp_dev = usbi_get_device_by_session_id(ctx, get_ancestor_session_id(devinst, i));
- if (tmp_dev == NULL) break;
- if (tmp_dev->bus_number != 0) {
- usbi_dbg("got bus number from ancestor #%d", i);
- parent_dev->bus_number = tmp_dev->bus_number;
- break;
- }
- }
- }
- if (parent_dev->bus_number == 0) {
- usbi_err(ctx, "program assertion failed: unable to find ancestor bus number for '%s'", device_id);
- return LIBUSB_ERROR_NOT_FOUND;
- }
- dev->bus_number = parent_dev->bus_number;
- priv->port = port_number;
- priv->depth = parent_priv->depth + 1;
- priv->parent_dev = parent_dev;
- memset(&conn_info, 0, sizeof(conn_info));
-
- if (priv->depth != 0) { // Not a HCD hub
- handle = CreateFileA(parent_priv->path, 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", parent_priv->path, windows_error_str(0));
- return LIBUSB_ERROR_ACCESS;
- }
- size = sizeof(USB_NODE_CONNECTION_INFORMATION);
- conn_info.ConnectionIndex = (ULONG)port_number;
- if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, &conn_info, size,
- &conn_info, size, &size, NULL)) {
- usbi_warn(ctx, "could not get node connection information for device '%s': %s",
- device_id, windows_error_str(0));
- safe_closehandle(handle);
- return LIBUSB_ERROR_NO_DEVICE;
- }
- if (conn_info.ConnectionStatus == NoDeviceConnected) {
- usbi_err(ctx, "device '%s' is no longer connected!", device_id);
- safe_closehandle(handle);
- return LIBUSB_ERROR_NO_DEVICE;
- }
- dev->device_address = (uint8_t)conn_info.DeviceAddress;
- memcpy(&priv->dev_descriptor, &(conn_info.DeviceDescriptor), sizeof(USB_DEVICE_DESCRIPTOR));
- dev->num_configurations = priv->dev_descriptor.bNumConfigurations;
- priv->active_config = conn_info.CurrentConfigurationValue;
- usbi_dbg("found %d configurations (active conf: %d)", dev->num_configurations, priv->active_config);
- // If we can't read the config descriptors, just set the number of confs to zero
- if (cache_config_descriptors(dev, handle, device_id) != LIBUSB_SUCCESS) {
- dev->num_configurations = 0;
- priv->dev_descriptor.bNumConfigurations = 0;
- }
- safe_closehandle(handle);
-
- if (conn_info.DeviceAddress > UINT8_MAX) {
- usbi_err(ctx, "program assertion failed: device address overflow");
- }
- dev->device_address = (uint8_t)conn_info.DeviceAddress;
- } else {
- dev->device_address = UINT8_MAX; // Hubs from HCD have a devaddr of 255
- force_hcd_device_descriptor(dev);
- }
-
- usbi_dbg("(bus: %d, addr: %d, depth: %d, port: %d): '%s'",
- dev->bus_number, dev->device_address, priv->depth, priv->port, device_id);
-
- return LIBUSB_SUCCESS;
-}
-
-// Returns the api type, or 0 if not found/unsupported
-static uint8_t get_api_type(struct libusb_context *ctx,
- HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data)
-{
- // 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"}
- };
- DWORD size, reg_type;
- unsigned k, l;
- uint8_t api;
-
- // Check the service & filter names to know the API we should use
- for (k=0; k<3; k++) {
- if (pSetupDiGetDeviceRegistryPropertyA(*dev_info, dev_info_data, lookup[k].reg_prop,
- &reg_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);
- } 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=1; 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;
- return api;
- }
- return 0;
-}
-
-static int set_composite_interface(struct libusb_context* ctx, struct libusb_device* dev,
- char* dev_interface_path, char* device_id, uint8_t api)
-{
- unsigned i;
- struct windows_device_priv *priv = __device_priv(dev);
- int interface_number;
-
- if (priv->apib->id != USB_API_COMPOSITE) {
- usbi_err(ctx, "program assertion failed: '%s' is not composite", device_id);
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- // 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 = 0;
- for (i=0; device_id[i] != 0; ) {
- if ( (device_id[i++] == 'M') && (device_id[i++] == 'I')
- && (device_id[i++] == '_') ) {
- interface_number = (device_id[i++] - '0')*10;
- interface_number += device_id[i] - '0';
- break;
- }
- }
-
- if (device_id[i] == 0) {
- usbi_warn(ctx, "failure to read interface number for %s. Using default value %d",
- device_id, interface_number);
- }
-
- // HID devices can have multiple collections (COL##) for each MI_## interface
- if (priv->usb_interface[interface_number].path != NULL) {
- if (api != USB_API_HID) {
- usbi_warn(ctx, "program assertion failed %s is not an USB HID collection", device_id);
- return LIBUSB_ERROR_OTHER;
- }
- usbi_dbg("interface[%d] already set - ignoring HID collection: %s",
- interface_number, device_id);
- return LIBUSB_ERROR_ACCESS;
- }
-
- usbi_dbg("interface[%d] = %s", interface_number, dev_interface_path);
- priv->usb_interface[interface_number].path = dev_interface_path;
- priv->usb_interface[interface_number].apib = &usb_api_backend[api];
- if ((api == USB_API_HID) && (priv->hid == NULL)) {
- priv->hid = calloc(1, sizeof(struct hid_device_priv));
- }
- priv->composite_api_flags |= 1<<api;
-
- return LIBUSB_SUCCESS;
-}
-
-static int set_hid_interface(struct libusb_context* ctx, struct libusb_device* dev,
- char* dev_interface_path)
-{
- struct windows_device_priv *priv = __device_priv(dev);
-
- if (priv->hid == NULL) {
- usbi_err(ctx, "program assertion failed: parent is not HID");
- return LIBUSB_ERROR_NO_DEVICE;
- }
- priv->usb_interface[priv->hid->nb_interfaces].path = dev_interface_path;
- priv->usb_interface[priv->hid->nb_interfaces].apib = &usb_api_backend[USB_API_HID];
- usbi_dbg("interface[%d] = %s", priv->hid->nb_interfaces, dev_interface_path);
- priv->hid->nb_interfaces++;
- 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 discovered_devs *discdevs = *_discdevs;
- HDEVINFO dev_info;
- SP_DEVINFO_DATA dev_info_data;
- SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL;
- GUID hid_guid;
-#define MAX_ENUM_GUIDS 64
- const GUID* guid[MAX_ENUM_GUIDS];
-#define HCD_PASS 0
-#define HUB_PASS 1
-#define GEN_PASS 2
-#define DEV_PASS 3
-#define HID_PASS 4
- int r = LIBUSB_SUCCESS;
- unsigned int nb_guids, pass, i, j, ancestor;
- char path[MAX_PATH_LENGTH];
- char strbuf[MAX_PATH_LENGTH];
- struct libusb_device *dev, *parent_dev;
- struct windows_device_priv *priv, *parent_priv;
- char* dev_interface_path = NULL;
- char* dev_id_path = NULL;
- unsigned long session_id;
- DWORD size, reg_type, port_nr, install_state;
- HKEY key;
- WCHAR guid_string_w[MAX_GUID_STRING_LENGTH];
- GUID* if_guid;
- LONG s;
- uint8_t api;
- // Keep a list of newly allocated devs to unref
- libusb_device** unref_list;
- unsigned int unref_size = 64;
- unsigned int unref_cur = 0;
-
- // PASS 1 : (re)enumerate HCDs (allows for HCD hotplug)
- // PASS 2 : (re)enumerate HUBS
- // PASS 3 : (re)enumerate generic USB devices (including driverless)
- // and list additional USB device interface GUIDs to explore
- // PASS 4 : (re)enumerate master USB devices that have a device interface
- // PASS 5+: (re)enumerate device interfaced GUIDs (including HID) and
- // set the device interfaces.
-
- // Init the GUID table
- guid[HCD_PASS] = &GUID_DEVINTERFACE_USB_HOST_CONTROLLER;
- guid[HUB_PASS] = &GUID_DEVINTERFACE_USB_HUB;
- guid[GEN_PASS] = NULL;
- guid[DEV_PASS] = &GUID_DEVINTERFACE_USB_DEVICE;
- HidD_GetHidGuid(&hid_guid);
- guid[HID_PASS] = &hid_guid;
- nb_guids = HID_PASS+1;
-
- unref_list = malloc(unref_size*sizeof(libusb_device*));
- if (unref_list == NULL) {
- return LIBUSB_ERROR_NO_MEM;
- }
-
- for (pass = 0; ((pass < nb_guids) && (r == LIBUSB_SUCCESS)); pass++) {
-//#define ENUM_DEBUG
-#ifdef ENUM_DEBUG
- switch(pass) {
- case HCD_PASS:
- usbi_dbg("PROCESSING HCDs %s", guid_to_string(guid[pass]));
- break;
- case HUB_PASS:
- usbi_dbg("PROCESSING HUBs %s", guid_to_string(guid[pass]));
- break;
- case DEV_PASS:
- usbi_dbg("PROCESSING DEVs %s", guid_to_string(guid[pass]));
- break;
- case GEN_PASS:
- usbi_dbg("PROCESSING GENs");
- break;
- case HID_PASS:
- usbi_dbg("PROCESSING HIDs %s", guid_to_string(guid[pass]));
- break;
- default:
- usbi_dbg("PROCESSING EXTs %s", guid_to_string(guid[pass]));
- break;
- }
-#endif
- for (i = 0; ; i++) {
- // safe loop: free up any (unprotected) dynamic resource
- // NB: this is always executed before breaking the loop
- safe_free(dev_interface_details);
- safe_free(dev_interface_path);
- safe_free(dev_id_path);
- session_id = 0;
- priv = parent_priv = NULL;
- dev = parent_dev = NULL;
-
- // Safe loop: end of loop conditions
- if (r != LIBUSB_SUCCESS) {
- break;
- }
- if ((pass == HCD_PASS) && (i == UINT8_MAX)) {
- usbi_warn(ctx, "program assertion failed - found more than %d buses, skipping the rest.", UINT8_MAX);
- break;
- }
- if (pass != GEN_PASS) {
- // Except for GEN, all passes deal with device interfaces
- dev_interface_details = get_interface_details(ctx, &dev_info, &dev_info_data, guid[pass], i);
- if (dev_interface_details == NULL) {
- break;
- } else {
- dev_interface_path = sanitize_path(dev_interface_details->DevicePath);
- if (dev_interface_path == NULL) {
- usbi_warn(ctx, "could not sanitize device interface path for '%s'", dev_interface_details->DevicePath);
- continue;
- }
- }
- } else {
- if (!get_devinfo_data(ctx, &dev_info, &dev_info_data, i)) {
- break;
- }
- }
-
- // Read the Device ID path. This is what we'll use as UID
- // Note that if the device is plugged in a different port or hub, the Device ID changes
- if (CM_Get_Device_IDA(dev_info_data.DevInst, path, sizeof(path), 0) != CR_SUCCESS) {
- usbi_warn(ctx, "could not read the device id path for devinst %X, skipping",
- dev_info_data.DevInst);
- continue;
- }
- dev_id_path = sanitize_path(path);
- if (dev_id_path == NULL) {
- usbi_warn(ctx, "could not sanitize device id path for devinst %X, skipping",
- dev_info_data.DevInst);
- continue;
- }
-#ifdef ENUM_DEBUG
- usbi_dbg("PRO: %s", dev_id_path);
-#endif
-
- // The SPDRP_ADDRESS for USB devices is the device port number on the hub
- port_nr = 0;
- if ((pass >= HUB_PASS) && (pass <= GEN_PASS)) {
- if ( (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ADDRESS,
- &reg_type, (BYTE*)&port_nr, 4, &size))
- || (size != 4) ) {
- usbi_warn(ctx, "could not retrieve port number for device '%s', skipping: %s",
- dev_id_path, windows_error_str(0));
- continue;
- }
- }
-
- // Set API to use or get additional data from generic pass
- api = USB_API_UNSUPPORTED;
- switch (pass) {
- case HCD_PASS:
- break;
- case GEN_PASS:
- // We use the GEN pass to detect driverless devices...
- size = sizeof(strbuf);
- if (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_DRIVER,
- &reg_type, (BYTE*)strbuf, size, &size)) {
- usbi_info(ctx, "The following device has no driver: '%s'", dev_id_path);
- usbi_info(ctx, "libusb will not be able to access it.");
- }
- // ...and to add the additional device interface GUIDs
- key = pSetupDiOpenDevRegKey(dev_info, &dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
- if (key != INVALID_HANDLE_VALUE) {
- size = sizeof(guid_string_w);
- s = pRegQueryValueExW(key, L"DeviceInterfaceGUIDs", NULL, &reg_type,
- (BYTE*)guid_string_w, &size);
- pRegCloseKey(key);
- if (s == ERROR_SUCCESS) {
- if (nb_guids >= MAX_ENUM_GUIDS) {
- // If this assert is ever reported, grow a GUID table dynamically
- usbi_err(ctx, "program assertion failed: too many GUIDs");
- LOOP_BREAK(LIBUSB_ERROR_OVERFLOW);
- }
- if_guid = calloc(1, sizeof(GUID));
- pCLSIDFromString(guid_string_w, if_guid);
- guid[nb_guids++] = if_guid;
- usbi_dbg("extra GUID: %s", guid_to_string(if_guid));
- }
- }
- break;
- case HID_PASS:
- api = USB_API_HID;
- break;
- default:
- // Get the API type (after checking that the driver installation is OK)
- if ( (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_INSTALL_STATE,
- &reg_type, (BYTE*)&install_state, 4, &size))
- || (size != 4) ){
- usbi_warn(ctx, "could not detect installation state of driver for '%s': %s",
- dev_id_path, windows_error_str(0));
- } else if (install_state != 0) {
- usbi_warn(ctx, "driver for device '%s' is reporting an issue (code: %d) - skipping",
- dev_id_path, install_state);
- continue;
- }
- api = get_api_type(ctx, &dev_info, &dev_info_data);
- break;
- }
-
- // Find parent device (for the passes that need it)
- switch (pass) {
- case HCD_PASS:
- case DEV_PASS:
- case HUB_PASS:
- break;
- default:
- // Go through the ancestors until we see a face we recognize
- parent_dev = NULL;
- for (ancestor = 1; parent_dev == NULL; ancestor++) {
- session_id = get_ancestor_session_id(dev_info_data.DevInst, ancestor);
- if (session_id == 0) {
- break;
- }
- parent_dev = usbi_get_device_by_session_id(ctx, session_id);
- }
- if (parent_dev == NULL) {
- usbi_dbg("unlisted ancestor for '%s' (non USB HID, newly connected, etc.) - ignoring", dev_id_path);
- continue;
- }
- parent_priv = __device_priv(parent_dev);
- // virtual USB devices are also listed during GEN - don't process these yet
- if ( (pass == GEN_PASS) && (parent_priv->apib->id != USB_API_HUB) ) {
- continue;
- }
- break;
- }
-
- // Create new or match existing device, using the (hashed) device_id as session id
- if (pass <= DEV_PASS) { // For subsequent passes, we'll lookup the parent
- // These are the passes that create "new" devices
- session_id = htab_hash(dev_id_path);
- dev = usbi_get_device_by_session_id(ctx, session_id);
- if (dev == NULL) {
- if (pass == DEV_PASS) {
- // This can occur if the OS only reports a newly plugged device after we started enum
- usbi_warn(ctx, "'%s' was only detected in late pass (newly connected device?)"
- " - ignoring", dev_id_path);
- continue;
- }
- usbi_dbg("allocating new device for session [%X]", session_id);
- if ((dev = usbi_alloc_device(ctx, session_id)) == NULL) {
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- }
- windows_device_priv_init(dev);
- // Keep track of devices that need unref
- unref_list[unref_cur++] = dev;
- if (unref_cur > unref_size) {
- unref_size += 64;
- unref_list = realloc(unref_list, unref_size*sizeof(libusb_device*));
- if (unref_list == NULL) {
- usbi_err(ctx, "could not realloc list for unref - aborting.");
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- }
- }
- } else {
- usbi_dbg("found existing device for session [%X]", session_id);
- }
- priv = __device_priv(dev);
- }
-
- // Setup device
- switch (pass) {
- case HCD_PASS:
- dev->bus_number = (uint8_t)(i + 1); // bus 0 is reserved for disconnected
- dev->device_address = 0;
- dev->num_configurations = 0;
- priv->apib = &usb_api_backend[USB_API_HUB];
- priv->depth = UINT8_MAX; // Overflow to 0 for HCD Hubs
- priv->path = dev_interface_path; dev_interface_path = NULL;
- break;
- case DEV_PASS:
- // Take care of API initialization
- priv->path = dev_interface_path; dev_interface_path = NULL;
- priv->apib = &usb_api_backend[api];
- switch(api) {
- case USB_API_COMPOSITE:
- break;
- case USB_API_HID:
- safe_free(priv->hid);
- priv->hid = calloc(1, sizeof(struct hid_device_priv));
- if (priv->hid == NULL) {
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- }
- priv->hid->nb_interfaces = 0;
- 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 API calls to work for both simple
- // and composite devices.
- for(j=0; j<USB_MAXINTERFACES; j++) {
- priv->usb_interface[j].apib = &usb_api_backend[api];
- }
- break;
- }
- break;
- case HUB_PASS:
- priv->apib = &usb_api_backend[api];
- priv->path = dev_interface_path; dev_interface_path = NULL;
- break;
- case GEN_PASS:
- r = init_device(dev, parent_dev, (uint8_t)port_nr, dev_id_path, dev_info_data.DevInst);
- if (r == LIBUSB_SUCCESS) {
- // Append device to the list of discovered devices
- discdevs = discovered_devs_append(*_discdevs, dev);
- if (!discdevs) {
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- }
- *_discdevs = discdevs;
- } else if (r == LIBUSB_ERROR_NO_DEVICE) {
- // This can occur if the device was disconnected but Windows hasn't
- // refreshed its enumeration yet - in that case, we ignore the device
- r = LIBUSB_SUCCESS;
- }
- break;
- default: // HID_PASS and later
- if (parent_priv->apib->id == USB_API_HID) {
- usbi_dbg("setting HID interface for [%lX]:", parent_dev->session_data);
- r = set_hid_interface(ctx, parent_dev, dev_interface_path);
- if (r != LIBUSB_SUCCESS) LOOP_BREAK(r);
- dev_interface_path = NULL;
- } else if (parent_priv->apib->id == USB_API_COMPOSITE) {
- usbi_dbg("setting composite interface for [%lX]:", parent_dev->session_data);
- switch (set_composite_interface(ctx, parent_dev, dev_interface_path, dev_id_path, api)) {
- case LIBUSB_SUCCESS:
- dev_interface_path = NULL;
- break;
- case LIBUSB_ERROR_ACCESS:
- // interface has already been set => make sure dev_interface_path is freed then
- break;
- default:
- LOOP_BREAK(r);
- break;
- }
- }
- break;
- }
- }
- }
-
- // Free any additional GUIDs
- for (pass = HID_PASS+1; pass < nb_guids; pass++) {
- safe_free(guid[pass]);
- }
-
- // Unref newly allocated devs
- for (i=0; i<unref_cur; i++) {
- safe_unref_device(unref_list[i]);
- }
- safe_free(unref_list);
-
- return r;
-}
-
-/*
- * exit: libusb backend deinitialization function
- */
-static void windows_exit(void)
-{
- int i;
- HANDLE semaphore;
- char sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID)
-
- sprintf(sem_name, "libusb_init%08X", (unsigned int)GetCurrentProcessId()&0xFFFFFFFF);
- semaphore = CreateSemaphoreA(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
- 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;
- }
- htab_destroy();
- }
-
- 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, 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, 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)
-{
- windows_device_priv_release(dev);
-}
-
-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);
-
- INIT_INTERLOCKEDEXCHANGE;
- nb_responses = pInterlockedExchange((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) {
- INIT_INTERLOCKEDINCREMENT;
- while (1) {
- pInterlockedIncrement((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* hub_driver_names[] = {"USBHUB"};
-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_HUB,
- "HUB API",
- &CLASS_GUID_UNSUPPORTED,
- hub_driver_names,
- sizeof(hub_driver_names)/sizeof(hub_driver_names[0]),
- unsupported_init,
- unsupported_exit,
- hub_open,
- hub_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,
- },
-};
-
-
-/*
- * HUB API functions - only cached descriptors readout for now
- * might be expanded if
- */
-static int hub_open(struct libusb_device_handle *dev_handle)
-{
- return LIBUSB_SUCCESS;
-}
-
-static void hub_close(struct libusb_device_handle *dev_handle)
-{
-}
-
-/*
- * 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_configure_endpoints(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);
- HANDLE winusb_handle = handle_priv->interface_handle[iface].api_handle;
- UCHAR policy;
- ULONG timeout = 0;
- uint8_t endpoint_address;
- int i;
-
- CHECK_WINUSB_AVAILABLE;
-
- // With handle and enpoints set (in parent), we can setup the default pipe properties
- // see http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DVC-T705_DDC08.pptx
- for (i=-1; i<priv->usb_interface[iface].nb_endpoints; i++) {
- endpoint_address =(i==-1)?0:priv->usb_interface[iface].endpoint[i];
- if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address,
- PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout)) {
- usbi_dbg("failed to set PIPE_TRANSFER_TIMEOUT for control endpoint %02X", endpoint_address);
- }
- if (i == -1) continue; // Other policies don't apply to control endpoint
- 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_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_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE);
- HANDLE file_handle, winusb_handle;
-
- CHECK_WINUSB_AVAILABLE;
-
- // If the device is composite, but using the default Windows composite parent driver (usbccgp)
- // or if it's the first WinUSB interface, we get a handle through WinUsb_Initialize().
- if ((is_using_usbccgp) || (iface == 0)) {
- // 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;
- } else {
- // For all other interfaces, use WinUsb_GetAssociatedInterface()
- winusb_handle = handle_priv->interface_handle[0].api_handle;
- // It is a requirement for multiple interface devices on Windows that, to you
- // must first claim the first interface before you claim the others
- 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;
- }
- }
- }
- usbi_dbg("claimed interface %d", iface);
- handle_priv->active_interface = iface;
-
- 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->id == 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, &current_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 (post hotplug): 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;
- }
-
- // 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;
- read_size = expected_size;
-
- // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0)
- if (!DeviceIoControl(hid_handle, ioctl_code, buf, expected_size+1,
- 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_warn(NULL, "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;
- }
-
- *size = MIN((size_t)read_size, *size);
- if (id == 0) {
- // Discard report ID
- memcpy(data, buf+1, *size);
- } else {
- 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);
- }
- }
-
- // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0)
- 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
- *size = write_size;
- if (write_size == 0) {
- usbi_dbg("program assertion failed - write completed synchronously, but no data was written");
- }
- 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, &current_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/libusb-1.0/libusb/os/windows_usb.h b/libusb-1.0/libusb/os/windows_usb.h
deleted file mode 100644
index 8851f41..0000000
--- a/libusb-1.0/libusb/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
-
-// 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 ';'
-#define HTAB_SIZE 1021
-
-// 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/ff545978.aspx
-// http://msdn.microsoft.com/en-us/library/ff545972.aspx
-// http://msdn.microsoft.com/en-us/library/ff545982.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
-#if !defined(GUID_DEVINTERFACE_USB_HUB)
-const GUID GUID_DEVINTERFACE_USB_HUB = { 0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8} };
-#endif
-const GUID GUID_NULL = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} };
-
-
-/*
- * Multiple USB API backend support
- */
-#define USB_API_UNSUPPORTED 0
-#define USB_API_HUB 1
-#define USB_API_COMPOSITE 2
-#define USB_API_WINUSB 3
-#define USB_API_HID 4
-#define USB_API_MAX 5
-
-#define CLASS_GUID_UNSUPPORTED GUID_NULL
-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
- */
-
-// 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;
- uint8_t nb_interfaces;
- 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 {
- uint8_t depth; // distance to HCD
- uint8_t port; // port number on the hub
- struct libusb_device *parent_dev; // access to parent is required for usermode ops
- char *path; // device interface path
- struct windows_usb_api_backend const *apib;
- struct {
- char *path; // each interface needs a 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 struct windows_device_priv *__device_priv(struct libusb_device *dev) {
- return (struct windows_device_priv *)dev->os_priv;
-}
-
-static inline void windows_device_priv_init(libusb_device* dev) {
- struct windows_device_priv* p = __device_priv(dev);
- int i;
- p->depth = 0;
- p->port = 0;
- p->parent_dev = NULL;
- 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(libusb_device* dev) {
- struct windows_device_priv* p = __device_priv(dev);
- int i;
- safe_free(p->path);
- if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) {
- for (i=0; i < dev->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);
- }
-}
-
-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_PREFIXED(api, ret, prefix, name, args) \
- typedef ret (api * __dll_##name##_t)args; \
- static __dll_##name##_t prefix##name = NULL
-
-#define DLL_LOAD_PREFIXED(dll, prefix, name, ret_on_failure) \
- do { \
- HMODULE h = GetModuleHandleA(#dll); \
- if (!h) \
- h = LoadLibraryA(#dll); \
- if (!h) { \
- if (ret_on_failure) { return LIBUSB_ERROR_NOT_FOUND; }\
- else { break; } \
- } \
- prefix##name = (__dll_##name##_t)GetProcAddress(h, #name);\
- if (prefix##name) break; \
- prefix##name = (__dll_##name##_t)GetProcAddress(h, #name "A");\
- if (prefix##name) break; \
- prefix##name = (__dll_##name##_t)GetProcAddress(h, #name "W");\
- if (prefix##name) break; \
- if(ret_on_failure) \
- return LIBUSB_ERROR_NOT_FOUND; \
- } while(0)
-
-#define DLL_DECLARE(api, ret, name, args) DLL_DECLARE_PREFIXED(api, ret, , name, args)
-#define DLL_LOAD(dll, name, ret_on_failure) DLL_LOAD_PREFIXED(dll, , name, ret_on_failure)
-
-/* OLE32 dependency */
-DLL_DECLARE_PREFIXED(WINAPI, HRESULT, p, CLSIDFromString, (LPCOLESTR, LPCLSID));
-
-/* SetupAPI dependencies */
-DLL_DECLARE_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (const GUID*, PCSTR, HWND, DWORD));
-DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA));
-DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA,
- const GUID*, DWORD, PSP_DEVICE_INTERFACE_DATA));
-DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA,
- PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA));
-DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO));
-DLL_DECLARE_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM));
-DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO,
- PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD));
-DLL_DECLARE_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD));
-DLL_DECLARE_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY));
-
-/*
- * 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 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));
-
-#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));