summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZoRo <dos21h@gmail.com>2022-02-19 21:43:52 +0000
committerZoRo <dos21h@gmail.com>2022-02-19 21:43:52 +0000
commitc6d603981adec7c0099fb48fc3369517b458ee85 (patch)
tree5096f42f05d884ded2336b11f806f49e49eb3732 /src
parent3d7c48a6e5c5c532cdd66b3ba5a8c5911bcf2383 (diff)
downloadlibrusb-c6d603981adec7c0099fb48fc3369517b458ee85.tar.gz
librusb-c6d603981adec7c0099fb48fc3369517b458ee85.zip
Compilable rusb for linux
Diffstat (limited to 'src')
-rw-r--r--src/make.mk22
-rw-r--r--src/os/darwin_usb.c2611
-rw-r--r--src/os/darwin_usb.h227
-rw-r--r--src/os/events_windows.c214
-rw-r--r--src/os/events_windows.h46
-rw-r--r--src/os/haiku_pollfs.cpp372
-rw-r--r--src/os/haiku_usb.h113
-rw-r--r--src/os/haiku_usb_backend.cpp532
-rw-r--r--src/os/haiku_usb_raw.cpp231
-rw-r--r--src/os/haiku_usb_raw.h188
-rw-r--r--src/os/linux_netlink.c401
-rw-r--r--src/os/netbsd_usb.c617
-rw-r--r--src/os/null_usb.c111
-rw-r--r--src/os/openbsd_usb.c700
-rw-r--r--src/os/sunos_usb.c1609
-rw-r--r--src/os/sunos_usb.h79
-rw-r--r--src/os/threads_windows.c40
-rw-r--r--src/os/threads_windows.h113
-rw-r--r--src/os/windows_common.c904
-rw-r--r--src/os/windows_common.h415
-rw-r--r--src/os/windows_usbdk.c724
-rw-r--r--src/os/windows_usbdk.h106
-rw-r--r--src/os/windows_winusb.c4527
-rw-r--r--src/os/windows_winusb.h783
24 files changed, 22 insertions, 15663 deletions
diff --git a/src/make.mk b/src/make.mk
new file mode 100644
index 0000000..acf8f12
--- /dev/null
+++ b/src/make.mk
@@ -0,0 +1,22 @@
+DIR=src
+
+SRC_UTILS_PRE += $(wildcard $(DIR)/os/*.c)
+SRC_UTILS += $(wildcard $(DIR)/*.c)
+OBJ_UTILS += $(SRC_UTILS:.c=.o)
+OBJ_UTILS_PRE += $(SRC_UTILS_PRE:.c=.o)
+LDFLAGS_UTILS =
+INCLUDE = -I./include -I./src
+CFLAGS = -fPIC
+
+build-src: src-pre
+ echo $(SRC_UTILS_PRE)
+ echo $(SRC_UTILS)
+
+$(DIR)-pre: $(OBJ_UTILS_PRE) $(OBJ_UTILS)
+
+$(DIR)/os/%.o: $(DIR)/os/%.c
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $(BUILD_DIR)$@
+
+$(DIR)/%.o: $(DIR)/%.c
+ echo "B"
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $(BUILD_DIR)$@ $(LDFLAGS_UTILS) \ No newline at end of file
diff --git a/src/os/darwin_usb.c b/src/os/darwin_usb.c
deleted file mode 100644
index 903422c..0000000
--- a/src/os/darwin_usb.c
+++ /dev/null
@@ -1,2611 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode:nil -*- */
-/*
- * darwin backend for libusb 1.0
- * Copyright © 2008-2021 Nathan Hjelm <hjelmn@cs.unm.edu>
- * Copyright © 2019-2021 Google LLC. All rights reserved.
- *
- * 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 <assert.h>
-#include <time.h>
-#include <ctype.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/sysctl.h>
-
-#include <mach/clock.h>
-#include <mach/clock_types.h>
-#include <mach/mach_host.h>
-#include <mach/mach_port.h>
-
-/* Suppress warnings about the use of the deprecated objc_registerThreadWithCollector
- * function. Its use is also conditionalized to only older deployment targets. */
-#define OBJC_SILENCE_GC_DEPRECATIONS 1
-
-/* Default timeout to 10s for reenumerate. This is needed because USBDeviceReEnumerate
- * does not return error status on macOS. */
-#define DARWIN_REENUMERATE_TIMEOUT_US 10000000
-
-#include <AvailabilityMacros.h>
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 && MAC_OS_X_VERSION_MIN_REQUIRED < 101200
- #include <objc/objc-auto.h>
-#endif
-
-#include "darwin_usb.h"
-
-static int init_count = 0;
-
-/* Both kIOMasterPortDefault or kIOMainPortDefault are synonyms for 0. */
-static const mach_port_t darwin_default_master_port = 0;
-
-/* async event thread */
-static pthread_mutex_t libusb_darwin_at_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t libusb_darwin_at_cond = PTHREAD_COND_INITIALIZER;
-
-#if !defined(HAVE_CLOCK_GETTIME)
-static clock_serv_t clock_realtime;
-static clock_serv_t clock_monotonic;
-#endif
-
-#define LIBUSB_DARWIN_STARTUP_FAILURE ((CFRunLoopRef) -1)
-
-static CFRunLoopRef libusb_darwin_acfl = NULL; /* event cf loop */
-static CFRunLoopSourceRef libusb_darwin_acfls = NULL; /* shutdown signal for event cf loop */
-
-static usbi_mutex_t darwin_cached_devices_lock = PTHREAD_MUTEX_INITIALIZER;
-static struct list_head darwin_cached_devices;
-static const char *darwin_device_class = "IOUSBDevice";
-
-#define DARWIN_CACHED_DEVICE(a) (((struct darwin_device_priv *)usbi_get_device_priv((a)))->dev)
-
-/* async event thread */
-static pthread_t libusb_darwin_at;
-
-static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, void *buffer, size_t len);
-static int darwin_claim_interface(struct libusb_device_handle *dev_handle, uint8_t iface);
-static int darwin_release_interface(struct libusb_device_handle *dev_handle, uint8_t iface);
-static int darwin_reenumerate_device(struct libusb_device_handle *dev_handle, bool capture);
-static int darwin_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint);
-static int darwin_reset_device(struct libusb_device_handle *dev_handle);
-static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0);
-
-static enum libusb_error darwin_scan_devices(struct libusb_context *ctx);
-static enum libusb_error process_new_device (struct libusb_context *ctx, struct darwin_cached_device *cached_device,
- UInt64 old_session_id);
-
-static enum libusb_error darwin_get_cached_device(struct libusb_context *ctx, io_service_t service, struct darwin_cached_device **cached_out,
- UInt64 *old_session_id);
-
-#if defined(ENABLE_LOGGING)
-static const char *darwin_error_str (IOReturn result) {
- static char string_buffer[50];
- 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:
-#if defined(kUSBHostReturnPipeStalled)
- case kUSBHostReturnPipeStalled:
-#endif
- 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";
- case kIOReturnNoResources:
- return "out of resources";
- case kIOUSBHighSpeedSplitError:
- return "high speed split error";
- case kIOUSBUnknownPipeErr:
- return "pipe ref not recognized";
- default:
- snprintf(string_buffer, sizeof(string_buffer), "unknown error (0x%x)", result);
- return string_buffer;
- }
-}
-#endif
-
-static enum libusb_error darwin_to_libusb (IOReturn 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:
-#if defined(kUSBHostReturnPipeStalled)
- case kUSBHostReturnPipeStalled:
-#endif
- return LIBUSB_ERROR_PIPE;
- case kIOReturnBadArgument:
- return LIBUSB_ERROR_INVALID_PARAM;
- case kIOUSBTransactionTimeout:
- return LIBUSB_ERROR_TIMEOUT;
- case kIOUSBUnknownPipeErr:
- return LIBUSB_ERROR_NOT_FOUND;
- case kIOReturnNotResponding:
- case kIOReturnAborted:
- case kIOReturnError:
- case kIOUSBNoAsyncPortErr:
- default:
- return LIBUSB_ERROR_OTHER;
- }
-}
-
-/* this function must be called with the darwin_cached_devices_lock held */
-static void darwin_deref_cached_device(struct darwin_cached_device *cached_dev) {
- cached_dev->refcount--;
- /* free the device and remove it from the cache */
- if (0 == cached_dev->refcount) {
- list_del(&cached_dev->list);
-
- if (cached_dev->device) {
- (*(cached_dev->device))->Release(cached_dev->device);
- cached_dev->device = NULL;
- }
- IOObjectRelease (cached_dev->service);
- free (cached_dev);
- }
-}
-
-static void darwin_ref_cached_device(struct darwin_cached_device *cached_dev) {
- cached_dev->refcount++;
-}
-
-static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, uint8_t *pipep, uint8_t *ifcp, struct darwin_interface **interface_out) {
- struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
-
- /* current interface */
- struct darwin_interface *cInterface;
-
- uint8_t i, iface;
-
- struct libusb_context *ctx = HANDLE_CTX(dev_handle);
-
- usbi_dbg (ctx, "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 & (1U << iface)) {
- for (i = 0 ; i < cInterface->num_endpoints ; i++) {
- if (cInterface->endpoint_addrs[i] == ep) {
- *pipep = i + 1;
-
- if (ifcp)
- *ifcp = iface;
-
- if (interface_out)
- *interface_out = cInterface;
-
- usbi_dbg (ctx, "pipe %d on interface %d matches", *pipep, iface);
- return LIBUSB_SUCCESS;
- }
- }
- }
- }
-
- /* No pipe found with the correct endpoint address */
- usbi_warn (HANDLE_CTX(dev_handle), "no pipeRef found with endpoint address 0x%02x.", ep);
-
- return LIBUSB_ERROR_NOT_FOUND;
-}
-
-static IOReturn usb_setup_device_iterator (io_iterator_t *deviceIterator, UInt32 location) {
- CFMutableDictionaryRef matchingDict = IOServiceMatching(darwin_device_class);
-
- if (!matchingDict)
- return kIOReturnError;
-
- if (location) {
- CFMutableDictionaryRef propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
-
- /* there are no unsigned CFNumber types so treat the value as signed. the OS seems to do this
- internally (CFNumberType of locationID is kCFNumberSInt32Type) */
- CFTypeRef locationCF = CFNumberCreate (NULL, kCFNumberSInt32Type, &location);
-
- if (propertyMatchDict && locationCF) {
- CFDictionarySetValue (propertyMatchDict, CFSTR(kUSBDevicePropertyLocationID), locationCF);
- CFDictionarySetValue (matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict);
- }
- /* else we can still proceed as long as the caller accounts for the possibility of other devices in the iterator */
-
- /* release our references as per the Create Rule */
- if (propertyMatchDict)
- CFRelease (propertyMatchDict);
- if (locationCF)
- CFRelease (locationCF);
- }
-
- return IOServiceGetMatchingServices(darwin_default_master_port, matchingDict, deviceIterator);
-}
-
-/* Returns 1 on success, 0 on failure. */
-static bool get_ioregistry_value_number (io_service_t service, CFStringRef property, CFNumberType type, void *p) {
- CFTypeRef cfNumber = IORegistryEntryCreateCFProperty (service, property, kCFAllocatorDefault, 0);
- Boolean success = 0;
-
- if (cfNumber) {
- if (CFGetTypeID(cfNumber) == CFNumberGetTypeID()) {
- success = CFNumberGetValue(cfNumber, type, p);
- }
-
- CFRelease (cfNumber);
- }
-
- return (success != 0);
-}
-
-/* Returns 1 on success, 0 on failure. */
-static bool get_ioregistry_value_data (io_service_t service, CFStringRef property, ssize_t size, void *p) {
- CFTypeRef cfData = IORegistryEntryCreateCFProperty (service, property, kCFAllocatorDefault, 0);
- bool success = false;
-
- if (cfData) {
- if (CFGetTypeID (cfData) == CFDataGetTypeID ()) {
- CFIndex length = CFDataGetLength (cfData);
- if (length < size) {
- size = length;
- }
-
- CFDataGetBytes (cfData, CFRangeMake(0, size), p);
- success = true;
- }
-
- CFRelease (cfData);
- }
-
- return success;
-}
-
-static usb_device_t **darwin_device_from_service (struct libusb_context *ctx, io_service_t service)
-{
- io_cf_plugin_ref_t *plugInInterface = NULL;
- usb_device_t **device;
- IOReturn kresult;
- SInt32 score;
- const int max_retries = 5;
-
- /* The IOCreatePlugInInterfaceForService function might consistently return
- an "out of resources" error with certain USB devices the first time we run
- it. The reason is still unclear, but retrying fixes the problem */
- for (int count = 0; count < max_retries; count++) {
- kresult = IOCreatePlugInInterfaceForService(service, kIOUSBDeviceUserClientTypeID,
- kIOCFPlugInInterfaceID, &plugInInterface,
- &score);
- if (kIOReturnSuccess == kresult && plugInInterface) {
- break;
- }
-
- usbi_dbg (ctx, "set up plugin for service retry: %s", darwin_error_str (kresult));
-
- /* sleep for a little while before trying again */
- nanosleep(&(struct timespec){.tv_sec = 0, .tv_nsec = 1000}, NULL);
- }
-
- if (kIOReturnSuccess != kresult || !plugInInterface) {
- usbi_dbg (ctx, "could not set up plugin for service: %s", darwin_error_str (kresult));
- return NULL;
- }
-
- (void)(*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID),
- (LPVOID)&device);
- /* Use release instead of IODestroyPlugInInterface to avoid stopping IOServices associated with this device */
- (*plugInInterface)->Release (plugInInterface);
-
- return device;
-}
-
-static void darwin_devices_attached (void *ptr, io_iterator_t add_devices) {
- UNUSED(ptr);
- struct darwin_cached_device *cached_device;
- UInt64 old_session_id;
- struct libusb_context *ctx;
- io_service_t service;
- int ret;
-
- usbi_mutex_lock(&active_contexts_lock);
-
- while ((service = IOIteratorNext(add_devices))) {
- ret = darwin_get_cached_device (NULL, service, &cached_device, &old_session_id);
- if (ret < 0 || !cached_device->can_enumerate) {
- continue;
- }
-
- /* add this device to each active context's device list */
- for_each_context(ctx) {
- process_new_device (ctx, cached_device, old_session_id);
- }
-
- if (cached_device->in_reenumerate) {
- usbi_dbg (NULL, "cached device in reset state. reset complete...");
- cached_device->in_reenumerate = false;
- }
-
- IOObjectRelease(service);
- }
-
- usbi_mutex_unlock(&active_contexts_lock);
-}
-
-static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
- UNUSED(ptr);
- struct libusb_device *dev = NULL;
- struct libusb_context *ctx;
- struct darwin_cached_device *old_device;
-
- io_service_t device;
- UInt64 session, locationID;
- int ret;
-
- usbi_mutex_lock(&active_contexts_lock);
-
- while ((device = IOIteratorNext (rem_devices)) != 0) {
- bool is_reenumerating = false;
-
- /* get the location from the i/o registry */
- ret = get_ioregistry_value_number (device, CFSTR("sessionID"), kCFNumberSInt64Type, &session);
- (void) get_ioregistry_value_number (device, CFSTR("locationID"), kCFNumberSInt32Type, &locationID);
- IOObjectRelease (device);
- if (!ret)
- continue;
-
- /* we need to match darwin_ref_cached_device call made in darwin_get_cached_device function
- otherwise no cached device will ever get freed */
- usbi_mutex_lock(&darwin_cached_devices_lock);
- list_for_each_entry(old_device, &darwin_cached_devices, list, struct darwin_cached_device) {
- if (old_device->session == session) {
- if (old_device->in_reenumerate) {
- /* device is re-enumerating. do not dereference the device at this time. libusb_reset_device()
- * will deref if needed. */
- usbi_dbg (NULL, "detected device detached due to re-enumeration. sessionID: 0x%" PRIx64 ", locationID: 0x%" PRIx64,
- session, locationID);
-
- /* the device object is no longer usable so go ahead and release it */
- if (old_device->device) {
- (*(old_device->device))->Release(old_device->device);
- old_device->device = NULL;
- }
-
- is_reenumerating = true;
- } else {
- darwin_deref_cached_device (old_device);
- }
-
- break;
- }
- }
-
- usbi_mutex_unlock(&darwin_cached_devices_lock);
- if (is_reenumerating) {
- continue;
- }
-
- for_each_context(ctx) {
- usbi_dbg (ctx, "notifying context %p of device disconnect", ctx);
-
- dev = usbi_get_device_by_session_id(ctx, (unsigned long) session);
- if (dev) {
- /* signal the core that this device has been disconnected. the core will tear down this device
- when the reference count reaches 0 */
- usbi_disconnect_device(dev);
- libusb_unref_device(dev);
- }
- }
- }
-
- usbi_mutex_unlock(&active_contexts_lock);
-}
-
-static void darwin_hotplug_poll (void)
-{
- /* not sure if 1 ms will be too long/short but it should work ok */
- mach_timespec_t timeout = {.tv_sec = 0, .tv_nsec = 1000000ul};
-
- /* since a kernel thread may notify the IOIterators used for
- * hotplug notification we can't just clear the iterators.
- * instead just wait until all IOService providers are quiet */
- (void) IOKitWaitQuiet (darwin_default_master_port, &timeout);
-}
-
-static void darwin_clear_iterator (io_iterator_t iter) {
- io_service_t device;
-
- while ((device = IOIteratorNext (iter)) != 0)
- IOObjectRelease (device);
-}
-
-static void darwin_fail_startup(void) {
- pthread_mutex_lock (&libusb_darwin_at_mutex);
- libusb_darwin_acfl = LIBUSB_DARWIN_STARTUP_FAILURE;
- pthread_cond_signal (&libusb_darwin_at_cond);
- pthread_mutex_unlock (&libusb_darwin_at_mutex);
- pthread_exit (NULL);
-}
-
-static void *darwin_event_thread_main (void *arg0) {
- IOReturn kresult;
- struct libusb_context *ctx = (struct libusb_context *)arg0;
- CFRunLoopRef runloop;
- CFRunLoopSourceRef libusb_shutdown_cfsource;
- CFRunLoopSourceContext libusb_shutdown_cfsourcectx;
-
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
- /* Set this thread's name, so it can be seen in the debugger
- and crash reports. */
- pthread_setname_np ("org.libusb.device-hotplug");
-#endif
-
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 && MAC_OS_X_VERSION_MIN_REQUIRED < 101200
- /* Tell the Objective-C garbage collector about this thread.
- This is required because, unlike NSThreads, pthreads are
- not automatically registered. Although we don't use
- Objective-C, we use CoreFoundation, which does.
- Garbage collection support was entirely removed in 10.12,
- so don't bother there. */
- objc_registerThreadWithCollector();
-#endif
-
- /* hotplug (device arrival/removal) sources */
- CFRunLoopSourceRef libusb_notification_cfsource;
- io_notification_port_t libusb_notification_port;
- io_iterator_t libusb_rem_device_iterator;
- io_iterator_t libusb_add_device_iterator;
-
- usbi_dbg (ctx, "creating hotplug event source");
-
- runloop = CFRunLoopGetCurrent ();
- CFRetain (runloop);
-
- /* add the shutdown cfsource to the run loop */
- memset(&libusb_shutdown_cfsourcectx, 0, sizeof(libusb_shutdown_cfsourcectx));
- libusb_shutdown_cfsourcectx.info = runloop;
- libusb_shutdown_cfsourcectx.perform = (void (*)(void *))CFRunLoopStop;
- libusb_shutdown_cfsource = CFRunLoopSourceCreate(NULL, 0, &libusb_shutdown_cfsourcectx);
- CFRunLoopAddSource(runloop, libusb_shutdown_cfsource, kCFRunLoopDefaultMode);
-
- /* add the notification port to the run loop */
- libusb_notification_port = IONotificationPortCreate (darwin_default_master_port);
- libusb_notification_cfsource = IONotificationPortGetRunLoopSource (libusb_notification_port);
- CFRunLoopAddSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode);
-
- /* create notifications for removed devices */
- kresult = IOServiceAddMatchingNotification (libusb_notification_port, kIOTerminatedNotification,
- IOServiceMatching(darwin_device_class),
- darwin_devices_detached,
- ctx, &libusb_rem_device_iterator);
-
- if (kresult != kIOReturnSuccess) {
- usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult));
- CFRelease (libusb_shutdown_cfsource);
- CFRelease (runloop);
- darwin_fail_startup ();
- }
-
- /* create notifications for attached devices */
- kresult = IOServiceAddMatchingNotification(libusb_notification_port, kIOFirstMatchNotification,
- IOServiceMatching(darwin_device_class),
- darwin_devices_attached,
- ctx, &libusb_add_device_iterator);
-
- if (kresult != kIOReturnSuccess) {
- usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult));
- CFRelease (libusb_shutdown_cfsource);
- CFRelease (runloop);
- darwin_fail_startup ();
- }
-
- /* arm notifiers */
- darwin_clear_iterator (libusb_rem_device_iterator);
- darwin_clear_iterator (libusb_add_device_iterator);
-
- usbi_dbg (ctx, "darwin event thread ready to receive events");
-
- /* signal the main thread that the hotplug runloop has been created. */
- pthread_mutex_lock (&libusb_darwin_at_mutex);
- libusb_darwin_acfl = runloop;
- libusb_darwin_acfls = libusb_shutdown_cfsource;
- pthread_cond_signal (&libusb_darwin_at_cond);
- pthread_mutex_unlock (&libusb_darwin_at_mutex);
-
- /* run the runloop */
- CFRunLoopRun();
-
- usbi_dbg (ctx, "darwin event thread exiting");
-
- /* signal the main thread that the hotplug runloop has finished. */
- pthread_mutex_lock (&libusb_darwin_at_mutex);
- libusb_darwin_acfls = NULL;
- libusb_darwin_acfl = NULL;
- pthread_cond_signal (&libusb_darwin_at_cond);
- pthread_mutex_unlock (&libusb_darwin_at_mutex);
-
- /* remove the notification cfsource */
- CFRunLoopRemoveSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode);
-
- /* remove the shutdown cfsource */
- CFRunLoopRemoveSource(runloop, libusb_shutdown_cfsource, kCFRunLoopDefaultMode);
-
- /* delete notification port */
- IONotificationPortDestroy (libusb_notification_port);
-
- /* delete iterators */
- IOObjectRelease (libusb_rem_device_iterator);
- IOObjectRelease (libusb_add_device_iterator);
-
- CFRelease (libusb_shutdown_cfsource);
- CFRelease (runloop);
-
- pthread_exit (NULL);
-}
-
-/* cleanup function to destroy cached devices */
-static void darwin_cleanup_devices(void) {
- struct darwin_cached_device *dev, *next;
-
- list_for_each_entry_safe(dev, next, &darwin_cached_devices, list, struct darwin_cached_device) {
- darwin_deref_cached_device(dev);
- }
-}
-
-static int darwin_init(struct libusb_context *ctx) {
- bool first_init;
- int rc;
-
- first_init = (1 == ++init_count);
-
- do {
- if (first_init) {
- if (NULL == darwin_cached_devices.next) {
- list_init (&darwin_cached_devices);
- }
- assert(list_empty(&darwin_cached_devices));
-#if !defined(HAVE_CLOCK_GETTIME)
- /* create the clocks that will be used if clock_gettime() is not available */
- host_name_port_t host_self;
-
- host_self = mach_host_self();
- host_get_clock_service(host_self, CALENDAR_CLOCK, &clock_realtime);
- host_get_clock_service(host_self, SYSTEM_CLOCK, &clock_monotonic);
- mach_port_deallocate(mach_task_self(), host_self);
-#endif
- }
-
- rc = darwin_scan_devices (ctx);
- if (LIBUSB_SUCCESS != rc)
- break;
-
- if (first_init) {
- rc = pthread_create (&libusb_darwin_at, NULL, darwin_event_thread_main, ctx);
- if (0 != rc) {
- usbi_err (ctx, "could not create event thread, error %d", rc);
- rc = LIBUSB_ERROR_OTHER;
- break;
- }
-
- pthread_mutex_lock (&libusb_darwin_at_mutex);
- while (!libusb_darwin_acfl)
- pthread_cond_wait (&libusb_darwin_at_cond, &libusb_darwin_at_mutex);
- if (libusb_darwin_acfl == LIBUSB_DARWIN_STARTUP_FAILURE) {
- libusb_darwin_acfl = NULL;
- rc = LIBUSB_ERROR_OTHER;
- }
- pthread_mutex_unlock (&libusb_darwin_at_mutex);
-
- if (0 != rc)
- pthread_join (libusb_darwin_at, NULL);
- }
- } while (0);
-
- if (LIBUSB_SUCCESS != rc) {
- if (first_init) {
- darwin_cleanup_devices ();
-#if !defined(HAVE_CLOCK_GETTIME)
- mach_port_deallocate(mach_task_self(), clock_realtime);
- mach_port_deallocate(mach_task_self(), clock_monotonic);
-#endif
- }
- --init_count;
- }
-
- return rc;
-}
-
-static void darwin_exit (struct libusb_context *ctx) {
- UNUSED(ctx);
-
- if (0 == --init_count) {
- /* stop the event runloop and wait for the thread to terminate. */
- pthread_mutex_lock (&libusb_darwin_at_mutex);
- CFRunLoopSourceSignal (libusb_darwin_acfls);
- CFRunLoopWakeUp (libusb_darwin_acfl);
- while (libusb_darwin_acfl)
- pthread_cond_wait (&libusb_darwin_at_cond, &libusb_darwin_at_mutex);
- pthread_mutex_unlock (&libusb_darwin_at_mutex);
- pthread_join (libusb_darwin_at, NULL);
-
- darwin_cleanup_devices ();
-
-#if !defined(HAVE_CLOCK_GETTIME)
- mach_port_deallocate(mach_task_self(), clock_realtime);
- mach_port_deallocate(mach_task_self(), clock_monotonic);
-#endif
- }
-}
-
-static int get_configuration_index (struct libusb_device *dev, UInt8 config_value) {
- struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
- 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_NOT_FOUND;
-}
-
-static int darwin_get_active_config_descriptor(struct libusb_device *dev, void *buffer, size_t len) {
- struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
- int config_index;
-
- if (0 == priv->active_config)
- return LIBUSB_ERROR_NOT_FOUND;
-
- config_index = get_configuration_index (dev, priv->active_config);
- if (config_index < 0)
- return config_index;
-
- assert(config_index >= 0 && config_index <= UINT8_MAX);
- return darwin_get_config_descriptor (dev, (UInt8)config_index, buffer, len);
-}
-
-static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, void *buffer, size_t len) {
- struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
- IOUSBConfigurationDescriptorPtr desc;
- IOReturn kresult;
- int ret;
-
- if (!priv || !priv->device)
- return LIBUSB_ERROR_OTHER;
-
- kresult = (*priv->device)->GetConfigurationDescriptorPtr (priv->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);
- }
-
- ret = darwin_to_libusb (kresult);
- if (ret != LIBUSB_SUCCESS)
- return ret;
-
- return (int) len;
-}
-
-/* check whether the os has configured the device */
-static enum libusb_error darwin_check_configuration (struct libusb_context *ctx, struct darwin_cached_device *dev) {
- usb_device_t **darwin_device = dev->device;
-
- IOUSBConfigurationDescriptorPtr configDesc;
- IOUSBFindInterfaceRequest request;
- IOReturn kresult;
- io_iterator_t interface_iterator;
- io_service_t firstInterface;
-
- if (dev->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 */
- }
-
- /* checking the configuration of a root hub simulation takes ~1 s in 10.11. the device is
- not usable anyway */
- if (0x05ac == libusb_le16_to_cpu (dev->dev_descriptor.idVendor) &&
- 0x8005 == libusb_le16_to_cpu (dev->dev_descriptor.idProduct)) {
- usbi_dbg (ctx, "ignoring configuration on root hub simulation");
- dev->active_config = 0;
- return LIBUSB_SUCCESS;
- }
-
- /* find the first configuration */
- kresult = (*darwin_device)->GetConfigurationDescriptorPtr (darwin_device, 0, &configDesc);
- dev->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 != kIOReturnSuccess)
- 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 (dev->dev_descriptor.bNumConfigurations == 1)
- /* to avoid problems with some devices get the configurations value from the configuration descriptor */
- dev->active_config = dev->first_config;
- else
- /* devices with more than one configuration should work with GetConfiguration */
- (*darwin_device)->GetConfiguration (darwin_device, &dev->active_config);
- } else
- /* not configured */
- dev->active_config = 0;
-
- usbi_dbg (ctx, "active config: %u, first config: %u", dev->active_config, dev->first_config);
-
- return LIBUSB_SUCCESS;
-}
-
-static IOReturn darwin_request_descriptor (usb_device_t **device, UInt8 desc, UInt8 desc_index, void *buffer, size_t buffer_size) {
- IOUSBDevRequestTO req;
-
- assert(buffer_size <= UINT16_MAX);
-
- memset (buffer, 0, buffer_size);
-
- /* Set up request for descriptor/ */
- req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
- req.bRequest = kUSBRqGetDescriptor;
- req.wValue = (UInt16)(desc << 8);
- req.wIndex = desc_index;
- req.wLength = (UInt16)buffer_size;
- req.pData = buffer;
- req.noDataTimeout = 20;
- req.completionTimeout = 100;
-
- return (*device)->DeviceRequestTO (device, &req);
-}
-
-static enum libusb_error darwin_cache_device_descriptor (struct libusb_context *ctx, struct darwin_cached_device *dev) {
- usb_device_t **device = dev->device;
- int retries = 1;
- long delay = 30000; // microseconds
- int unsuspended = 0, try_unsuspend = 1, try_reconfigure = 1;
- int is_open = 0;
- IOReturn ret = 0, ret2;
- UInt8 bDeviceClass;
- UInt16 idProduct, idVendor;
-
- dev->can_enumerate = 0;
-
- (*device)->GetDeviceClass (device, &bDeviceClass);
- (*device)->GetDeviceProduct (device, &idProduct);
- (*device)->GetDeviceVendor (device, &idVendor);
-
- /* 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. Still,
- * to follow the spec as closely as possible, try opening the device */
- is_open = ((*device)->USBDeviceOpenSeize(device) == kIOReturnSuccess);
-
- do {
- /**** retrieve device descriptor ****/
- ret = darwin_request_descriptor (device, kUSBDeviceDesc, 0, &dev->dev_descriptor, sizeof(dev->dev_descriptor));
-
- if (kIOReturnOverrun == ret && kUSBDeviceDesc == dev->dev_descriptor.bDescriptorType)
- /* received an overrun error but we still received a device descriptor */
- ret = kIOReturnSuccess;
-
- if (kIOUSBVendorIDAppleComputer == idVendor) {
- /* NTH: don't bother retrying or unsuspending Apple devices */
- break;
- }
-
- if (kIOReturnSuccess == ret && (0 == dev->dev_descriptor.bNumConfigurations ||
- 0 == dev->dev_descriptor.bcdUSB)) {
- /* work around for incorrectly configured devices */
- if (try_reconfigure && is_open) {
- usbi_dbg(ctx, "descriptor appears to be invalid. resetting configuration before trying again...");
-
- /* set the first configuration */
- (*device)->SetConfiguration(device, 1);
-
- /* don't try to reconfigure again */
- try_reconfigure = 0;
- }
-
- ret = kIOUSBPipeStalled;
- }
-
- if (kIOReturnSuccess != ret && is_open && try_unsuspend) {
- /* device may be suspended. unsuspend it and try again */
-#if DeviceVersion >= 320
- UInt32 info = 0;
-
- /* IOUSBFamily 320+ provides a way to detect device suspension but earlier versions do not */
- (void)(*device)->GetUSBDeviceInformation (device, &info);
-
- /* note that the device was suspended */
- if (info & (1U << kUSBInformationDeviceIsSuspendedBit) || 0 == info)
- try_unsuspend = 1;
-#endif
-
- if (try_unsuspend) {
- /* try to unsuspend the device */
- ret2 = (*device)->USBDeviceSuspend (device, 0);
- if (kIOReturnSuccess != ret2) {
- /* prevent log spew from poorly behaving devices. this indicates the
- os actually had trouble communicating with the device */
- usbi_dbg(ctx, "could not retrieve device descriptor. failed to unsuspend: %s",darwin_error_str(ret2));
- } else
- unsuspended = 1;
-
- try_unsuspend = 0;
- }
- }
-
- if (kIOReturnSuccess != ret) {
- usbi_dbg(ctx, "kernel responded with code: 0x%08x. sleeping for %ld ms before trying again", ret, delay/1000);
- /* sleep for a little while before trying again */
- nanosleep(&(struct timespec){delay / 1000000, (delay * 1000) % 1000000000}, NULL);
- }
- } while (kIOReturnSuccess != ret && retries--);
-
- if (unsuspended)
- /* resuspend the device */
- (void)(*device)->USBDeviceSuspend (device, 1);
-
- if (is_open)
- (void) (*device)->USBDeviceClose (device);
-
- if (ret != kIOReturnSuccess) {
- /* a debug message was already printed out for this error */
- if (LIBUSB_CLASS_HUB == bDeviceClass)
- usbi_dbg (ctx, "could not retrieve device descriptor %.4x:%.4x: %s (%x). skipping device",
- idVendor, idProduct, darwin_error_str (ret), ret);
- else
- usbi_warn (ctx, "could not retrieve device descriptor %.4x:%.4x: %s (%x). skipping device",
- idVendor, idProduct, darwin_error_str (ret), ret);
- return darwin_to_libusb (ret);
- }
-
- /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices. */
- if (libusb_le16_to_cpu (dev->dev_descriptor.idProduct) != idProduct) {
- /* not a valid device */
- usbi_warn (NULL, "idProduct from iokit (%04x) does not match idProduct in descriptor (%04x). skipping device",
- idProduct, libusb_le16_to_cpu (dev->dev_descriptor.idProduct));
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- usbi_dbg (ctx, "cached device descriptor:");
- usbi_dbg (ctx, " bDescriptorType: 0x%02x", dev->dev_descriptor.bDescriptorType);
- usbi_dbg (ctx, " bcdUSB: 0x%04x", libusb_le16_to_cpu (dev->dev_descriptor.bcdUSB));
- usbi_dbg (ctx, " bDeviceClass: 0x%02x", dev->dev_descriptor.bDeviceClass);
- usbi_dbg (ctx, " bDeviceSubClass: 0x%02x", dev->dev_descriptor.bDeviceSubClass);
- usbi_dbg (ctx, " bDeviceProtocol: 0x%02x", dev->dev_descriptor.bDeviceProtocol);
- usbi_dbg (ctx, " bMaxPacketSize0: 0x%02x", dev->dev_descriptor.bMaxPacketSize0);
- usbi_dbg (ctx, " idVendor: 0x%04x", libusb_le16_to_cpu (dev->dev_descriptor.idVendor));
- usbi_dbg (ctx, " idProduct: 0x%04x", libusb_le16_to_cpu (dev->dev_descriptor.idProduct));
- usbi_dbg (ctx, " bcdDevice: 0x%04x", libusb_le16_to_cpu (dev->dev_descriptor.bcdDevice));
- usbi_dbg (ctx, " iManufacturer: 0x%02x", dev->dev_descriptor.iManufacturer);
- usbi_dbg (ctx, " iProduct: 0x%02x", dev->dev_descriptor.iProduct);
- usbi_dbg (ctx, " iSerialNumber: 0x%02x", dev->dev_descriptor.iSerialNumber);
- usbi_dbg (ctx, " bNumConfigurations: 0x%02x", dev->dev_descriptor.bNumConfigurations);
-
- dev->can_enumerate = 1;
-
- return LIBUSB_SUCCESS;
-}
-
-/* Returns 1 on success, 0 on failure. */
-static bool get_device_port (io_service_t service, UInt8 *port) {
- IOReturn kresult;
- io_service_t parent;
- bool ret = false;
-
- if (get_ioregistry_value_number (service, CFSTR("PortNum"), kCFNumberSInt8Type, port)) {
- return true;
- }
-
- kresult = IORegistryEntryGetParentEntry (service, kIOServicePlane, &parent);
- if (kIOReturnSuccess == kresult) {
- ret = get_ioregistry_value_data (parent, CFSTR("port"), 1, port);
- IOObjectRelease (parent);
- }
-
- return ret;
-}
-
-/* Returns 1 on success, 0 on failure. */
-static bool get_device_parent_sessionID(io_service_t service, UInt64 *parent_sessionID) {
- IOReturn kresult;
- io_service_t parent;
-
- /* Walk up the tree in the IOService plane until we find a parent that has a sessionID */
- parent = service;
- while((kresult = IORegistryEntryGetParentEntry (parent, kIOUSBPlane, &parent)) == kIOReturnSuccess) {
- if (get_ioregistry_value_number (parent, CFSTR("sessionID"), kCFNumberSInt64Type, parent_sessionID)) {
- /* Success */
- return true;
- }
- }
-
- /* We ran out of parents */
- return false;
-}
-
-static enum libusb_error darwin_get_cached_device(struct libusb_context *ctx, io_service_t service, struct darwin_cached_device **cached_out,
- UInt64 *old_session_id) {
- struct darwin_cached_device *new_device;
- UInt64 sessionID = 0, parent_sessionID = 0;
- UInt32 locationID = 0;
- enum libusb_error ret = LIBUSB_SUCCESS;
- usb_device_t **device;
- UInt8 port = 0;
-
- /* assuming sessionID != 0 normally (never seen it be 0) */
- *old_session_id = 0;
- *cached_out = NULL;
-
- /* get some info from the io registry */
- (void) get_ioregistry_value_number (service, CFSTR("sessionID"), kCFNumberSInt64Type, &sessionID);
- (void) get_ioregistry_value_number (service, CFSTR("locationID"), kCFNumberSInt32Type, &locationID);
- if (!get_device_port (service, &port)) {
- usbi_dbg(ctx, "could not get connected port number");
- }
-
- usbi_dbg(ctx, "finding cached device for sessionID 0x%" PRIx64, sessionID);
-
- if (get_device_parent_sessionID(service, &parent_sessionID)) {
- usbi_dbg(ctx, "parent sessionID: 0x%" PRIx64, parent_sessionID);
- }
-
- usbi_mutex_lock(&darwin_cached_devices_lock);
- do {
- list_for_each_entry(new_device, &darwin_cached_devices, list, struct darwin_cached_device) {
- usbi_dbg(ctx, "matching sessionID/locationID 0x%" PRIx64 "/0x%x against cached device with sessionID/locationID 0x%" PRIx64 "/0x%x",
- sessionID, locationID, new_device->session, new_device->location);
- if (new_device->location == locationID && new_device->in_reenumerate) {
- usbi_dbg (ctx, "found cached device with matching location that is being re-enumerated");
- *old_session_id = new_device->session;
- break;
- }
-
- if (new_device->session == sessionID) {
- usbi_dbg(ctx, "using cached device for device");
- *cached_out = new_device;
- break;
- }
- }
-
- if (*cached_out)
- break;
-
- usbi_dbg(ctx, "caching new device with sessionID 0x%" PRIx64, sessionID);
-
- device = darwin_device_from_service (ctx, service);
- if (!device) {
- ret = LIBUSB_ERROR_NO_DEVICE;
- break;
- }
-
- if (!(*old_session_id)) {
- new_device = calloc (1, sizeof (*new_device));
- if (!new_device) {
- ret = LIBUSB_ERROR_NO_MEM;
- break;
- }
-
- /* add this device to the cached device list */
- list_add(&new_device->list, &darwin_cached_devices);
-
- (*device)->GetDeviceAddress (device, (USBDeviceAddress *)&new_device->address);
-
- /* keep a reference to this device */
- darwin_ref_cached_device(new_device);
-
- (*device)->GetLocationID (device, &new_device->location);
- new_device->port = port;
- new_device->parent_session = parent_sessionID;
- } else {
- /* release the ref to old device's service */
- IOObjectRelease (new_device->service);
- }
-
- /* keep track of devices regardless of if we successfully enumerate them to
- prevent them from being enumerated multiple times */
- *cached_out = new_device;
-
- new_device->session = sessionID;
- new_device->device = device;
- new_device->service = service;
-
- /* retain the service */
- IOObjectRetain (service);
-
- /* cache the device descriptor */
- ret = darwin_cache_device_descriptor(ctx, new_device);
- if (ret)
- break;
-
- if (new_device->can_enumerate) {
- snprintf(new_device->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", new_device->address,
- libusb_le16_to_cpu (new_device->dev_descriptor.idVendor),
- libusb_le16_to_cpu (new_device->dev_descriptor.idProduct),
- new_device->dev_descriptor.bDeviceClass, new_device->dev_descriptor.bDeviceSubClass);
- }
- } while (0);
-
- usbi_mutex_unlock(&darwin_cached_devices_lock);
-
- return ret;
-}
-
-static enum libusb_error process_new_device (struct libusb_context *ctx, struct darwin_cached_device *cached_device,
- UInt64 old_session_id) {
- struct darwin_device_priv *priv;
- struct libusb_device *dev = NULL;
- UInt8 devSpeed;
- enum libusb_error ret = LIBUSB_SUCCESS;
-
- do {
- /* check current active configuration (and cache the first configuration value--
- which may be used by claim_interface) */
- ret = darwin_check_configuration (ctx, cached_device);
- if (ret)
- break;
-
- if (0 != old_session_id) {
- usbi_dbg (ctx, "re-using existing device from context %p for with session 0x%" PRIx64 " new session 0x%" PRIx64,
- ctx, old_session_id, cached_device->session);
- /* save the libusb device before the session id is updated */
- dev = usbi_get_device_by_session_id (ctx, (unsigned long) old_session_id);
- }
-
- if (!dev) {
- usbi_dbg (ctx, "allocating new device in context %p for with session 0x%" PRIx64,
- ctx, cached_device->session);
-
- dev = usbi_alloc_device(ctx, (unsigned long) cached_device->session);
- if (!dev) {
- return LIBUSB_ERROR_NO_MEM;
- }
-
- priv = usbi_get_device_priv(dev);
-
- priv->dev = cached_device;
- darwin_ref_cached_device (priv->dev);
- dev->port_number = cached_device->port;
- /* the location ID encodes the path to the device. the top byte of the location ID contains the bus number
- (numbered from 0). the remaining bytes can be used to construct the device tree for that bus. */
- dev->bus_number = cached_device->location >> 24;
- assert(cached_device->address <= UINT8_MAX);
- dev->device_address = (uint8_t)cached_device->address;
- } else {
- priv = usbi_get_device_priv(dev);
- }
-
- static_assert(sizeof(dev->device_descriptor) == sizeof(cached_device->dev_descriptor),
- "mismatch between libusb and IOKit device descriptor sizes");
- memcpy(&dev->device_descriptor, &cached_device->dev_descriptor, LIBUSB_DT_DEVICE_SIZE);
- usbi_localize_device_descriptor(&dev->device_descriptor);
- dev->session_data = cached_device->session;
-
- if (NULL != dev->parent_dev) {
- libusb_unref_device(dev->parent_dev);
- dev->parent_dev = NULL;
- }
-
- if (cached_device->parent_session > 0) {
- dev->parent_dev = usbi_get_device_by_session_id (ctx, (unsigned long) cached_device->parent_session);
- }
-
- (*(priv->dev->device))->GetDeviceSpeed (priv->dev->device, &devSpeed);
-
- switch (devSpeed) {
- case kUSBDeviceSpeedLow: dev->speed = LIBUSB_SPEED_LOW; break;
- case kUSBDeviceSpeedFull: dev->speed = LIBUSB_SPEED_FULL; break;
- case kUSBDeviceSpeedHigh: dev->speed = LIBUSB_SPEED_HIGH; break;
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
- case kUSBDeviceSpeedSuper: dev->speed = LIBUSB_SPEED_SUPER; break;
-#endif
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
- case kUSBDeviceSpeedSuperPlus: dev->speed = LIBUSB_SPEED_SUPER_PLUS; break;
-#endif
- default:
- usbi_warn (ctx, "Got unknown device speed %d", devSpeed);
- }
-
- ret = usbi_sanitize_device (dev);
- if (ret < 0)
- break;
-
- usbi_dbg (ctx, "found device with address %d port = %d parent = %p at %p", dev->device_address,
- dev->port_number, (void *) dev->parent_dev, priv->dev->sys_path);
-
- } while (0);
-
- if (!cached_device->in_reenumerate && 0 == ret) {
- usbi_connect_device (dev);
- } else {
- libusb_unref_device (dev);
- }
-
- return ret;
-}
-
-static enum libusb_error darwin_scan_devices(struct libusb_context *ctx) {
- struct darwin_cached_device *cached_device;
- UInt64 old_session_id;
- io_iterator_t deviceIterator;
- io_service_t service;
- IOReturn kresult;
- int ret;
-
- kresult = usb_setup_device_iterator (&deviceIterator, 0);
- if (kresult != kIOReturnSuccess)
- return darwin_to_libusb (kresult);
-
- while ((service = IOIteratorNext (deviceIterator))) {
- ret = darwin_get_cached_device (ctx, service, &cached_device, &old_session_id);
- if (ret < 0 || !cached_device->can_enumerate) {
- continue;
- }
-
- (void) process_new_device (ctx, cached_device, old_session_id);
-
- IOObjectRelease(service);
- }
-
- IOObjectRelease(deviceIterator);
-
- return LIBUSB_SUCCESS;
-}
-
-static int darwin_open (struct libusb_device_handle *dev_handle) {
- struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- IOReturn kresult;
-
- if (0 == dpriv->open_count) {
- /* try to open the device */
- kresult = (*(dpriv->device))->USBDeviceOpenSeize (dpriv->device);
- if (kresult != kIOReturnSuccess) {
- usbi_warn (HANDLE_CTX (dev_handle), "USBDeviceOpen: %s", darwin_error_str(kresult));
-
- if (kIOReturnExclusiveAccess != kresult) {
- return darwin_to_libusb (kresult);
- }
-
- /* it is possible to perform some actions on a device that is not open so do not return an error */
- priv->is_open = false;
- } else {
- priv->is_open = true;
- }
-
- /* create async event source */
- kresult = (*(dpriv->device))->CreateDeviceAsyncEventSource (dpriv->device, &priv->cfSource);
- if (kresult != kIOReturnSuccess) {
- usbi_err (HANDLE_CTX (dev_handle), "CreateDeviceAsyncEventSource: %s", darwin_error_str(kresult));
-
- if (priv->is_open) {
- (*(dpriv->device))->USBDeviceClose (dpriv->device);
- }
-
- priv->is_open = false;
-
- return darwin_to_libusb (kresult);
- }
-
- CFRetain (libusb_darwin_acfl);
-
- /* add the cfSource to the async run loop */
- CFRunLoopAddSource(libusb_darwin_acfl, priv->cfSource, kCFRunLoopCommonModes);
- }
-
- /* device opened successfully */
- dpriv->open_count++;
-
- usbi_dbg (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 = usbi_get_device_handle_priv(dev_handle);
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- 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!");
- return;
- }
-
- dpriv->open_count--;
- if (NULL == dpriv->device) {
- usbi_warn (HANDLE_CTX (dev_handle), "darwin_close device missing IOService");
- return;
- }
-
- /* make sure all interfaces are released */
- for (i = 0 ; i < USB_MAXINTERFACES ; i++)
- if (dev_handle->claimed_interfaces & (1U << i))
- libusb_release_interface (dev_handle, i);
-
- if (0 == dpriv->open_count) {
- /* delete the device's async event source */
- if (priv->cfSource) {
- CFRunLoopRemoveSource (libusb_darwin_acfl, priv->cfSource, kCFRunLoopDefaultMode);
- CFRelease (priv->cfSource);
- priv->cfSource = NULL;
- CFRelease (libusb_darwin_acfl);
- }
-
- if (priv->is_open) {
- /* close the device */
- kresult = (*(dpriv->device))->USBDeviceClose(dpriv->device);
- if (kresult != kIOReturnSuccess) {
- /* 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_warn (HANDLE_CTX (dev_handle), "USBDeviceClose: %s", darwin_error_str(kresult));
- }
- }
- }
-}
-
-static int darwin_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config) {
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
-
- *config = dpriv->active_config;
-
- return LIBUSB_SUCCESS;
-}
-
-static enum libusb_error darwin_set_configuration(struct libusb_device_handle *dev_handle, int config) {
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- IOReturn kresult;
- uint8_t i;
-
- if (config == -1)
- config = 0;
-
- /* 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 & (1U << i))
- darwin_release_interface (dev_handle, i);
-
- kresult = (*(dpriv->device))->SetConfiguration (dpriv->device, (UInt8)config);
- if (kresult != kIOReturnSuccess)
- return darwin_to_libusb (kresult);
-
- /* Reclaim any interfaces. */
- for (i = 0 ; i < USB_MAXINTERFACES ; i++)
- if (dev_handle->claimed_interfaces & (1U << i))
- darwin_claim_interface (dev_handle, i);
-
- dpriv->active_config = (UInt8)config;
-
- return LIBUSB_SUCCESS;
-}
-
-static IOReturn darwin_get_interface (usb_device_t **darwin_device, uint8_t ifc, io_service_t *usbInterfacep) {
- IOUSBFindInterfaceRequest request;
- IOReturn kresult;
- io_iterator_t interface_iterator;
- UInt8 bInterfaceNumber;
- bool ret;
-
- *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 != kIOReturnSuccess)
- return kresult;
-
- while ((*usbInterfacep = IOIteratorNext(interface_iterator))) {
- /* find the interface number */
- ret = get_ioregistry_value_number (*usbInterfacep, CFSTR("bInterfaceNumber"), kCFNumberSInt8Type,
- &bInterfaceNumber);
-
- if (ret && bInterfaceNumber == ifc) {
- break;
- }
-
- (void) IOObjectRelease (*usbInterfacep);
- }
-
- /* done with the interface iterator */
- IOObjectRelease(interface_iterator);
-
- return kIOReturnSuccess;
-}
-
-static enum libusb_error get_endpoints (struct libusb_device_handle *dev_handle, uint8_t iface) {
- struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
-
- /* current interface */
- struct darwin_interface *cInterface = &priv->interfaces[iface];
-
- IOReturn kresult;
-
- UInt8 numep, direction, number;
- UInt8 dont_care1, dont_care3;
- UInt16 dont_care2;
- int rc;
- struct libusb_context *ctx = HANDLE_CTX (dev_handle);
-
-
- usbi_dbg (ctx, "building table of endpoints.");
-
- /* retrieve the total number of endpoints on this interface */
- kresult = (*(cInterface->interface))->GetNumEndpoints(cInterface->interface, &numep);
- if (kresult != kIOReturnSuccess) {
- usbi_err (ctx, "can't get number of endpoints for interface: %s", darwin_error_str(kresult));
- return darwin_to_libusb (kresult);
- }
-
- /* iterate through pipe references */
- for (UInt8 i = 1 ; i <= numep ; i++) {
- kresult = (*(cInterface->interface))->GetPipeProperties(cInterface->interface, i, &direction, &number, &dont_care1,
- &dont_care2, &dont_care3);
-
- if (kresult != kIOReturnSuccess) {
- /* probably a buggy device. try to get the endpoint address from the descriptors */
- struct libusb_config_descriptor *config;
- const struct libusb_endpoint_descriptor *endpoint_desc;
- UInt8 alt_setting;
-
- kresult = (*(cInterface->interface))->GetAlternateSetting (cInterface->interface, &alt_setting);
- if (kresult != kIOReturnSuccess) {
- usbi_err (HANDLE_CTX (dev_handle), "can't get alternate setting for interface");
- return darwin_to_libusb (kresult);
- }
-
- rc = libusb_get_active_config_descriptor (dev_handle->dev, &config);
- if (LIBUSB_SUCCESS != rc) {
- return rc;
- }
-
- endpoint_desc = config->interface[iface].altsetting[alt_setting].endpoint + i - 1;
-
- cInterface->endpoint_addrs[i - 1] = endpoint_desc->bEndpointAddress;
- } else {
- cInterface->endpoint_addrs[i - 1] = (UInt8)(((kUSBIn == direction) << kUSBRqDirnShift) | (number & LIBUSB_ENDPOINT_ADDRESS_MASK));
- }
-
- usbi_dbg (ctx, "interface: %i pipe %i: dir: %i number: %i", iface, i, cInterface->endpoint_addrs[i - 1] >> kUSBRqDirnShift,
- cInterface->endpoint_addrs[i - 1] & LIBUSB_ENDPOINT_ADDRESS_MASK);
- }
-
- cInterface->num_endpoints = numep;
-
- return LIBUSB_SUCCESS;
-}
-
-static int darwin_claim_interface(struct libusb_device_handle *dev_handle, uint8_t iface) {
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
- io_service_t usbInterface = IO_OBJECT_NULL;
- IOReturn kresult;
- enum libusb_error ret;
- IOCFPlugInInterface **plugInInterface = NULL;
- SInt32 score;
-
- /* current interface */
- struct darwin_interface *cInterface = &priv->interfaces[iface];
-
- struct libusb_context *ctx = HANDLE_CTX (dev_handle);
-
- 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 (ctx, "no interface found; setting configuration: %d", dpriv->first_config);
-
- /* set the configuration */
- ret = darwin_set_configuration (dev_handle, (int) dpriv->first_config);
- if (ret != LIBUSB_SUCCESS) {
- usbi_err (ctx, "could not set configuration");
- return ret;
- }
-
- kresult = darwin_get_interface (dpriv->device, iface, &usbInterface);
- if (kresult != kIOReturnSuccess) {
- usbi_err (ctx, "darwin_get_interface: %s", darwin_error_str(kresult));
- return darwin_to_libusb (kresult);
- }
- }
-
- if (!usbInterface) {
- usbi_info (ctx, "interface not found");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- /* get an interface to the device's interface */
- kresult = IOCreatePlugInInterfaceForService (usbInterface, kIOUSBInterfaceUserClientTypeID,
- kIOCFPlugInInterfaceID, &plugInInterface, &score);
-
- /* ignore release error */
- (void)IOObjectRelease (usbInterface);
-
- if (kresult != kIOReturnSuccess) {
- usbi_err (ctx, "IOCreatePlugInInterfaceForService: %s", darwin_error_str(kresult));
- return darwin_to_libusb (kresult);
- }
-
- if (!plugInInterface) {
- usbi_err (ctx, "plugin interface not found");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- /* Do the actual claim */
- kresult = (*plugInInterface)->QueryInterface(plugInInterface,
- CFUUIDGetUUIDBytes(InterfaceInterfaceID),
- (LPVOID)&cInterface->interface);
- /* We no longer need the intermediate plug-in */
- /* Use release instead of IODestroyPlugInInterface to avoid stopping IOServices associated with this device */
- (*plugInInterface)->Release (plugInInterface);
- if (kresult != kIOReturnSuccess || !cInterface->interface) {
- usbi_err (ctx, "QueryInterface: %s", darwin_error_str(kresult));
- return darwin_to_libusb (kresult);
- }
-
- /* claim the interface */
- kresult = (*(cInterface->interface))->USBInterfaceOpen(cInterface->interface);
- if (kresult != kIOReturnSuccess) {
- usbi_info (ctx, "USBInterfaceOpen: %s", darwin_error_str(kresult));
- return darwin_to_libusb (kresult);
- }
-
- /* update list of endpoints */
- ret = get_endpoints (dev_handle, iface);
- if (ret) {
- /* this should not happen */
- darwin_release_interface (dev_handle, iface);
- usbi_err (ctx, "could not build endpoint table");
- return ret;
- }
-
- cInterface->cfSource = NULL;
-
- /* create async event source */
- kresult = (*(cInterface->interface))->CreateInterfaceAsyncEventSource (cInterface->interface, &cInterface->cfSource);
- if (kresult != kIOReturnSuccess) {
- usbi_err (ctx, "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_dbg (ctx, "interface opened");
-
- return LIBUSB_SUCCESS;
-}
-
-static int darwin_release_interface(struct libusb_device_handle *dev_handle, uint8_t iface) {
- struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
- 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);
- cInterface->cfSource = NULL;
- }
-
- kresult = (*(cInterface->interface))->USBInterfaceClose(cInterface->interface);
- if (kresult != kIOReturnSuccess)
- usbi_warn (HANDLE_CTX (dev_handle), "USBInterfaceClose: %s", darwin_error_str(kresult));
-
- kresult = (*(cInterface->interface))->Release(cInterface->interface);
- if (kresult != kIOReturnSuccess)
- usbi_warn (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult));
-
- cInterface->interface = (usb_interface_t **) IO_OBJECT_NULL;
-
- return darwin_to_libusb (kresult);
-}
-
-static int check_alt_setting_and_clear_halt(struct libusb_device_handle *dev_handle, uint8_t altsetting, struct darwin_interface *cInterface) {
- enum libusb_error ret;
- IOReturn kresult;
- uint8_t current_alt_setting;
-
- kresult = (*(cInterface->interface))->GetAlternateSetting (cInterface->interface, &current_alt_setting);
- if (kresult == kIOReturnSuccess && altsetting != current_alt_setting) {
- return LIBUSB_ERROR_PIPE;
- }
-
- for (int i = 0 ; i < cInterface->num_endpoints ; i++) {
- ret = darwin_clear_halt(dev_handle, cInterface->endpoint_addrs[i]);
- if (LIBUSB_SUCCESS != ret) {
- usbi_warn(HANDLE_CTX (dev_handle), "error clearing pipe halt for endpoint %d", i);
- if (LIBUSB_ERROR_NOT_FOUND == ret) {
- /* may need to re-open the interface */
- return ret;
- }
- }
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int darwin_set_interface_altsetting(struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting) {
- struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
- IOReturn kresult;
- enum libusb_error ret;
-
- /* 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) {
- /* update the list of endpoints */
- ret = get_endpoints (dev_handle, iface);
- if (ret) {
- /* this should not happen */
- darwin_release_interface (dev_handle, iface);
- usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table");
- }
- return ret;
- }
-
- usbi_warn (HANDLE_CTX (dev_handle), "SetAlternateInterface: %s", darwin_error_str(kresult));
-
- ret = darwin_to_libusb(kresult);
- if (ret != LIBUSB_ERROR_PIPE) {
- return ret;
- }
-
- /* If a device only supports a default setting for the specified interface, then a STALL
- (kIOUSBPipeStalled) may be returned. Ref: USB 2.0 specs 9.4.10.
- Mimic the behaviour in e.g. the Linux kernel: in such case, reset all endpoints
- of the interface (as would have been done per 9.1.1.5) and return success. */
-
- ret = check_alt_setting_and_clear_halt(dev_handle, altsetting, cInterface);
- if (LIBUSB_ERROR_NOT_FOUND == ret) {
- /* For some reason we need to reclaim the interface after the pipe error with some versions of macOS */
- ret = darwin_claim_interface (dev_handle, iface);
- if (LIBUSB_SUCCESS != ret) {
- darwin_release_interface (dev_handle, iface);
- usbi_err (HANDLE_CTX (dev_handle), "could not reclaim interface: %s", darwin_error_str(kresult));
- }
- ret = check_alt_setting_and_clear_halt(dev_handle, altsetting, cInterface);
- }
-
- return ret;
-}
-
-static int darwin_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) {
- /* current interface */
- struct darwin_interface *cInterface;
- IOReturn kresult;
- uint8_t pipeRef;
-
- /* determine the interface/endpoint to use */
- if (ep_to_pipeRef (dev_handle, endpoint, &pipeRef, NULL, &cInterface) != 0) {
- usbi_err (HANDLE_CTX (dev_handle), "endpoint not found on any open interface");
-
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- /* newer versions of darwin support clearing additional bits on the device's endpoint */
- kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef);
- if (kresult != kIOReturnSuccess)
- usbi_warn (HANDLE_CTX (dev_handle), "ClearPipeStall: %s", darwin_error_str (kresult));
-
- return darwin_to_libusb (kresult);
-}
-
-static int darwin_restore_state (struct libusb_device_handle *dev_handle, int8_t active_config,
- unsigned long claimed_interfaces) {
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
- int open_count = dpriv->open_count;
- int ret;
-
- struct libusb_context *ctx = HANDLE_CTX (dev_handle);
-
- /* clear claimed interfaces temporarily */
- dev_handle->claimed_interfaces = 0;
-
- /* close and re-open the device */
- priv->is_open = false;
- dpriv->open_count = 1;
-
- /* clean up open interfaces */
- (void) darwin_close (dev_handle);
-
- /* re-open the device */
- ret = darwin_open (dev_handle);
- dpriv->open_count = open_count;
- if (LIBUSB_SUCCESS != ret) {
- /* could not restore configuration */
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- if (dpriv->active_config != active_config) {
- usbi_dbg (ctx, "darwin/restore_state: restoring configuration %d...", active_config);
-
- ret = darwin_set_configuration (dev_handle, active_config);
- if (LIBUSB_SUCCESS != ret) {
- usbi_dbg (ctx, "darwin/restore_state: could not restore configuration");
- return LIBUSB_ERROR_NOT_FOUND;
- }
- }
-
- usbi_dbg (ctx, "darwin/restore_state: reclaiming interfaces");
-
- if (claimed_interfaces) {
- for (uint8_t iface = 0 ; iface < USB_MAXINTERFACES ; ++iface) {
- if (!(claimed_interfaces & (1U << iface))) {
- continue;
- }
-
- usbi_dbg (ctx, "darwin/restore_state: re-claiming interface %u", iface);
-
- ret = darwin_claim_interface (dev_handle, iface);
- if (LIBUSB_SUCCESS != ret) {
- usbi_dbg (ctx, "darwin/restore_state: could not claim interface %u", iface);
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- dev_handle->claimed_interfaces |= 1U << iface;
- }
- }
-
- usbi_dbg (ctx, "darwin/restore_state: device state restored");
-
- return LIBUSB_SUCCESS;
-}
-
-static int darwin_reenumerate_device (struct libusb_device_handle *dev_handle, bool capture) {
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- unsigned long claimed_interfaces = dev_handle->claimed_interfaces;
- int8_t active_config = dpriv->active_config;
- UInt32 options = 0;
- IOUSBDeviceDescriptor descriptor;
- IOUSBConfigurationDescriptorPtr cached_configuration;
- IOUSBConfigurationDescriptor *cached_configurations;
- IOReturn kresult;
- UInt8 i;
-
- struct libusb_context *ctx = HANDLE_CTX (dev_handle);
-
- if (dpriv->in_reenumerate) {
- /* ack, two (or more) threads are trying to reset the device! abort! */
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- dpriv->in_reenumerate = true;
-
- /* store copies of descriptors so they can be compared after the reset */
- memcpy (&descriptor, &dpriv->dev_descriptor, sizeof (descriptor));
- cached_configurations = alloca (sizeof (*cached_configurations) * descriptor.bNumConfigurations);
-
- for (i = 0 ; i < descriptor.bNumConfigurations ; ++i) {
- (*(dpriv->device))->GetConfigurationDescriptorPtr (dpriv->device, i, &cached_configuration);
- memcpy (cached_configurations + i, cached_configuration, sizeof (cached_configurations[i]));
- }
-
- /* if we need to release capture */
- if (HAS_CAPTURE_DEVICE()) {
- if (capture) {
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
- options |= kUSBReEnumerateCaptureDeviceMask;
-#endif
- }
- } else {
- capture = false;
- }
-
- /* from macOS 10.11 ResetDevice no longer does anything so just use USBDeviceReEnumerate */
- kresult = (*(dpriv->device))->USBDeviceReEnumerate (dpriv->device, options);
- if (kresult != kIOReturnSuccess) {
- usbi_err (ctx, "USBDeviceReEnumerate: %s", darwin_error_str (kresult));
- dpriv->in_reenumerate = false;
- return darwin_to_libusb (kresult);
- }
-
- /* capture mode does not re-enumerate but it does require re-open */
- if (capture) {
- usbi_dbg (ctx, "darwin/reenumerate_device: restoring state...");
- dpriv->in_reenumerate = false;
- return darwin_restore_state (dev_handle, active_config, claimed_interfaces);
- }
-
- usbi_dbg (ctx, "darwin/reenumerate_device: waiting for re-enumeration to complete...");
-
- struct timespec start;
- clock_gettime(CLOCK_MONOTONIC, &start);
-
- while (dpriv->in_reenumerate) {
- struct timespec delay = {.tv_sec = 0, .tv_nsec = 1000};
- nanosleep (&delay, NULL);
-
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
- UInt32 elapsed = (now.tv_sec - start.tv_sec) * 1000000 + (now.tv_nsec - start.tv_nsec) / 1000;
-
- if (elapsed >= DARWIN_REENUMERATE_TIMEOUT_US) {
- usbi_err (ctx, "darwin/reenumerate_device: timeout waiting for reenumerate");
- dpriv->in_reenumerate = false;
- return LIBUSB_ERROR_TIMEOUT;
- }
- }
-
- /* compare descriptors */
- usbi_dbg (ctx, "darwin/reenumerate_device: checking whether descriptors changed");
-
- if (memcmp (&descriptor, &dpriv->dev_descriptor, sizeof (descriptor))) {
- /* device descriptor changed. need to return not found. */
- usbi_dbg (ctx, "darwin/reenumerate_device: device descriptor changed");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- for (i = 0 ; i < descriptor.bNumConfigurations ; ++i) {
- (void) (*(dpriv->device))->GetConfigurationDescriptorPtr (dpriv->device, i, &cached_configuration);
- if (memcmp (cached_configuration, cached_configurations + i, sizeof (cached_configurations[i]))) {
- usbi_dbg (ctx, "darwin/reenumerate_device: configuration descriptor %d changed", i);
- return LIBUSB_ERROR_NOT_FOUND;
- }
- }
-
- usbi_dbg (ctx, "darwin/reenumerate_device: device reset complete. restoring state...");
-
- return darwin_restore_state (dev_handle, active_config, claimed_interfaces);
-}
-
-static int darwin_reset_device (struct libusb_device_handle *dev_handle) {
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- IOReturn kresult;
-
- if (dpriv->capture_count > 0) {
- /* we have to use ResetDevice as USBDeviceReEnumerate() loses the authorization for capture */
- kresult = (*(dpriv->device))->ResetDevice (dpriv->device);
- return darwin_to_libusb (kresult);
- } else {
- return darwin_reenumerate_device (dev_handle, false);
- }
-}
-
-static io_service_t usb_find_interface_matching_location (const io_name_t class_name, UInt8 interface_number, UInt32 location) {
- CFMutableDictionaryRef matchingDict = IOServiceMatching (class_name);
- CFMutableDictionaryRef propertyMatchDict = CFDictionaryCreateMutable (kCFAllocatorDefault, 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- CFTypeRef locationCF = CFNumberCreate (NULL, kCFNumberSInt32Type, &location);
- CFTypeRef interfaceCF = CFNumberCreate (NULL, kCFNumberSInt8Type, &interface_number);
-
- CFDictionarySetValue (matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict);
- CFDictionarySetValue (propertyMatchDict, CFSTR(kUSBDevicePropertyLocationID), locationCF);
- CFDictionarySetValue (propertyMatchDict, CFSTR(kUSBHostMatchingPropertyInterfaceNumber), interfaceCF);
-
- CFRelease (interfaceCF);
- CFRelease (locationCF);
- CFRelease (propertyMatchDict);
-
- return IOServiceGetMatchingService (darwin_default_master_port, matchingDict);
-}
-
-static int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle, uint8_t interface) {
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- io_service_t usb_interface, child = IO_OBJECT_NULL;
-
- /* locate the IO registry entry for this interface */
- usb_interface = usb_find_interface_matching_location (kIOUSBHostInterfaceClassName, interface, dpriv->location);
- if (0 == usb_interface) {
- /* check for the legacy class entry */
- usb_interface = usb_find_interface_matching_location (kIOUSBInterfaceClassName, interface, dpriv->location);
- if (0 == usb_interface) {
- return LIBUSB_ERROR_NOT_FOUND;
- }
- }
-
- /* if the IO object has a child entry in the IO Registry it has a kernel driver attached */
- (void) IORegistryEntryGetChildEntry (usb_interface, kIOServicePlane, &child);
- IOObjectRelease (usb_interface);
- if (IO_OBJECT_NULL != child) {
- IOObjectRelease (child);
- return 1;
- }
-
- /* no driver */
- return 0;
-}
-
-static void darwin_destroy_device(struct libusb_device *dev) {
- struct darwin_device_priv *dpriv = usbi_get_device_priv(dev);
-
- if (dpriv->dev) {
- /* need to hold the lock in case this is the last reference to the device */
- usbi_mutex_lock(&darwin_cached_devices_lock);
- darwin_deref_cached_device (dpriv->dev);
- dpriv->dev = NULL;
- usbi_mutex_unlock(&darwin_cached_devices_lock);
- }
-}
-
-static int submit_bulk_transfer(struct usbi_transfer *itransfer) {
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-
- IOReturn ret;
- uint8_t transferType;
- uint8_t pipeRef;
- uint16_t maxPacketSize;
-
- struct darwin_interface *cInterface;
-#if InterfaceVersion >= 550
- IOUSBEndpointProperties pipeProperties = {.bVersion = kUSBEndpointPropertiesVersion3};
-#else
- /* None of the values below are used in libusb for bulk transfers */
- uint8_t direction, number, interval;
-#endif
-
- if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, NULL, &cInterface) != 0) {
- usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
-
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
-#if InterfaceVersion >= 550
- ret = (*(cInterface->interface))->GetPipePropertiesV3 (cInterface->interface, pipeRef, &pipeProperties);
-
- transferType = pipeProperties.bTransferType;
- maxPacketSize = pipeProperties.wMaxPacketSize;
-#else
- ret = (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number,
- &transferType, &maxPacketSize, &interval);
-#endif
-
- if (ret) {
- usbi_err (TRANSFER_CTX (transfer), "bulk transfer failed (dir = %s): %s (code = 0x%08x)", IS_XFERIN(transfer) ? "In" : "Out",
- darwin_error_str(ret), ret);
- return darwin_to_libusb (ret);
- }
-
- if (0 != (transfer->length % maxPacketSize)) {
- /* do not need a zero packet */
- transfer->flags &= ~LIBUSB_TRANSFER_ADD_ZERO_PACKET;
- }
-
- /* submit the request */
- /* timeouts are unavailable on interrupt endpoints */
- if (transferType == kUSBInterrupt) {
- if (IS_XFERIN(transfer))
- ret = (*(cInterface->interface))->ReadPipeAsync(cInterface->interface, pipeRef, transfer->buffer,
- (UInt32)transfer->length, darwin_async_io_callback, itransfer);
- else
- ret = (*(cInterface->interface))->WritePipeAsync(cInterface->interface, pipeRef, transfer->buffer,
- (UInt32)transfer->length, darwin_async_io_callback, itransfer);
- } else {
- itransfer->timeout_flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
-
- if (IS_XFERIN(transfer))
- ret = (*(cInterface->interface))->ReadPipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer,
- (UInt32)transfer->length, transfer->timeout, transfer->timeout,
- darwin_async_io_callback, itransfer);
- else
- ret = (*(cInterface->interface))->WritePipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer,
- (UInt32)transfer->length, transfer->timeout, transfer->timeout,
- darwin_async_io_callback, itransfer);
- }
-
- if (ret)
- usbi_err (TRANSFER_CTX (transfer), "bulk transfer failed (dir = %s): %s (code = 0x%08x)", IS_XFERIN(transfer) ? "In" : "Out",
- darwin_error_str(ret), ret);
-
- return darwin_to_libusb (ret);
-}
-
-#if InterfaceVersion >= 550
-static int submit_stream_transfer(struct usbi_transfer *itransfer) {
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct darwin_interface *cInterface;
- uint8_t pipeRef;
- IOReturn ret;
-
- if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, NULL, &cInterface) != 0) {
- usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
-
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- itransfer->timeout_flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
-
- if (IS_XFERIN(transfer))
- ret = (*(cInterface->interface))->ReadStreamsPipeAsyncTO(cInterface->interface, pipeRef, itransfer->stream_id,
- transfer->buffer, (UInt32)transfer->length, transfer->timeout,
- transfer->timeout, darwin_async_io_callback, itransfer);
- else
- ret = (*(cInterface->interface))->WriteStreamsPipeAsyncTO(cInterface->interface, pipeRef, itransfer->stream_id,
- transfer->buffer, (UInt32)transfer->length, transfer->timeout,
- transfer->timeout, darwin_async_io_callback, itransfer);
-
- if (ret)
- usbi_err (TRANSFER_CTX (transfer), "bulk stream transfer failed (dir = %s): %s (code = 0x%08x)", IS_XFERIN(transfer) ? "In" : "Out",
- darwin_error_str(ret), ret);
-
- return darwin_to_libusb (ret);
-}
-#endif
-
-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_get_transfer_priv(itransfer);
-
- IOReturn kresult;
- uint8_t direction, number, interval, pipeRef, transferType;
- uint16_t maxPacketSize;
- UInt64 frame;
- AbsoluteTime atTime;
- int i;
-
- struct darwin_interface *cInterface;
-
- /* construct an array of IOUSBIsocFrames, reuse the old one if the sizes are the same */
- if (tpriv->num_iso_packets != transfer->num_iso_packets) {
- free(tpriv->isoc_framelist);
- tpriv->isoc_framelist = NULL;
- }
-
- if (!tpriv->isoc_framelist) {
- tpriv->num_iso_packets = transfer->num_iso_packets;
- tpriv->isoc_framelist = (IOUSBIsocFrame*) calloc ((size_t)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++) {
- unsigned int length = transfer->iso_packet_desc[i].length;
- assert(length <= UINT16_MAX);
- tpriv->isoc_framelist[i].frReqCount = (UInt16)length;
- }
-
- /* determine the interface/endpoint to use */
- if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, NULL, &cInterface) != 0) {
- usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
-
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- /* determine the properties of this endpoint and the speed of the device */
- (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number,
- &transferType, &maxPacketSize, &interval);
-
- /* Last but not least we need the bus frame number */
- kresult = (*(cInterface->interface))->GetBusFrameNumber(cInterface->interface, &frame, &atTime);
- if (kresult != kIOReturnSuccess) {
- 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);
- }
-
- (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number,
- &transferType, &maxPacketSize, &interval);
-
- /* schedule for a frame a little in the future */
- frame += 4;
-
- if (cInterface->frames[transfer->endpoint] && frame < cInterface->frames[transfer->endpoint])
- frame = cInterface->frames[transfer->endpoint];
-
- /* submit the request */
- if (IS_XFERIN(transfer))
- kresult = (*(cInterface->interface))->ReadIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame,
- (UInt32)transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback,
- itransfer);
- else
- kresult = (*(cInterface->interface))->WriteIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame,
- (UInt32)transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback,
- itransfer);
-
- if (LIBUSB_SPEED_FULL == transfer->dev_handle->dev->speed)
- /* Full speed */
- cInterface->frames[transfer->endpoint] = frame + (UInt32)transfer->num_iso_packets * (1U << (interval - 1));
- else
- /* High/super speed */
- cInterface->frames[transfer->endpoint] = frame + (UInt32)transfer->num_iso_packets * (1U << (interval - 1)) / 8;
-
- if (kresult != kIOReturnSuccess) {
- usbi_err (TRANSFER_CTX (transfer), "isochronous transfer failed (dir: %s): %s", IS_XFERIN(transfer) ? "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_cached_device *dpriv = DARWIN_CACHED_DEVICE(transfer->dev_handle->dev);
- struct darwin_transfer_priv *tpriv = usbi_get_transfer_priv(itransfer);
-
- IOReturn kresult;
-
- memset(&tpriv->req, 0, sizeof(tpriv->req));
-
- /* IOUSBDeviceInterface expects the request in cpu endianness */
- 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;
-
- itransfer->timeout_flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
-
- /* all transfers in libusb-1.0 are async */
-
- if (transfer->endpoint) {
- struct darwin_interface *cInterface;
- uint8_t pipeRef;
-
- if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, NULL, &cInterface) != 0) {
- usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
-
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- kresult = (*(cInterface->interface))->ControlRequestAsyncTO (cInterface->interface, pipeRef, &(tpriv->req), darwin_async_io_callback, itransfer);
- } else
- /* control request on endpoint 0 */
- 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);
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
-#if InterfaceVersion >= 550
- return submit_stream_transfer(itransfer);
-#else
- usbi_err (TRANSFER_CTX(transfer), "IOUSBFamily version does not support bulk stream transfers");
- return LIBUSB_ERROR_NOT_SUPPORTED;
-#endif
- 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_cached_device *dpriv = DARWIN_CACHED_DEVICE(transfer->dev_handle->dev);
- IOReturn kresult;
-
- usbi_warn (ITRANSFER_CTX (itransfer), "aborting all transactions control pipe");
-
- if (!dpriv->device)
- return LIBUSB_ERROR_NO_DEVICE;
-
- 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_cached_device *dpriv = DARWIN_CACHED_DEVICE(transfer->dev_handle->dev);
- struct darwin_interface *cInterface;
- uint8_t pipeRef, iface;
- IOReturn kresult;
-
- struct libusb_context *ctx = ITRANSFER_CTX (itransfer);
-
- if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface, &cInterface) != 0) {
- usbi_err (ctx, "endpoint not found on any open interface");
-
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- if (!dpriv->device)
- return LIBUSB_ERROR_NO_DEVICE;
-
- usbi_warn (ctx, "aborting all transactions on interface %d pipe %d", iface, pipeRef);
-
- /* abort transactions */
-#if InterfaceVersion >= 550
- if (LIBUSB_TRANSFER_TYPE_BULK_STREAM == transfer->type)
- (*(cInterface->interface))->AbortStreamsPipe (cInterface->interface, pipeRef, itransfer->stream_id);
- else
-#endif
- (*(cInterface->interface))->AbortPipe (cInterface->interface, pipeRef);
-
- usbi_dbg (ctx, "calling clear pipe stall to clear the data toggle bit");
-
- /* newer versions of darwin support clearing additional bits on the device's endpoint */
- kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef);
-
- 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_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_transfer_priv *tpriv = usbi_get_transfer_priv(itransfer);
-
- usbi_dbg (TRANSFER_CTX(transfer), "an async io operation has completed");
-
- /* if requested write a zero packet */
- if (kIOReturnSuccess == result && IS_XFEROUT(transfer) && transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
- struct darwin_interface *cInterface;
- uint8_t pipeRef;
-
- (void) ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, NULL, &cInterface);
-
- (*(cInterface->interface))->WritePipe (cInterface->interface, pipeRef, transfer->buffer, 0);
- }
-
- tpriv->result = result;
- tpriv->size = (UInt32) (uintptr_t) arg0;
-
- /* signal the core that this transfer is complete */
- usbi_signal_transfer_completion(itransfer);
-}
-
-static enum libusb_transfer_status darwin_transfer_status (struct usbi_transfer *itransfer, IOReturn result) {
- if (itransfer->timeout_flags & USBI_TRANSFER_TIMED_OUT)
- result = kIOUSBTransactionTimeout;
-
- struct libusb_context *ctx = ITRANSFER_CTX (itransfer);
-
- switch (result) {
- case kIOReturnUnderrun:
- case kIOReturnSuccess:
- return LIBUSB_TRANSFER_COMPLETED;
- case kIOReturnAborted:
- return LIBUSB_TRANSFER_CANCELLED;
- case kIOUSBPipeStalled:
- usbi_dbg (ctx, "transfer error: pipe is stalled");
- return LIBUSB_TRANSFER_STALL;
- case kIOReturnOverrun:
- usbi_warn (ctx, "transfer error: data overrun");
- return LIBUSB_TRANSFER_OVERFLOW;
- case kIOUSBTransactionTimeout:
- usbi_warn (ctx, "transfer error: timed out");
- itransfer->timeout_flags |= USBI_TRANSFER_TIMED_OUT;
- return LIBUSB_TRANSFER_TIMED_OUT;
- default:
- usbi_warn (ctx, "transfer error: %s (value = 0x%08x)", darwin_error_str (result), result);
- return LIBUSB_TRANSFER_ERROR;
- }
-}
-
-static int darwin_handle_transfer_completion (struct usbi_transfer *itransfer) {
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct darwin_transfer_priv *tpriv = usbi_get_transfer_priv(itransfer);
- const unsigned char max_transfer_type = LIBUSB_TRANSFER_TYPE_BULK_STREAM;
- const char *transfer_types[] = {"control", "isoc", "bulk", "interrupt", "bulk-stream", NULL};
- bool is_isoc = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type;
- struct libusb_context *ctx = ITRANSFER_CTX (itransfer);
-
- if (transfer->type > max_transfer_type) {
- usbi_err (ctx, "unknown endpoint type %d", transfer->type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- if (NULL == tpriv) {
- usbi_err (ctx, "malformed request is missing transfer priv");
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- usbi_dbg (ctx, "handling transfer completion type %s with kernel status %d", transfer_types[transfer->type], tpriv->result);
-
- if (kIOReturnSuccess == tpriv->result || kIOReturnUnderrun == tpriv->result || kIOUSBTransactionTimeout == tpriv->result) {
- if (is_isoc && tpriv->isoc_framelist) {
- /* copy isochronous results back */
-
- for (int i = 0; i < transfer->num_iso_packets ; i++) {
- struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
- lib_desc->status = darwin_transfer_status (itransfer, tpriv->isoc_framelist[i].frStatus);
- lib_desc->actual_length = tpriv->isoc_framelist[i].frActCount;
- }
- } else if (!is_isoc) {
- itransfer->transferred += tpriv->size;
- }
- }
-
- /* it is ok to handle cancelled transfers without calling usbi_handle_transfer_cancellation (we catch timeout transfers) */
- return usbi_handle_transfer_completion (itransfer, darwin_transfer_status (itransfer, tpriv->result));
-}
-
-#if !defined(HAVE_CLOCK_GETTIME)
-void usbi_get_monotonic_time(struct timespec *tp) {
- mach_timespec_t sys_time;
-
- /* use system boot time as reference for the monotonic clock */
- clock_get_time (clock_monotonic, &sys_time);
-
- tp->tv_sec = sys_time.tv_sec;
- tp->tv_nsec = sys_time.tv_nsec;
-}
-
-void usbi_get_real_time(struct timespec *tp) {
- mach_timespec_t sys_time;
-
- /* CLOCK_REALTIME represents time since the epoch */
- clock_get_time (clock_realtime, &sys_time);
-
- tp->tv_sec = sys_time.tv_sec;
- tp->tv_nsec = sys_time.tv_nsec;
-}
-#endif
-
-#if InterfaceVersion >= 550
-static int darwin_alloc_streams (struct libusb_device_handle *dev_handle, uint32_t num_streams, unsigned char *endpoints,
- int num_endpoints) {
- struct darwin_interface *cInterface;
- UInt32 supportsStreams;
- uint8_t pipeRef;
- int rc, i;
-
- /* find the minimum number of supported streams on the endpoint list */
- for (i = 0 ; i < num_endpoints ; ++i) {
- if (0 != (rc = ep_to_pipeRef (dev_handle, endpoints[i], &pipeRef, NULL, &cInterface))) {
- return rc;
- }
-
- (*(cInterface->interface))->SupportsStreams (cInterface->interface, pipeRef, &supportsStreams);
- if (num_streams > supportsStreams)
- num_streams = supportsStreams;
- }
-
- /* it is an error if any endpoint in endpoints does not support streams */
- if (0 == num_streams)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- /* create the streams */
- for (i = 0 ; i < num_endpoints ; ++i) {
- (void) ep_to_pipeRef (dev_handle, endpoints[i], &pipeRef, NULL, &cInterface);
-
- rc = (*(cInterface->interface))->CreateStreams (cInterface->interface, pipeRef, num_streams);
- if (kIOReturnSuccess != rc)
- return darwin_to_libusb(rc);
- }
-
- assert(num_streams <= INT_MAX);
- return (int)num_streams;
-}
-
-static int darwin_free_streams (struct libusb_device_handle *dev_handle, unsigned char *endpoints, int num_endpoints) {
- struct darwin_interface *cInterface;
- UInt32 supportsStreams;
- uint8_t pipeRef;
- int rc;
-
- for (int i = 0 ; i < num_endpoints ; ++i) {
- if (0 != (rc = ep_to_pipeRef (dev_handle, endpoints[i], &pipeRef, NULL, &cInterface)))
- return rc;
-
- (*(cInterface->interface))->SupportsStreams (cInterface->interface, pipeRef, &supportsStreams);
- if (0 == supportsStreams)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- rc = (*(cInterface->interface))->CreateStreams (cInterface->interface, pipeRef, 0);
- if (kIOReturnSuccess != rc)
- return darwin_to_libusb(rc);
- }
-
- return LIBUSB_SUCCESS;
-}
-#endif
-
-#if InterfaceVersion >= 700
-
-/* macOS APIs for getting entitlement values */
-
-#if TARGET_OS_OSX
-#include <Security/Security.h>
-#else
-typedef struct __SecTask *SecTaskRef;
-extern SecTaskRef SecTaskCreateFromSelf(CFAllocatorRef allocator);
-extern CFTypeRef SecTaskCopyValueForEntitlement(SecTaskRef task, CFStringRef entitlement, CFErrorRef *error);
-#endif
-
-static bool darwin_has_capture_entitlements (void) {
- SecTaskRef task;
- CFTypeRef value;
- bool entitled;
-
- task = SecTaskCreateFromSelf (kCFAllocatorDefault);
- if (task == NULL) {
- return false;
- }
- value = SecTaskCopyValueForEntitlement(task, CFSTR("com.apple.vm.device-access"), NULL);
- CFRelease (task);
- entitled = value && (CFGetTypeID (value) == CFBooleanGetTypeID ()) && CFBooleanGetValue (value);
- if (value) {
- CFRelease (value);
- }
- return entitled;
-}
-
-static int darwin_reload_device (struct libusb_device_handle *dev_handle) {
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- enum libusb_error err;
-
- usbi_mutex_lock(&darwin_cached_devices_lock);
- (*(dpriv->device))->Release(dpriv->device);
- dpriv->device = darwin_device_from_service (HANDLE_CTX (dev_handle), dpriv->service);
- if (!dpriv->device) {
- err = LIBUSB_ERROR_NO_DEVICE;
- } else {
- err = LIBUSB_SUCCESS;
- }
- usbi_mutex_unlock(&darwin_cached_devices_lock);
-
- return err;
-}
-
-/* On macOS, we capture an entire device at once, not individual interfaces. */
-
-static int darwin_detach_kernel_driver (struct libusb_device_handle *dev_handle, uint8_t interface) {
- UNUSED(interface);
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- IOReturn kresult;
- enum libusb_error err;
- struct libusb_context *ctx = HANDLE_CTX (dev_handle);
-
- if (HAS_CAPTURE_DEVICE()) {
- } else {
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-
- if (dpriv->capture_count == 0) {
- usbi_dbg (ctx, "attempting to detach kernel driver from device");
-
- if (darwin_has_capture_entitlements ()) {
- /* request authorization */
- kresult = IOServiceAuthorize (dpriv->service, kIOServiceInteractionAllowed);
- if (kresult != kIOReturnSuccess) {
- usbi_warn (ctx, "IOServiceAuthorize: %s", darwin_error_str(kresult));
- return darwin_to_libusb (kresult);
- }
-
- /* we need start() to be called again for authorization status to refresh */
- err = darwin_reload_device (dev_handle);
- if (err != LIBUSB_SUCCESS) {
- return err;
- }
- } else {
- usbi_info (ctx, "no capture entitlements. may not be able to detach the kernel driver for this device");
- if (0 != geteuid()) {
- usbi_warn (ctx, "USB device capture requires either an entitlement (com.apple.vm.device-access) or root privilege");
- return LIBUSB_ERROR_ACCESS;
- }
- }
-
- /* reset device to release existing drivers */
- err = darwin_reenumerate_device (dev_handle, true);
- if (err != LIBUSB_SUCCESS) {
- return err;
- }
- }
- dpriv->capture_count++;
- return LIBUSB_SUCCESS;
-}
-
-
-static int darwin_attach_kernel_driver (struct libusb_device_handle *dev_handle, uint8_t interface) {
- UNUSED(interface);
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
-
- if (HAS_CAPTURE_DEVICE()) {
- } else {
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-
- dpriv->capture_count--;
- if (dpriv->capture_count > 0) {
- return LIBUSB_SUCCESS;
- }
-
- usbi_dbg (HANDLE_CTX (dev_handle), "reenumerating device for kernel driver attach");
-
- /* reset device to attach kernel drivers */
- return darwin_reenumerate_device (dev_handle, false);
-}
-
-static int darwin_capture_claim_interface(struct libusb_device_handle *dev_handle, uint8_t iface) {
- enum libusb_error ret;
- if (dev_handle->auto_detach_kernel_driver && darwin_kernel_driver_active(dev_handle, iface)) {
- ret = darwin_detach_kernel_driver (dev_handle, iface);
- if (ret != LIBUSB_SUCCESS) {
- usbi_info (HANDLE_CTX (dev_handle), "failed to auto-detach the kernel driver for this device, ret=%d", ret);
- }
- }
-
- return darwin_claim_interface (dev_handle, iface);
-}
-
-static int darwin_capture_release_interface(struct libusb_device_handle *dev_handle, uint8_t iface) {
- enum libusb_error ret;
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
-
- ret = darwin_release_interface (dev_handle, iface);
- if (ret != LIBUSB_SUCCESS) {
- return ret;
- }
-
- if (dev_handle->auto_detach_kernel_driver && dpriv->capture_count > 0) {
- ret = darwin_attach_kernel_driver (dev_handle, iface);
- if (LIBUSB_SUCCESS != ret) {
- usbi_info (HANDLE_CTX (dev_handle), "on attempt to reattach the kernel driver got ret=%d", ret);
- }
- /* ignore the error as the interface was successfully released */
- }
-
- return LIBUSB_SUCCESS;
-}
-
-#endif
-
-const struct usbi_os_backend usbi_backend = {
- .name = "Darwin",
- .caps = USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER,
- .init = darwin_init,
- .exit = darwin_exit,
- .get_active_config_descriptor = darwin_get_active_config_descriptor,
- .get_config_descriptor = darwin_get_config_descriptor,
- .hotplug_poll = darwin_hotplug_poll,
-
- .open = darwin_open,
- .close = darwin_close,
- .get_configuration = darwin_get_configuration,
- .set_configuration = darwin_set_configuration,
-
- .set_interface_altsetting = darwin_set_interface_altsetting,
- .clear_halt = darwin_clear_halt,
- .reset_device = darwin_reset_device,
-
-#if InterfaceVersion >= 550
- .alloc_streams = darwin_alloc_streams,
- .free_streams = darwin_free_streams,
-#endif
-
- .kernel_driver_active = darwin_kernel_driver_active,
-
-#if InterfaceVersion >= 700
- .detach_kernel_driver = darwin_detach_kernel_driver,
- .attach_kernel_driver = darwin_attach_kernel_driver,
- .claim_interface = darwin_capture_claim_interface,
- .release_interface = darwin_capture_release_interface,
-#else
- .claim_interface = darwin_claim_interface,
- .release_interface = darwin_release_interface,
-#endif
-
- .destroy_device = darwin_destroy_device,
-
- .submit_transfer = darwin_submit_transfer,
- .cancel_transfer = darwin_cancel_transfer,
-
- .handle_transfer_completion = darwin_handle_transfer_completion,
-
- .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),
-};
diff --git a/src/os/darwin_usb.h b/src/os/darwin_usb.h
deleted file mode 100644
index 7b72fff..0000000
--- a/src/os/darwin_usb.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * darwin backend for libusb 1.0
- * Copyright © 2008-2019 Nathan Hjelm <hjelmn@users.sourceforge.net>
- * Copyright © 2019 Google LLC. All rights reserved.
- *
- * 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 <stdbool.h>
-
-#include "libusbi.h"
-
-#include <IOKit/IOTypes.h>
-#include <IOKit/IOCFBundle.h>
-#include <IOKit/usb/IOUSBLib.h>
-#include <IOKit/IOCFPlugIn.h>
-
-#if defined(HAVE_IOKIT_USB_IOUSBHOSTFAMILYDEFINITIONS_H)
-#include <IOKit/usb/IOUSBHostFamilyDefinitions.h>
-#endif
-
-/* IOUSBInterfaceInferface */
-
-/* New in OS 10.12.0. */
-#if defined (kIOUSBInterfaceInterfaceID800)
-
-#define usb_interface_t IOUSBInterfaceInterface800
-#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID800
-#define InterfaceVersion 800
-
-/* New in OS 10.10.0. */
-#elif defined (kIOUSBInterfaceInterfaceID700)
-
-#define usb_interface_t IOUSBInterfaceInterface700
-#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID700
-#define InterfaceVersion 700
-
-/* New in OS 10.9.0. */
-#elif defined (kIOUSBInterfaceInterfaceID650)
-
-#define usb_interface_t IOUSBInterfaceInterface650
-#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID650
-#define InterfaceVersion 650
-
-/* New in OS 10.8.2 but can't test deployment target to that granularity, so round up. */
-#elif defined (kIOUSBInterfaceInterfaceID550)
-
-#define usb_interface_t IOUSBInterfaceInterface550
-#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID550
-#define InterfaceVersion 550
-
-/* New in OS 10.7.3 but can't test deployment target to that granularity, so round up. */
-#elif defined (kIOUSBInterfaceInterfaceID500)
-
-#define usb_interface_t IOUSBInterfaceInterface500
-#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID500
-#define InterfaceVersion 500
-
-/* New in OS 10.5.0. */
-#elif defined (kIOUSBInterfaceInterfaceID300)
-
-#define usb_interface_t IOUSBInterfaceInterface300
-#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300
-#define InterfaceVersion 300
-
-/* New in OS 10.4.5 (or 10.4.6?) but can't test deployment target to that granularity, so round up. */
-#elif defined (kIOUSBInterfaceInterfaceID245)
-
-#define usb_interface_t IOUSBInterfaceInterface245
-#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID245
-#define InterfaceVersion 245
-
-/* New in OS 10.4.0. */
-#elif defined (kIOUSBInterfaceInterfaceID220)
-
-#define usb_interface_t IOUSBInterfaceInterface220
-#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
-#define InterfaceVersion 220
-
-#else
-
-#error "IOUSBFamily is too old. Please upgrade your SDK and/or deployment target"
-
-#endif
-
-/* IOUSBDeviceInterface */
-
-/* New in OS 10.9.0. */
-#if defined (kIOUSBDeviceInterfaceID650)
-
-#define usb_device_t IOUSBDeviceInterface650
-#define DeviceInterfaceID kIOUSBDeviceInterfaceID650
-#define DeviceVersion 650
-
-/* New in OS 10.7.3 but can't test deployment target to that granularity, so round up. */
-#elif defined (kIOUSBDeviceInterfaceID500)
-
-#define usb_device_t IOUSBDeviceInterface500
-#define DeviceInterfaceID kIOUSBDeviceInterfaceID500
-#define DeviceVersion 500
-
-/* New in OS 10.5.4 but can't test deployment target to that granularity, so round up. */
-#elif defined (kIOUSBDeviceInterfaceID320)
-
-#define usb_device_t IOUSBDeviceInterface320
-#define DeviceInterfaceID kIOUSBDeviceInterfaceID320
-#define DeviceVersion 320
-
-/* New in OS 10.5.0. */
-#elif defined (kIOUSBDeviceInterfaceID300)
-
-#define usb_device_t IOUSBDeviceInterface300
-#define DeviceInterfaceID kIOUSBDeviceInterfaceID300
-#define DeviceVersion 300
-
-/* New in OS 10.4.5 (or 10.4.6?) but can't test deployment target to that granularity, so round up. */
-#elif defined (kIOUSBDeviceInterfaceID245)
-
-#define usb_device_t IOUSBDeviceInterface245
-#define DeviceInterfaceID kIOUSBDeviceInterfaceID245
-#define DeviceVersion 245
-
-/* New in OS 10.2.3 but can't test deployment target to that granularity, so round up. */
-#elif defined (kIOUSBDeviceInterfaceID197)
-
-#define usb_device_t IOUSBDeviceInterface197
-#define DeviceInterfaceID kIOUSBDeviceInterfaceID197
-#define DeviceVersion 197
-
-#else
-
-#error "IOUSBFamily is too old. Please upgrade your SDK and/or deployment target"
-
-#endif
-
-#if !defined(kIOUSBHostInterfaceClassName)
-#define kIOUSBHostInterfaceClassName "IOUSBHostInterface"
-#endif
-
-#if !defined(kUSBHostMatchingPropertyInterfaceNumber)
-#define kUSBHostMatchingPropertyInterfaceNumber "bInterfaceNumber"
-#endif
-
-#if !defined(IO_OBJECT_NULL)
-#define IO_OBJECT_NULL ((io_object_t) 0)
-#endif
-
-/* Testing availability */
-#ifndef __has_builtin
- #define __has_builtin(x) 0 // Compatibility with non-clang compilers.
-#endif
-#if __has_builtin(__builtin_available)
- #define HAS_CAPTURE_DEVICE() __builtin_available(macOS 10.10, *)
-#else
- #define HAS_CAPTURE_DEVICE() 0
-#endif
-
-typedef IOCFPlugInInterface *io_cf_plugin_ref_t;
-typedef IONotificationPortRef io_notification_port_t;
-
-/* private structures */
-struct darwin_cached_device {
- struct list_head list;
- IOUSBDeviceDescriptor dev_descriptor;
- UInt32 location;
- UInt64 parent_session;
- UInt64 session;
- USBDeviceAddress address;
- char sys_path[21];
- usb_device_t **device;
- io_service_t service;
- int open_count;
- UInt8 first_config, active_config, port;
- int can_enumerate;
- int refcount;
- bool in_reenumerate;
- int capture_count;
-};
-
-struct darwin_device_priv {
- struct darwin_cached_device *dev;
-};
-
-struct darwin_device_handle_priv {
- bool is_open;
- CFRunLoopSourceRef cfSource;
-
- struct darwin_interface {
- usb_interface_t **interface;
- uint8_t num_endpoints;
- CFRunLoopSourceRef cfSource;
- uint64_t frames[256];
- uint8_t endpoint_addrs[USB_MAXENDPOINTS];
- } interfaces[USB_MAXINTERFACES];
-};
-
-struct darwin_transfer_priv {
- /* Isoc */
- IOUSBIsocFrame *isoc_framelist;
- int num_iso_packets;
-
- /* Control */
- IOUSBDevRequestTO req;
-
- /* Bulk */
-
- /* Completion status */
- IOReturn result;
- UInt32 size;
-};
-
-#endif
diff --git a/src/os/events_windows.c b/src/os/events_windows.c
deleted file mode 100644
index f22bebc..0000000
--- a/src/os/events_windows.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * libusb event abstraction on Microsoft Windows
- *
- * Copyright © 2020 Chris Dickens <christopher.a.dickens@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 "libusbi.h"
-#include "windows_common.h"
-
-int usbi_create_event(usbi_event_t *event)
-{
- event->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (event->hEvent == NULL) {
- usbi_err(NULL, "CreateEvent failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_OTHER;
- }
-
- return 0;
-}
-
-void usbi_destroy_event(usbi_event_t *event)
-{
- if (!CloseHandle(event->hEvent))
- usbi_warn(NULL, "CloseHandle failed: %s", windows_error_str(0));
-}
-
-void usbi_signal_event(usbi_event_t *event)
-{
- if (!SetEvent(event->hEvent))
- usbi_warn(NULL, "SetEvent failed: %s", windows_error_str(0));
-}
-
-void usbi_clear_event(usbi_event_t *event)
-{
- if (!ResetEvent(event->hEvent))
- usbi_warn(NULL, "ResetEvent failed: %s", windows_error_str(0));
-}
-
-#ifdef HAVE_OS_TIMER
-int usbi_create_timer(usbi_timer_t *timer)
-{
- timer->hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
- if (timer->hTimer == NULL) {
- usbi_warn(NULL, "CreateWaitableTimer failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_OTHER;
- }
-
- return 0;
-}
-
-void usbi_destroy_timer(usbi_timer_t *timer)
-{
- if (!CloseHandle(timer->hTimer))
- usbi_warn(NULL, "CloseHandle failed: %s", windows_error_str(0));
-}
-
-int usbi_arm_timer(usbi_timer_t *timer, const struct timespec *timeout)
-{
- struct timespec systime, remaining;
- FILETIME filetime;
- LARGE_INTEGER dueTime;
-
- /* Transfer timeouts are based on the monotonic clock and the waitable
- * timers on the system clock. This requires a conversion between the
- * two, so we calculate the remaining time relative to the monotonic
- * clock and calculate an absolute system time for the timer expiration.
- * Note that if the timeout has already passed, the remaining time will
- * be negative and thus an absolute system time in the past will be set.
- * This works just as intended because the timer becomes signalled
- * immediately. */
- usbi_get_monotonic_time(&systime);
-
- TIMESPEC_SUB(timeout, &systime, &remaining);
-
- GetSystemTimeAsFileTime(&filetime);
- dueTime.LowPart = filetime.dwLowDateTime;
- dueTime.HighPart = filetime.dwHighDateTime;
- dueTime.QuadPart += (remaining.tv_sec * 10000000LL) + (remaining.tv_nsec / 100LL);
-
- if (!SetWaitableTimer(timer->hTimer, &dueTime, 0, NULL, NULL, FALSE)) {
- usbi_warn(NULL, "SetWaitableTimer failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_OTHER;
- }
-
- return 0;
-}
-
-int usbi_disarm_timer(usbi_timer_t *timer)
-{
- LARGE_INTEGER dueTime;
-
- /* A manual-reset waitable timer will stay in the signalled state until
- * another call to SetWaitableTimer() is made. It is possible that the
- * timer has already expired by the time we come in to disarm it, so to
- * be entirely sure the timer is disarmed and not in the signalled state,
- * we will set it with an impossibly large expiration and immediately
- * cancel. */
- dueTime.QuadPart = LLONG_MAX;
- if (!SetWaitableTimer(timer->hTimer, &dueTime, 0, NULL, NULL, FALSE)) {
- usbi_warn(NULL, "SetWaitableTimer failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_OTHER;
- }
-
- if (!CancelWaitableTimer(timer->hTimer)) {
- usbi_warn(NULL, "SetWaitableTimer failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_OTHER;
- }
-
- return 0;
-}
-#endif
-
-int usbi_alloc_event_data(struct libusb_context *ctx)
-{
- struct usbi_event_source *ievent_source;
- HANDLE *handles;
- size_t i = 0;
-
- /* Event sources are only added during usbi_io_init(). We should not
- * be running this function again if the event data has already been
- * allocated. */
- if (ctx->event_data) {
- usbi_warn(ctx, "program assertion failed - event data already allocated");
- return LIBUSB_ERROR_OTHER;
- }
-
- ctx->event_data_cnt = 0;
- for_each_event_source(ctx, ievent_source)
- ctx->event_data_cnt++;
-
- /* We only expect up to two HANDLEs to wait on, one for the internal
- * signalling event and the other for the timer. */
- if (ctx->event_data_cnt != 1 && ctx->event_data_cnt != 2) {
- usbi_err(ctx, "program assertion failed - expected exactly 1 or 2 HANDLEs");
- return LIBUSB_ERROR_OTHER;
- }
-
- handles = calloc(ctx->event_data_cnt, sizeof(HANDLE));
- if (!handles)
- return LIBUSB_ERROR_NO_MEM;
-
- for_each_event_source(ctx, ievent_source) {
- handles[i] = ievent_source->data.os_handle;
- i++;
- }
-
- ctx->event_data = handles;
- return 0;
-}
-
-int usbi_wait_for_events(struct libusb_context *ctx,
- struct usbi_reported_events *reported_events, int timeout_ms)
-{
- HANDLE *handles = ctx->event_data;
- DWORD num_handles = (DWORD)ctx->event_data_cnt;
- DWORD result;
-
- usbi_dbg(ctx, "WaitForMultipleObjects() for %lu HANDLEs with timeout in %dms", ULONG_CAST(num_handles), timeout_ms);
- result = WaitForMultipleObjects(num_handles, handles, FALSE, (DWORD)timeout_ms);
- usbi_dbg(ctx, "WaitForMultipleObjects() returned %lu", ULONG_CAST(result));
- if (result == WAIT_TIMEOUT) {
- if (usbi_using_timer(ctx))
- goto done;
- return LIBUSB_ERROR_TIMEOUT;
- } else if (result == WAIT_FAILED) {
- usbi_err(ctx, "WaitForMultipleObjects() failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_IO;
- }
-
- result -= WAIT_OBJECT_0;
-
- /* handles[0] is always the internal signalling event */
- if (result == 0)
- reported_events->event_triggered = 1;
- else
- reported_events->event_triggered = 0;
-
-#ifdef HAVE_OS_TIMER
- /* on timer configurations, handles[1] is the timer */
- if (usbi_using_timer(ctx)) {
- /* The WaitForMultipleObjects() function reports the index of
- * the first object that became signalled. If the internal
- * signalling event was reported, we need to also check and
- * report whether the timer is in the signalled state. */
- if (result == 1 || WaitForSingleObject(handles[1], 0) == WAIT_OBJECT_0)
- reported_events->timer_triggered = 1;
- else
- reported_events->timer_triggered = 0;
- } else {
- reported_events->timer_triggered = 0;
- }
-#endif
-
-done:
- /* no events are ever reported to the backend */
- reported_events->num_ready = 0;
- return LIBUSB_SUCCESS;
-}
diff --git a/src/os/events_windows.h b/src/os/events_windows.h
deleted file mode 100644
index 0c5e0b0..0000000
--- a/src/os/events_windows.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * libusb event abstraction on Microsoft Windows
- *
- * Copyright © 2020 Chris Dickens <christopher.a.dickens@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_EVENTS_WINDOWS_H
-#define LIBUSB_EVENTS_WINDOWS_H
-
-typedef HANDLE usbi_os_handle_t;
-#define USBI_OS_HANDLE_FORMAT_STRING "HANDLE %p"
-
-typedef struct usbi_event {
- HANDLE hEvent;
-} usbi_event_t;
-#define USBI_EVENT_OS_HANDLE(e) ((e)->hEvent)
-#define USBI_EVENT_POLL_EVENTS 0
-#define USBI_INVALID_EVENT { INVALID_HANDLE_VALUE }
-
-#define HAVE_OS_TIMER 1
-typedef struct usbi_timer {
- HANDLE hTimer;
-} usbi_timer_t;
-#define USBI_TIMER_OS_HANDLE(t) ((t)->hTimer)
-#define USBI_TIMER_POLL_EVENTS 0
-
-static inline int usbi_timer_valid(usbi_timer_t *timer)
-{
- return timer->hTimer != NULL;
-}
-
-#endif
diff --git a/src/os/haiku_pollfs.cpp b/src/os/haiku_pollfs.cpp
deleted file mode 100644
index b85edf7..0000000
--- a/src/os/haiku_pollfs.cpp
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright 2007-2008, Haiku Inc. All rights reserved.
- * Distributed under the terms of the MIT License.
- *
- * Authors:
- * Michael Lotz <mmlr@mlotz.ch>
- */
-
-#include "haiku_usb.h"
-#include <cstdio>
-#include <Directory.h>
-#include <Entry.h>
-#include <Looper.h>
-#include <Messenger.h>
-#include <Node.h>
-#include <NodeMonitor.h>
-#include <Path.h>
-#include <cstring>
-
-class WatchedEntry {
-public:
- WatchedEntry(BMessenger *, entry_ref *);
- ~WatchedEntry();
- bool EntryCreated(entry_ref *ref);
- bool EntryRemoved(ino_t node);
- bool InitCheck();
-
-private:
- BMessenger* fMessenger;
- node_ref fNode;
- bool fIsDirectory;
- USBDevice* fDevice;
- WatchedEntry* fEntries;
- WatchedEntry* fLink;
- bool fInitCheck;
-};
-
-
-class RosterLooper : public BLooper {
-public:
- RosterLooper(USBRoster *);
- void Stop();
- virtual void MessageReceived(BMessage *);
- bool InitCheck();
-
-private:
- USBRoster* fRoster;
- WatchedEntry* fRoot;
- BMessenger* fMessenger;
- bool fInitCheck;
-};
-
-
-WatchedEntry::WatchedEntry(BMessenger *messenger, entry_ref *ref)
- : fMessenger(messenger),
- fIsDirectory(false),
- fDevice(NULL),
- fEntries(NULL),
- fLink(NULL),
- fInitCheck(false)
-{
- BEntry entry(ref);
- entry.GetNodeRef(&fNode);
-
- BDirectory directory;
- if (entry.IsDirectory() && directory.SetTo(ref) >= B_OK) {
- fIsDirectory = true;
-
- while (directory.GetNextEntry(&entry) >= B_OK) {
- if (entry.GetRef(ref) < B_OK)
- continue;
-
- WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref);
- if (child == NULL)
- continue;
- if (child->InitCheck() == false) {
- delete child;
- continue;
- }
-
- child->fLink = fEntries;
- fEntries = child;
- }
-
- watch_node(&fNode, B_WATCH_DIRECTORY, *fMessenger);
- }
- else {
- if (strncmp(ref->name, "raw", 3) == 0)
- return;
-
- BPath path, parent_path;
- entry.GetPath(&path);
- fDevice = new(std::nothrow) USBDevice(path.Path());
- if (fDevice != NULL && fDevice->InitCheck() == true) {
- // Add this new device to each active context's device list
- struct libusb_context *ctx;
- unsigned long session_id = (unsigned long)&fDevice;
-
- usbi_mutex_lock(&active_contexts_lock);
- for_each_context(ctx) {
- struct libusb_device *dev = usbi_get_device_by_session_id(ctx, session_id);
- if (dev) {
- usbi_dbg(NULL, "using previously allocated device with location %lu", session_id);
- libusb_unref_device(dev);
- continue;
- }
- usbi_dbg(NULL, "allocating new device with location %lu", session_id);
- dev = usbi_alloc_device(ctx, session_id);
- if (!dev) {
- usbi_dbg(NULL, "device allocation failed");
- continue;
- }
- *((USBDevice **)usbi_get_device_priv(dev)) = fDevice;
-
- // Calculate pseudo-device-address
- int addr, tmp;
- if (strcmp(path.Leaf(), "hub") == 0)
- tmp = 100; //Random Number
- else
- sscanf(path.Leaf(), "%d", &tmp);
- addr = tmp + 1;
- path.GetParent(&parent_path);
- while (strcmp(parent_path.Leaf(), "usb") != 0) {
- sscanf(parent_path.Leaf(), "%d", &tmp);
- addr += tmp + 1;
- parent_path.GetParent(&parent_path);
- }
- sscanf(path.Path(), "/dev/bus/usb/%hhu", &dev->bus_number);
- dev->device_address = addr - (dev->bus_number + 1);
-
- static_assert(sizeof(dev->device_descriptor) == sizeof(usb_device_descriptor),
- "mismatch between libusb and OS device descriptor sizes");
- memcpy(&dev->device_descriptor, fDevice->Descriptor(), LIBUSB_DT_DEVICE_SIZE);
- usbi_localize_device_descriptor(&dev->device_descriptor);
-
- if (usbi_sanitize_device(dev) < 0) {
- usbi_dbg(NULL, "device sanitization failed");
- libusb_unref_device(dev);
- continue;
- }
- usbi_connect_device(dev);
- }
- usbi_mutex_unlock(&active_contexts_lock);
- }
- else if (fDevice) {
- delete fDevice;
- fDevice = NULL;
- return;
- }
- }
- fInitCheck = true;
-}
-
-
-WatchedEntry::~WatchedEntry()
-{
- if (fIsDirectory) {
- watch_node(&fNode, B_STOP_WATCHING, *fMessenger);
-
- WatchedEntry *child = fEntries;
- while (child) {
- WatchedEntry *next = child->fLink;
- delete child;
- child = next;
- }
- }
-
- if (fDevice) {
- // Remove this device from each active context's device list
- struct libusb_context *ctx;
- struct libusb_device *dev;
- unsigned long session_id = (unsigned long)&fDevice;
-
- usbi_mutex_lock(&active_contexts_lock);
- for_each_context(ctx) {
- dev = usbi_get_device_by_session_id(ctx, session_id);
- if (dev != NULL) {
- usbi_disconnect_device(dev);
- libusb_unref_device(dev);
- } else {
- usbi_dbg(ctx, "device with location %lu not found", session_id);
- }
- }
- usbi_mutex_static_unlock(&active_contexts_lock);
- delete fDevice;
- }
-}
-
-
-bool
-WatchedEntry::EntryCreated(entry_ref *ref)
-{
- if (!fIsDirectory)
- return false;
-
- if (ref->directory != fNode.node) {
- WatchedEntry *child = fEntries;
- while (child) {
- if (child->EntryCreated(ref))
- return true;
- child = child->fLink;
- }
- return false;
- }
-
- WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref);
- if (child == NULL)
- return false;
- child->fLink = fEntries;
- fEntries = child;
- return true;
-}
-
-
-bool
-WatchedEntry::EntryRemoved(ino_t node)
-{
- if (!fIsDirectory)
- return false;
-
- WatchedEntry *child = fEntries;
- WatchedEntry *lastChild = NULL;
- while (child) {
- if (child->fNode.node == node) {
- if (lastChild)
- lastChild->fLink = child->fLink;
- else
- fEntries = child->fLink;
- delete child;
- return true;
- }
-
- if (child->EntryRemoved(node))
- return true;
-
- lastChild = child;
- child = child->fLink;
- }
- return false;
-}
-
-
-bool
-WatchedEntry::InitCheck()
-{
- return fInitCheck;
-}
-
-
-RosterLooper::RosterLooper(USBRoster *roster)
- : BLooper("LibusbRoster Looper"),
- fRoster(roster),
- fRoot(NULL),
- fMessenger(NULL),
- fInitCheck(false)
-{
- BEntry entry("/dev/bus/usb");
- if (!entry.Exists()) {
- usbi_err(NULL, "usb_raw not published");
- return;
- }
-
- Run();
- fMessenger = new(std::nothrow) BMessenger(this);
- if (fMessenger == NULL) {
- usbi_err(NULL, "error creating BMessenger object");
- return;
- }
-
- if (Lock()) {
- entry_ref ref;
- entry.GetRef(&ref);
- fRoot = new(std::nothrow) WatchedEntry(fMessenger, &ref);
- Unlock();
- if (fRoot == NULL)
- return;
- if (fRoot->InitCheck() == false) {
- delete fRoot;
- fRoot = NULL;
- return;
- }
- }
- fInitCheck = true;
-}
-
-
-void
-RosterLooper::Stop()
-{
- Lock();
- delete fRoot;
- delete fMessenger;
- Quit();
-}
-
-
-void
-RosterLooper::MessageReceived(BMessage *message)
-{
- int32 opcode;
- if (message->FindInt32("opcode", &opcode) < B_OK)
- return;
-
- switch (opcode) {
- case B_ENTRY_CREATED:
- {
- dev_t device;
- ino_t directory;
- const char *name;
- if (message->FindInt32("device", &device) < B_OK ||
- message->FindInt64("directory", &directory) < B_OK ||
- message->FindString("name", &name) < B_OK)
- break;
-
- entry_ref ref(device, directory, name);
- fRoot->EntryCreated(&ref);
- break;
- }
- case B_ENTRY_REMOVED:
- {
- ino_t node;
- if (message->FindInt64("node", &node) < B_OK)
- break;
- fRoot->EntryRemoved(node);
- break;
- }
- }
-}
-
-
-bool
-RosterLooper::InitCheck()
-{
- return fInitCheck;
-}
-
-
-USBRoster::USBRoster()
- : fLooper(NULL)
-{
-}
-
-
-USBRoster::~USBRoster()
-{
- Stop();
-}
-
-
-int
-USBRoster::Start()
-{
- if (fLooper == NULL) {
- fLooper = new(std::nothrow) RosterLooper(this);
- if (fLooper == NULL || ((RosterLooper *)fLooper)->InitCheck() == false) {
- if (fLooper)
- fLooper = NULL;
- return LIBUSB_ERROR_OTHER;
- }
- }
- return LIBUSB_SUCCESS;
-}
-
-
-void
-USBRoster::Stop()
-{
- if (fLooper) {
- ((RosterLooper *)fLooper)->Stop();
- fLooper = NULL;
- }
-}
diff --git a/src/os/haiku_usb.h b/src/os/haiku_usb.h
deleted file mode 100644
index 2dd5177..0000000
--- a/src/os/haiku_usb.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Haiku Backend for libusb
- * Copyright © 2014 Akshay Jaggi <akshay1994.leo@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 <List.h>
-#include <Locker.h>
-#include <Autolock.h>
-#include <USBKit.h>
-#include <map>
-#include "libusbi.h"
-#include "haiku_usb_raw.h"
-
-using namespace std;
-
-class USBDevice;
-class USBDeviceHandle;
-class USBTransfer;
-
-class USBDevice {
-public:
- USBDevice(const char *);
- virtual ~USBDevice();
- const char* Location() const;
- uint8 CountConfigurations() const;
- const usb_device_descriptor* Descriptor() const;
- const usb_configuration_descriptor* ConfigurationDescriptor(uint8) const;
- const usb_configuration_descriptor* ActiveConfiguration() const;
- uint8 EndpointToIndex(uint8) const;
- uint8 EndpointToInterface(uint8) const;
- int ClaimInterface(uint8);
- int ReleaseInterface(uint8);
- int CheckInterfacesFree(uint8);
- void SetActiveConfiguration(uint8);
- uint8 ActiveConfigurationIndex() const;
- bool InitCheck();
-private:
- int Initialise();
- unsigned int fClaimedInterfaces; // Max Interfaces can be 32. Using a bitmask
- usb_device_descriptor fDeviceDescriptor;
- unsigned char** fConfigurationDescriptors;
- uint8 fActiveConfiguration;
- char* fPath;
- map<uint8,uint8> fConfigToIndex;
- map<uint8,uint8>* fEndpointToIndex;
- map<uint8,uint8>* fEndpointToInterface;
- bool fInitCheck;
-};
-
-class USBDeviceHandle {
-public:
- USBDeviceHandle(USBDevice *dev);
- virtual ~USBDeviceHandle();
- int ClaimInterface(uint8);
- int ReleaseInterface(uint8);
- int SetConfiguration(uint8);
- int SetAltSetting(uint8, uint8);
- int ClearHalt(uint8);
- status_t SubmitTransfer(struct usbi_transfer *);
- status_t CancelTransfer(USBTransfer *);
- bool InitCheck();
-private:
- int fRawFD;
- static status_t TransfersThread(void *);
- void TransfersWorker();
- USBDevice* fUSBDevice;
- unsigned int fClaimedInterfaces;
- BList fTransfers;
- BLocker fTransfersLock;
- sem_id fTransfersSem;
- thread_id fTransfersThread;
- bool fInitCheck;
-};
-
-class USBTransfer {
-public:
- USBTransfer(struct usbi_transfer *, USBDevice *);
- virtual ~USBTransfer();
- void Do(int);
- struct usbi_transfer* UsbiTransfer();
- void SetCancelled();
- bool IsCancelled();
-private:
- struct usbi_transfer* fUsbiTransfer;
- struct libusb_transfer* fLibusbTransfer;
- USBDevice* fUSBDevice;
- BLocker fStatusLock;
- bool fCancelled;
-};
-
-class USBRoster {
-public:
- USBRoster();
- virtual ~USBRoster();
- int Start();
- void Stop();
-private:
- void* fLooper;
-};
diff --git a/src/os/haiku_usb_backend.cpp b/src/os/haiku_usb_backend.cpp
deleted file mode 100644
index 2fcefdd..0000000
--- a/src/os/haiku_usb_backend.cpp
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- * Haiku Backend for libusb
- * Copyright © 2014 Akshay Jaggi <akshay1994.leo@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 <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <new>
-#include <vector>
-
-#include "haiku_usb.h"
-
-static int _errno_to_libusb(int status)
-{
- return status;
-}
-
-USBTransfer::USBTransfer(struct usbi_transfer *itransfer, USBDevice *device)
-{
- fUsbiTransfer = itransfer;
- fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- fUSBDevice = device;
- fCancelled = false;
-}
-
-USBTransfer::~USBTransfer()
-{
-}
-
-struct usbi_transfer *
-USBTransfer::UsbiTransfer()
-{
- return fUsbiTransfer;
-}
-
-void
-USBTransfer::SetCancelled()
-{
- fCancelled = true;
-}
-
-bool
-USBTransfer::IsCancelled()
-{
- return fCancelled;
-}
-
-void
-USBTransfer::Do(int fRawFD)
-{
- switch (fLibusbTransfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- {
- struct libusb_control_setup *setup = (struct libusb_control_setup *)fLibusbTransfer->buffer;
- usb_raw_command command;
- command.control.request_type = setup->bmRequestType;
- command.control.request = setup->bRequest;
- command.control.value = setup->wValue;
- command.control.index = setup->wIndex;
- command.control.length = setup->wLength;
- command.control.data = fLibusbTransfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
- if (fCancelled)
- break;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) ||
- command.control.status != B_USB_RAW_STATUS_SUCCESS) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed control transfer");
- break;
- }
- fUsbiTransfer->transferred = command.control.length;
- }
- break;
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- {
- usb_raw_command command;
- command.transfer.interface = fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint);
- command.transfer.endpoint = fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint);
- command.transfer.data = fLibusbTransfer->buffer;
- command.transfer.length = fLibusbTransfer->length;
- if (fCancelled)
- break;
- if (fLibusbTransfer->type == LIBUSB_TRANSFER_TYPE_BULK) {
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_BULK_TRANSFER, &command, sizeof(command)) ||
- command.transfer.status != B_USB_RAW_STATUS_SUCCESS) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed bulk transfer");
- break;
- }
- }
- else {
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_INTERRUPT_TRANSFER, &command, sizeof(command)) ||
- command.transfer.status != B_USB_RAW_STATUS_SUCCESS) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed interrupt transfer");
- break;
- }
- }
- fUsbiTransfer->transferred = command.transfer.length;
- }
- break;
- // IsochronousTransfers not tested
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- {
- usb_raw_command command;
- command.isochronous.interface = fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint);
- command.isochronous.endpoint = fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint);
- command.isochronous.data = fLibusbTransfer->buffer;
- command.isochronous.length = fLibusbTransfer->length;
- command.isochronous.packet_count = fLibusbTransfer->num_iso_packets;
- int i;
- usb_iso_packet_descriptor *packetDescriptors = new usb_iso_packet_descriptor[fLibusbTransfer->num_iso_packets];
- for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) {
- if ((fLibusbTransfer->iso_packet_desc[i]).length > (unsigned int)INT16_MAX) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer");
- break;
- }
- packetDescriptors[i].request_length = (int16)(fLibusbTransfer->iso_packet_desc[i]).length;
- }
- if (i < fLibusbTransfer->num_iso_packets)
- break; // TODO Handle this error
- command.isochronous.packet_descriptors = packetDescriptors;
- if (fCancelled)
- break;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER, &command, sizeof(command)) ||
- command.isochronous.status != B_USB_RAW_STATUS_SUCCESS) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer");
- break;
- }
- for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) {
- (fLibusbTransfer->iso_packet_desc[i]).actual_length = packetDescriptors[i].actual_length;
- switch (packetDescriptors[i].status) {
- case B_OK:
- (fLibusbTransfer->iso_packet_desc[i]).status = LIBUSB_TRANSFER_COMPLETED;
- break;
- default:
- (fLibusbTransfer->iso_packet_desc[i]).status = LIBUSB_TRANSFER_ERROR;
- break;
- }
- }
- delete[] packetDescriptors;
- // Do we put the length of transfer here, for isochronous transfers?
- fUsbiTransfer->transferred = command.transfer.length;
- }
- break;
- default:
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "Unknown type of transfer");
- }
-}
-
-bool
-USBDeviceHandle::InitCheck()
-{
- return fInitCheck;
-}
-
-status_t
-USBDeviceHandle::TransfersThread(void *self)
-{
- USBDeviceHandle *handle = (USBDeviceHandle *)self;
- handle->TransfersWorker();
- return B_OK;
-}
-
-void
-USBDeviceHandle::TransfersWorker()
-{
- while (true) {
- status_t status = acquire_sem(fTransfersSem);
- if (status == B_BAD_SEM_ID)
- break;
- if (status == B_INTERRUPTED)
- continue;
- fTransfersLock.Lock();
- USBTransfer *fPendingTransfer = (USBTransfer *) fTransfers.RemoveItem((int32)0);
- fTransfersLock.Unlock();
- fPendingTransfer->Do(fRawFD);
- usbi_signal_transfer_completion(fPendingTransfer->UsbiTransfer());
- }
-}
-
-status_t
-USBDeviceHandle::SubmitTransfer(struct usbi_transfer *itransfer)
-{
- USBTransfer *transfer = new USBTransfer(itransfer, fUSBDevice);
- *((USBTransfer **)usbi_get_transfer_priv(itransfer)) = transfer;
- BAutolock locker(fTransfersLock);
- fTransfers.AddItem(transfer);
- release_sem(fTransfersSem);
- return LIBUSB_SUCCESS;
-}
-
-status_t
-USBDeviceHandle::CancelTransfer(USBTransfer *transfer)
-{
- transfer->SetCancelled();
- fTransfersLock.Lock();
- bool removed = fTransfers.RemoveItem(transfer);
- fTransfersLock.Unlock();
- if (removed)
- usbi_signal_transfer_completion(transfer->UsbiTransfer());
- return LIBUSB_SUCCESS;
-}
-
-USBDeviceHandle::USBDeviceHandle(USBDevice *dev)
- :
- fUSBDevice(dev),
- fClaimedInterfaces(0),
- fTransfersThread(-1),
- fInitCheck(false)
-{
- fRawFD = open(dev->Location(), O_RDWR | O_CLOEXEC);
- if (fRawFD < 0) {
- usbi_err(NULL,"failed to open device");
- return;
- }
- fTransfersSem = create_sem(0, "Transfers Queue Sem");
- fTransfersThread = spawn_thread(TransfersThread, "Transfer Worker", B_NORMAL_PRIORITY, this);
- resume_thread(fTransfersThread);
- fInitCheck = true;
-}
-
-USBDeviceHandle::~USBDeviceHandle()
-{
- if (fRawFD > 0)
- close(fRawFD);
- for (int i = 0; i < 32; i++) {
- if (fClaimedInterfaces & (1U << i))
- ReleaseInterface(i);
- }
- delete_sem(fTransfersSem);
- if (fTransfersThread > 0)
- wait_for_thread(fTransfersThread, NULL);
-}
-
-int
-USBDeviceHandle::ClaimInterface(uint8 inumber)
-{
- int status = fUSBDevice->ClaimInterface(inumber);
- if (status == LIBUSB_SUCCESS)
- fClaimedInterfaces |= (1U << inumber);
- return status;
-}
-
-int
-USBDeviceHandle::ReleaseInterface(uint8 inumber)
-{
- fUSBDevice->ReleaseInterface(inumber);
- fClaimedInterfaces &= ~(1U << inumber);
- return LIBUSB_SUCCESS;
-}
-
-int
-USBDeviceHandle::SetConfiguration(uint8 config)
-{
- int config_index = fUSBDevice->CheckInterfacesFree(config);
- if (config_index == LIBUSB_ERROR_BUSY || config_index == LIBUSB_ERROR_NOT_FOUND)
- return config_index;
- usb_raw_command command;
- command.config.config_index = config_index;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_CONFIGURATION, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- return _errno_to_libusb(command.config.status);
- }
- fUSBDevice->SetActiveConfiguration((uint8)config_index);
- return LIBUSB_SUCCESS;
-}
-
-int
-USBDeviceHandle::SetAltSetting(uint8 inumber, uint8 alt)
-{
- usb_raw_command command;
- command.alternate.config_index = fUSBDevice->ActiveConfigurationIndex();
- command.alternate.interface_index = inumber;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX, &command, sizeof(command)) ||
- command.alternate.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "Error retrieving active alternate interface");
- return _errno_to_libusb(command.alternate.status);
- }
- if (command.alternate.alternate_info == (uint32)alt) {
- usbi_dbg(NULL, "Setting alternate interface successful");
- return LIBUSB_SUCCESS;
- }
- command.alternate.alternate_info = alt;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_ALT_INTERFACE, &command, sizeof(command)) ||
- command.alternate.status != B_USB_RAW_STATUS_SUCCESS) { //IF IOCTL FAILS DEVICE DISCONNECTED PROBABLY
- usbi_err(NULL, "Error setting alternate interface");
- return _errno_to_libusb(command.alternate.status);
- }
- usbi_dbg(NULL, "Setting alternate interface successful");
- return LIBUSB_SUCCESS;
-}
-
-int
-USBDeviceHandle::ClearHalt(uint8 endpoint)
-{
- usb_raw_command command;
- command.control.request_type = USB_REQTYPE_ENDPOINT_OUT;
- command.control.request = USB_REQUEST_CLEAR_FEATURE;
- command.control.value = USB_FEATURE_ENDPOINT_HALT;
- command.control.index = endpoint;
- command.control.length = 0;
-
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) ||
- command.control.status != B_USB_RAW_STATUS_SUCCESS) {
- return _errno_to_libusb(command.control.status);
- }
- return LIBUSB_SUCCESS;
-}
-
-
-USBDevice::USBDevice(const char *path)
- :
- fClaimedInterfaces(0),
- fConfigurationDescriptors(NULL),
- fActiveConfiguration(0), //0?
- fPath(NULL),
- fEndpointToIndex(NULL),
- fEndpointToInterface(NULL),
- fInitCheck(false)
-{
- fPath=strdup(path);
- Initialise();
-}
-
-USBDevice::~USBDevice()
-{
- free(fPath);
- if (fConfigurationDescriptors) {
- for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
- if (fConfigurationDescriptors[i])
- delete fConfigurationDescriptors[i];
- }
- delete[] fConfigurationDescriptors;
- }
- if (fEndpointToIndex)
- delete[] fEndpointToIndex;
- if (fEndpointToInterface)
- delete[] fEndpointToInterface;
-}
-
-bool
-USBDevice::InitCheck()
-{
- return fInitCheck;
-}
-
-const char *
-USBDevice::Location() const
-{
- return fPath;
-}
-
-uint8
-USBDevice::CountConfigurations() const
-{
- return fDeviceDescriptor.num_configurations;
-}
-
-const usb_device_descriptor *
-USBDevice::Descriptor() const
-{
- return &fDeviceDescriptor;
-}
-
-const usb_configuration_descriptor *
-USBDevice::ConfigurationDescriptor(uint8 index) const
-{
- if (index > CountConfigurations())
- return NULL;
- return (usb_configuration_descriptor *) fConfigurationDescriptors[index];
-}
-
-const usb_configuration_descriptor *
-USBDevice::ActiveConfiguration() const
-{
- return (usb_configuration_descriptor *) fConfigurationDescriptors[fActiveConfiguration];
-}
-
-uint8
-USBDevice::ActiveConfigurationIndex() const
-{
- return fActiveConfiguration;
-}
-
-int USBDevice::ClaimInterface(uint8 interface)
-{
- if (interface > ActiveConfiguration()->number_interfaces)
- return LIBUSB_ERROR_NOT_FOUND;
- if (fClaimedInterfaces & (1U << interface))
- return LIBUSB_ERROR_BUSY;
- fClaimedInterfaces |= (1U << interface);
- return LIBUSB_SUCCESS;
-}
-
-int USBDevice::ReleaseInterface(uint8 interface)
-{
- fClaimedInterfaces &= ~(1U << interface);
- return LIBUSB_SUCCESS;
-}
-
-int
-USBDevice::CheckInterfacesFree(uint8 config)
-{
- if (fConfigToIndex.count(config) == 0)
- return LIBUSB_ERROR_NOT_FOUND;
- if (fClaimedInterfaces == 0)
- return fConfigToIndex[config];
- return LIBUSB_ERROR_BUSY;
-}
-
-void
-USBDevice::SetActiveConfiguration(uint8 config_index)
-{
- fActiveConfiguration = config_index;
-}
-
-uint8
-USBDevice::EndpointToIndex(uint8 address) const
-{
- return fEndpointToIndex[fActiveConfiguration][address];
-}
-
-uint8
-USBDevice::EndpointToInterface(uint8 address) const
-{
- return fEndpointToInterface[fActiveConfiguration][address];
-}
-
-int
-USBDevice::Initialise() //Do we need more error checking, etc? How to report?
-{
- int fRawFD = open(fPath, O_RDWR | O_CLOEXEC);
- if (fRawFD < 0)
- return B_ERROR;
- usb_raw_command command;
- command.device.descriptor = &fDeviceDescriptor;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR, &command, sizeof(command)) ||
- command.device.status != B_USB_RAW_STATUS_SUCCESS) {
- close(fRawFD);
- return B_ERROR;
- }
-
- fConfigurationDescriptors = new(std::nothrow) unsigned char *[fDeviceDescriptor.num_configurations];
- fEndpointToIndex = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
- fEndpointToInterface = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
- for (uint8 i = 0; i < fDeviceDescriptor.num_configurations; i++) {
- usb_configuration_descriptor tmp_config;
- command.config.descriptor = &tmp_config;
- command.config.config_index = i;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving configuration descriptor");
- close(fRawFD);
- return B_ERROR;
- }
- fConfigToIndex[tmp_config.configuration_value] = i;
- fConfigurationDescriptors[i] = new(std::nothrow) unsigned char[tmp_config.total_length];
-
- command.config_etc.descriptor = (usb_configuration_descriptor*)fConfigurationDescriptors[i];
- command.config_etc.length = tmp_config.total_length;
- command.config_etc.config_index = i;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC, &command, sizeof(command)) ||
- command.config_etc.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving full configuration descriptor");
- close(fRawFD);
- return B_ERROR;
- }
-
- for (uint8 j = 0; j < tmp_config.number_interfaces; j++) {
- command.alternate.config_index = i;
- command.alternate.interface_index = j;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving number of alternate interfaces");
- close(fRawFD);
- return B_ERROR;
- }
- uint8 num_alternate = (uint8)command.alternate.alternate_info;
- for (uint8 k = 0; k < num_alternate; k++) {
- usb_interface_descriptor tmp_interface;
- command.interface_etc.config_index = i;
- command.interface_etc.interface_index = j;
- command.interface_etc.alternate_index = k;
- command.interface_etc.descriptor = &tmp_interface;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving interface descriptor");
- close(fRawFD);
- return B_ERROR;
- }
- for (uint8 l = 0; l < tmp_interface.num_endpoints; l++) {
- usb_endpoint_descriptor tmp_endpoint;
- command.endpoint_etc.config_index = i;
- command.endpoint_etc.interface_index = j;
- command.endpoint_etc.alternate_index = k;
- command.endpoint_etc.endpoint_index = l;
- command.endpoint_etc.descriptor = &tmp_endpoint;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving endpoint descriptor");
- close(fRawFD);
- return B_ERROR;
- }
- fEndpointToIndex[i][tmp_endpoint.endpoint_address] = l;
- fEndpointToInterface[i][tmp_endpoint.endpoint_address] = j;
- }
- }
- }
- }
- close(fRawFD);
- fInitCheck = true;
- return B_OK;
-}
diff --git a/src/os/haiku_usb_raw.cpp b/src/os/haiku_usb_raw.cpp
deleted file mode 100644
index bce706c..0000000
--- a/src/os/haiku_usb_raw.cpp
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Haiku Backend for libusb
- * Copyright © 2014 Akshay Jaggi <akshay1994.leo@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 <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <new>
-#include <vector>
-
-#include "haiku_usb.h"
-
-USBRoster gUsbRoster;
-int32 gInitCount = 0;
-
-static int haiku_get_config_descriptor(struct libusb_device *, uint8_t,
- void *, size_t);
-
-static int
-haiku_init(struct libusb_context *ctx)
-{
- UNUSED(ctx);
- if (atomic_add(&gInitCount, 1) == 0)
- return gUsbRoster.Start();
- return LIBUSB_SUCCESS;
-}
-
-static void
-haiku_exit(struct libusb_context *ctx)
-{
- UNUSED(ctx);
- if (atomic_add(&gInitCount, -1) == 1)
- gUsbRoster.Stop();
-}
-
-static int
-haiku_open(struct libusb_device_handle *dev_handle)
-{
- USBDevice *dev = *((USBDevice **)usbi_get_device_priv(dev_handle->dev));
- USBDeviceHandle *handle = new(std::nothrow) USBDeviceHandle(dev);
- if (handle == NULL)
- return LIBUSB_ERROR_NO_MEM;
- if (handle->InitCheck() == false) {
- delete handle;
- return LIBUSB_ERROR_NO_DEVICE;
- }
- *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle)) = handle;
- return LIBUSB_SUCCESS;
-}
-
-static void
-haiku_close(struct libusb_device_handle *dev_handle)
-{
- USBDeviceHandle **pHandle = (USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle);
- USBDeviceHandle *handle = *pHandle;
- if (handle == NULL)
- return;
- delete handle;
- *pHandle = NULL;
-}
-
-static int
-haiku_get_active_config_descriptor(struct libusb_device *device, void *buffer, size_t len)
-{
- USBDevice *dev = *((USBDevice **)usbi_get_device_priv(device));
- return haiku_get_config_descriptor(device, dev->ActiveConfigurationIndex(), buffer, len);
-}
-
-static int
-haiku_get_config_descriptor(struct libusb_device *device, uint8_t config_index, void *buffer, size_t len)
-{
- USBDevice *dev = *((USBDevice **)usbi_get_device_priv(device));
- const usb_configuration_descriptor *config = dev->ConfigurationDescriptor(config_index);
- if (config == NULL) {
- usbi_err(DEVICE_CTX(device), "failed getting configuration descriptor");
- return LIBUSB_ERROR_IO;
- }
- if (len > config->total_length) {
- len = config->total_length;
- }
- memcpy(buffer, config, len);
- return len;
-}
-
-static int
-haiku_set_configuration(struct libusb_device_handle *dev_handle, int config)
-{
- USBDeviceHandle *handle= *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
- if (config <= 0)
- return LIBUSB_ERROR_NOT_SUPPORTED; // cannot unconfigure
- return handle->SetConfiguration((uint8)config);
-}
-
-static int
-haiku_claim_interface(struct libusb_device_handle *dev_handle, uint8_t interface_number)
-{
- USBDeviceHandle *handle = *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
- return handle->ClaimInterface(interface_number);
-}
-
-static int
-haiku_set_altsetting(struct libusb_device_handle *dev_handle, uint8_t interface_number, uint8_t altsetting)
-{
- USBDeviceHandle *handle = *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
- return handle->SetAltSetting(interface_number, altsetting);
-}
-
-static int
-haiku_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
-{
- USBDeviceHandle *handle = *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
- return handle->ClearHalt(endpoint);
-}
-
-static int
-haiku_release_interface(struct libusb_device_handle *dev_handle, uint8_t interface_number)
-{
- USBDeviceHandle *handle = *((USBDeviceHandle **)usbi_get_device_handle_priv(dev_handle));
- haiku_set_altsetting(dev_handle, interface_number, 0);
- return handle->ReleaseInterface(interface_number);
-}
-
-static int
-haiku_submit_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)usbi_get_device_handle_priv(fLibusbTransfer->dev_handle));
- return fDeviceHandle->SubmitTransfer(itransfer);
-}
-
-static int
-haiku_cancel_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)usbi_get_device_handle_priv(fLibusbTransfer->dev_handle));
- return fDeviceHandle->CancelTransfer(*((USBTransfer **)usbi_get_transfer_priv(itransfer)));
-}
-
-static int
-haiku_handle_transfer_completion(struct usbi_transfer *itransfer)
-{
- USBTransfer **pTransfer = (USBTransfer **)usbi_get_transfer_priv(itransfer);
- USBTransfer *transfer = *pTransfer;
-
- usbi_mutex_lock(&itransfer->lock);
- if (transfer->IsCancelled()) {
- delete transfer;
- *pTransfer = NULL;
- usbi_mutex_unlock(&itransfer->lock);
- if (itransfer->transferred < 0)
- itransfer->transferred = 0;
- return usbi_handle_transfer_cancellation(itransfer);
- }
- libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED;
- if (itransfer->transferred < 0) {
- usbi_err(ITRANSFER_CTX(itransfer), "error in transfer");
- status = LIBUSB_TRANSFER_ERROR;
- itransfer->transferred = 0;
- }
- delete transfer;
- *pTransfer = NULL;
- usbi_mutex_unlock(&itransfer->lock);
- return usbi_handle_transfer_completion(itransfer, status);
-}
-
-const struct usbi_os_backend usbi_backend = {
- /*.name =*/ "Haiku usbfs",
- /*.caps =*/ 0,
- /*.init =*/ haiku_init,
- /*.exit =*/ haiku_exit,
- /*.set_option =*/ NULL,
- /*.get_device_list =*/ NULL,
- /*.hotplug_poll =*/ NULL,
- /*.wrap_sys_device =*/ NULL,
- /*.open =*/ haiku_open,
- /*.close =*/ haiku_close,
-
- /*.get_active_config_descriptor =*/ haiku_get_active_config_descriptor,
- /*.get_config_descriptor =*/ haiku_get_config_descriptor,
- /*.get_config_descriptor_by_value =*/ NULL,
-
- /*.get_configuration =*/ NULL,
- /*.set_configuration =*/ haiku_set_configuration,
-
- /*.claim_interface =*/ haiku_claim_interface,
- /*.release_interface =*/ haiku_release_interface,
- /*.set_interface_altsetting =*/ haiku_set_altsetting,
-
- /*.clear_halt =*/ haiku_clear_halt,
- /*.reset_device =*/ NULL,
-
- /*.alloc_streams =*/ NULL,
- /*.free_streams =*/ NULL,
-
- /*.dev_mem_alloc =*/ NULL,
- /*.dev_mem_free =*/ NULL,
-
- /*.kernel_driver_active =*/ NULL,
- /*.detach_kernel_driver =*/ NULL,
- /*.attach_kernel_driver =*/ NULL,
-
- /*.destroy_device =*/ NULL,
-
- /*.submit_transfer =*/ haiku_submit_transfer,
- /*.cancel_transfer =*/ haiku_cancel_transfer,
- /*.clear_transfer_priv =*/ NULL,
-
- /*.handle_events =*/ NULL,
- /*.handle_transfer_completion =*/ haiku_handle_transfer_completion,
-
- /*.context_priv_size =*/ 0,
- /*.device_priv_size =*/ sizeof(USBDevice *),
- /*.device_handle_priv_size =*/ sizeof(USBDeviceHandle *),
- /*.transfer_priv_size =*/ sizeof(USBTransfer *),
-};
diff --git a/src/os/haiku_usb_raw.h b/src/os/haiku_usb_raw.h
deleted file mode 100644
index d371f01..0000000
--- a/src/os/haiku_usb_raw.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright 2006-2008, Haiku Inc. All rights reserved.
- * Distributed under the terms of the MIT License.
- */
-
-#ifndef _USB_RAW_H_
-#define _USB_RAW_H_
-
-#include <USB3.h>
-
-#define B_USB_RAW_PROTOCOL_VERSION 0x0015
-#define B_USB_RAW_ACTIVE_ALTERNATE 0xffffffff
-
-typedef enum {
- B_USB_RAW_COMMAND_GET_VERSION = 0x1000,
-
- B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR = 0x2000,
- B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR,
- B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR,
- B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR,
- B_USB_RAW_COMMAND_GET_STRING_DESCRIPTOR,
- B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR,
- B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT,
- B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX,
- B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC,
- B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC,
- B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR_ETC,
- B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR_ETC,
-
- B_USB_RAW_COMMAND_SET_CONFIGURATION = 0x3000,
- B_USB_RAW_COMMAND_SET_FEATURE,
- B_USB_RAW_COMMAND_CLEAR_FEATURE,
- B_USB_RAW_COMMAND_GET_STATUS,
- B_USB_RAW_COMMAND_GET_DESCRIPTOR,
- B_USB_RAW_COMMAND_SET_ALT_INTERFACE,
-
- B_USB_RAW_COMMAND_CONTROL_TRANSFER = 0x4000,
- B_USB_RAW_COMMAND_INTERRUPT_TRANSFER,
- B_USB_RAW_COMMAND_BULK_TRANSFER,
- B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER
-} usb_raw_command_id;
-
-
-typedef enum {
- B_USB_RAW_STATUS_SUCCESS = 0,
-
- B_USB_RAW_STATUS_FAILED,
- B_USB_RAW_STATUS_ABORTED,
- B_USB_RAW_STATUS_STALLED,
- B_USB_RAW_STATUS_CRC_ERROR,
- B_USB_RAW_STATUS_TIMEOUT,
-
- B_USB_RAW_STATUS_INVALID_CONFIGURATION,
- B_USB_RAW_STATUS_INVALID_INTERFACE,
- B_USB_RAW_STATUS_INVALID_ENDPOINT,
- B_USB_RAW_STATUS_INVALID_STRING,
-
- B_USB_RAW_STATUS_NO_MEMORY
-} usb_raw_command_status;
-
-
-typedef union {
- struct {
- status_t status;
- } version;
-
- struct {
- status_t status;
- usb_device_descriptor *descriptor;
- } device;
-
- struct {
- status_t status;
- usb_configuration_descriptor *descriptor;
- uint32 config_index;
- } config;
-
- struct {
- status_t status;
- usb_configuration_descriptor *descriptor;
- uint32 config_index;
- size_t length;
- } config_etc;
-
- struct {
- status_t status;
- uint32 alternate_info;
- uint32 config_index;
- uint32 interface_index;
- } alternate;
-
- struct {
- status_t status;
- usb_interface_descriptor *descriptor;
- uint32 config_index;
- uint32 interface_index;
- } interface;
-
- struct {
- status_t status;
- usb_interface_descriptor *descriptor;
- uint32 config_index;
- uint32 interface_index;
- uint32 alternate_index;
- } interface_etc;
-
- struct {
- status_t status;
- usb_endpoint_descriptor *descriptor;
- uint32 config_index;
- uint32 interface_index;
- uint32 endpoint_index;
- } endpoint;
-
- struct {
- status_t status;
- usb_endpoint_descriptor *descriptor;
- uint32 config_index;
- uint32 interface_index;
- uint32 alternate_index;
- uint32 endpoint_index;
- } endpoint_etc;
-
- struct {
- status_t status;
- usb_descriptor *descriptor;
- uint32 config_index;
- uint32 interface_index;
- uint32 generic_index;
- size_t length;
- } generic;
-
- struct {
- status_t status;
- usb_descriptor *descriptor;
- uint32 config_index;
- uint32 interface_index;
- uint32 alternate_index;
- uint32 generic_index;
- size_t length;
- } generic_etc;
-
- struct {
- status_t status;
- usb_string_descriptor *descriptor;
- uint32 string_index;
- size_t length;
- } string;
-
- struct {
- status_t status;
- uint8 type;
- uint8 index;
- uint16 language_id;
- void *data;
- size_t length;
- } descriptor;
-
- struct {
- status_t status;
- uint8 request_type;
- uint8 request;
- uint16 value;
- uint16 index;
- uint16 length;
- void *data;
- } control;
-
- struct {
- status_t status;
- uint32 interface;
- uint32 endpoint;
- void *data;
- size_t length;
- } transfer;
-
- struct {
- status_t status;
- uint32 interface;
- uint32 endpoint;
- void *data;
- size_t length;
- usb_iso_packet_descriptor *packet_descriptors;
- uint32 packet_count;
- } isochronous;
-} usb_raw_command;
-
-#endif // _USB_RAW_H_
diff --git a/src/os/linux_netlink.c b/src/os/linux_netlink.c
deleted file mode 100644
index 899084f..0000000
--- a/src/os/linux_netlink.c
+++ /dev/null
@@ -1,401 +0,0 @@
-/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */
-/*
- * Linux usbfs backend for libusb
- * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
- * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
- * Copyright (c) 2013 Nathan Hjelm <hjelmn@mac.com>
- * Copyright (c) 2016 Chris Dickens <christopher.a.dickens@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 "libusbi.h"
-#include "linux_usbfs.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <pthread.h>
-#include <string.h>
-#include <unistd.h>
-
-#ifdef HAVE_ASM_TYPES_H
-#include <asm/types.h>
-#endif
-#include <sys/socket.h>
-#include <linux/netlink.h>
-
-#define NL_GROUP_KERNEL 1
-
-#ifndef SOCK_CLOEXEC
-#define SOCK_CLOEXEC 0
-#endif
-
-#ifndef SOCK_NONBLOCK
-#define SOCK_NONBLOCK 0
-#endif
-
-static int linux_netlink_socket = -1;
-static usbi_event_t netlink_control_event = USBI_INVALID_EVENT;
-static pthread_t libusb_linux_event_thread;
-
-static void *linux_netlink_event_thread_main(void *arg);
-
-static int set_fd_cloexec_nb(int fd, int socktype)
-{
- int flags;
-
-#if defined(FD_CLOEXEC)
- /* Make sure the netlink socket file descriptor is marked as CLOEXEC */
- if (!(socktype & SOCK_CLOEXEC)) {
- flags = fcntl(fd, F_GETFD);
- if (flags == -1) {
- usbi_err(NULL, "failed to get netlink fd flags, errno=%d", errno);
- return -1;
- }
-
- if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
- usbi_err(NULL, "failed to set netlink fd flags, errno=%d", errno);
- return -1;
- }
- }
-#endif
-
- /* Make sure the netlink socket is non-blocking */
- if (!(socktype & SOCK_NONBLOCK)) {
- flags = fcntl(fd, F_GETFL);
- if (flags == -1) {
- usbi_err(NULL, "failed to get netlink fd status flags, errno=%d", errno);
- return -1;
- }
-
- if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
- usbi_err(NULL, "failed to set netlink fd status flags, errno=%d", errno);
- return -1;
- }
- }
-
- return 0;
-}
-
-int linux_netlink_start_event_monitor(void)
-{
- struct sockaddr_nl sa_nl = { .nl_family = AF_NETLINK, .nl_groups = NL_GROUP_KERNEL };
- int socktype = SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC;
- int opt = 1;
- int ret;
-
- linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
- if (linux_netlink_socket == -1 && errno == EINVAL) {
- usbi_dbg(NULL, "failed to create netlink socket of type %d, attempting SOCK_RAW", socktype);
- socktype = SOCK_RAW;
- linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
- }
-
- if (linux_netlink_socket == -1) {
- usbi_err(NULL, "failed to create netlink socket, errno=%d", errno);
- goto err;
- }
-
- ret = set_fd_cloexec_nb(linux_netlink_socket, socktype);
- if (ret == -1)
- goto err_close_socket;
-
- ret = bind(linux_netlink_socket, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
- if (ret == -1) {
- usbi_err(NULL, "failed to bind netlink socket, errno=%d", errno);
- goto err_close_socket;
- }
-
- ret = setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt));
- if (ret == -1) {
- usbi_err(NULL, "failed to set netlink socket SO_PASSCRED option, errno=%d", errno);
- goto err_close_socket;
- }
-
- ret = usbi_create_event(&netlink_control_event);
- if (ret) {
- usbi_err(NULL, "failed to create netlink control event");
- goto err_close_socket;
- }
-
- ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL);
- if (ret != 0) {
- usbi_err(NULL, "failed to create netlink event thread (%d)", ret);
- goto err_destroy_event;
- }
-
- return LIBUSB_SUCCESS;
-
-err_destroy_event:
- usbi_destroy_event(&netlink_control_event);
- netlink_control_event = (usbi_event_t)USBI_INVALID_EVENT;
-err_close_socket:
- close(linux_netlink_socket);
- linux_netlink_socket = -1;
-err:
- return LIBUSB_ERROR_OTHER;
-}
-
-int linux_netlink_stop_event_monitor(void)
-{
- int ret;
-
- assert(linux_netlink_socket != -1);
-
- /* Signal the control event and wait for the thread to exit */
- usbi_signal_event(&netlink_control_event);
-
- ret = pthread_join(libusb_linux_event_thread, NULL);
- if (ret)
- usbi_warn(NULL, "failed to join netlink event thread (%d)", ret);
-
- usbi_destroy_event(&netlink_control_event);
- netlink_control_event = (usbi_event_t)USBI_INVALID_EVENT;
-
- close(linux_netlink_socket);
- linux_netlink_socket = -1;
-
- return LIBUSB_SUCCESS;
-}
-
-static const char *netlink_message_parse(const char *buffer, size_t len, const char *key)
-{
- const char *end = buffer + len;
- size_t keylen = strlen(key);
-
- while (buffer < end && *buffer) {
- if (strncmp(buffer, key, keylen) == 0 && buffer[keylen] == '=')
- return buffer + keylen + 1;
- buffer += strlen(buffer) + 1;
- }
-
- return NULL;
-}
-
-/* parse parts of netlink message common to both libudev and the kernel */
-static int linux_netlink_parse(const char *buffer, size_t len, int *detached,
- const char **sys_name, uint8_t *busnum, uint8_t *devaddr)
-{
- const char *tmp, *slash;
-
- errno = 0;
-
- *sys_name = NULL;
- *detached = 0;
- *busnum = 0;
- *devaddr = 0;
-
- tmp = netlink_message_parse(buffer, len, "ACTION");
- if (!tmp) {
- return -1;
- } else if (strcmp(tmp, "remove") == 0) {
- *detached = 1;
- } else if (strcmp(tmp, "add") != 0) {
- usbi_dbg(NULL, "unknown device action %s", tmp);
- return -1;
- }
-
- /* check that this is a usb message */
- tmp = netlink_message_parse(buffer, len, "SUBSYSTEM");
- if (!tmp || strcmp(tmp, "usb") != 0) {
- /* not usb. ignore */
- return -1;
- }
-
- /* check that this is an actual usb device */
- tmp = netlink_message_parse(buffer, len, "DEVTYPE");
- if (!tmp || strcmp(tmp, "usb_device") != 0) {
- /* not usb. ignore */
- return -1;
- }
-
- tmp = netlink_message_parse(buffer, len, "BUSNUM");
- if (tmp) {
- *busnum = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff);
- if (errno) {
- errno = 0;
- return -1;
- }
-
- tmp = netlink_message_parse(buffer, len, "DEVNUM");
- if (NULL == tmp)
- return -1;
-
- *devaddr = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff);
- if (errno) {
- errno = 0;
- return -1;
- }
- } else {
- /* no bus number. try "DEVICE" */
- tmp = netlink_message_parse(buffer, len, "DEVICE");
- if (!tmp) {
- /* not usb. ignore */
- return -1;
- }
-
- /* Parse a device path such as /dev/bus/usb/003/004 */
- slash = strrchr(tmp, '/');
- if (!slash)
- return -1;
-
- *busnum = (uint8_t)(strtoul(slash - 3, NULL, 10) & 0xff);
- if (errno) {
- errno = 0;
- return -1;
- }
-
- *devaddr = (uint8_t)(strtoul(slash + 1, NULL, 10) & 0xff);
- if (errno) {
- errno = 0;
- return -1;
- }
-
- return 0;
- }
-
- tmp = netlink_message_parse(buffer, len, "DEVPATH");
- if (!tmp)
- return -1;
-
- slash = strrchr(tmp, '/');
- if (slash)
- *sys_name = slash + 1;
-
- /* found a usb device */
- return 0;
-}
-
-static int linux_netlink_read_message(void)
-{
- char cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
- char msg_buffer[2048];
- const char *sys_name = NULL;
- uint8_t busnum, devaddr;
- int detached, r;
- ssize_t len;
- struct cmsghdr *cmsg;
- struct ucred *cred;
- struct sockaddr_nl sa_nl;
- struct iovec iov = { .iov_base = msg_buffer, .iov_len = sizeof(msg_buffer) };
- struct msghdr msg = {
- .msg_iov = &iov, .msg_iovlen = 1,
- .msg_control = cred_buffer, .msg_controllen = sizeof(cred_buffer),
- .msg_name = &sa_nl, .msg_namelen = sizeof(sa_nl)
- };
-
- /* read netlink message */
- len = recvmsg(linux_netlink_socket, &msg, 0);
- if (len == -1) {
- if (errno != EAGAIN && errno != EINTR)
- usbi_err(NULL, "error receiving message from netlink, errno=%d", errno);
- return -1;
- }
-
- if (len < 32 || (msg.msg_flags & MSG_TRUNC)) {
- usbi_err(NULL, "invalid netlink message length");
- return -1;
- }
-
- if (sa_nl.nl_groups != NL_GROUP_KERNEL || sa_nl.nl_pid != 0) {
- usbi_dbg(NULL, "ignoring netlink message from unknown group/PID (%u/%u)",
- (unsigned int)sa_nl.nl_groups, (unsigned int)sa_nl.nl_pid);
- return -1;
- }
-
- cmsg = CMSG_FIRSTHDR(&msg);
- if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) {
- usbi_dbg(NULL, "ignoring netlink message with no sender credentials");
- return -1;
- }
-
- cred = (struct ucred *)CMSG_DATA(cmsg);
- if (cred->uid != 0) {
- usbi_dbg(NULL, "ignoring netlink message with non-zero sender UID %u", (unsigned int)cred->uid);
- return -1;
- }
-
- r = linux_netlink_parse(msg_buffer, (size_t)len, &detached, &sys_name, &busnum, &devaddr);
- if (r)
- return r;
-
- usbi_dbg(NULL, "netlink hotplug found device busnum: %hhu, devaddr: %hhu, sys_name: %s, removed: %s",
- busnum, devaddr, sys_name, detached ? "yes" : "no");
-
- /* signal device is available (or not) to all contexts */
- if (detached)
- linux_device_disconnected(busnum, devaddr);
- else
- linux_hotplug_enumerate(busnum, devaddr, sys_name);
-
- return 0;
-}
-
-static void *linux_netlink_event_thread_main(void *arg)
-{
- struct pollfd fds[] = {
- { .fd = USBI_EVENT_OS_HANDLE(&netlink_control_event),
- .events = USBI_EVENT_POLL_EVENTS },
- { .fd = linux_netlink_socket,
- .events = POLLIN },
- };
- int r;
-
- UNUSED(arg);
-
-#if defined(HAVE_PTHREAD_SETNAME_NP)
- r = pthread_setname_np(pthread_self(), "libusb_event");
- if (r)
- usbi_warn(NULL, "failed to set hotplug event thread name, error=%d", r);
-#endif
-
- usbi_dbg(NULL, "netlink event thread entering");
-
- while (1) {
- r = poll(fds, 2, -1);
- if (r == -1) {
- /* check for temporary failure */
- if (errno == EINTR)
- continue;
- usbi_err(NULL, "poll() failed, errno=%d", errno);
- break;
- }
- if (fds[0].revents) {
- /* activity on control event, exit */
- break;
- }
- if (fds[1].revents) {
- usbi_mutex_static_lock(&linux_hotplug_lock);
- linux_netlink_read_message();
- usbi_mutex_static_unlock(&linux_hotplug_lock);
- }
- }
-
- usbi_dbg(NULL, "netlink event thread exiting");
-
- return NULL;
-}
-
-void linux_netlink_hotplug_poll(void)
-{
- int r;
-
- usbi_mutex_static_lock(&linux_hotplug_lock);
- do {
- r = linux_netlink_read_message();
- } while (r == 0);
- usbi_mutex_static_unlock(&linux_hotplug_lock);
-}
diff --git a/src/os/netbsd_usb.c b/src/os/netbsd_usb.c
deleted file mode 100644
index 74833f6..0000000
--- a/src/os/netbsd_usb.c
+++ /dev/null
@@ -1,617 +0,0 @@
-/*
- * Copyright © 2011 Martin Pieuchot <mpi@openbsd.org>
- *
- * 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 <sys/time.h>
-#include <sys/types.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <dev/usb/usb.h>
-
-#include "libusbi.h"
-
-struct device_priv {
- char devnode[16];
- int fd;
-
- usb_config_descriptor_t *cdesc; /* active config descriptor */
-};
-
-struct handle_priv {
- int endpoints[USB_MAX_ENDPOINTS];
-};
-
-/*
- * Backend functions
- */
-static int netbsd_get_device_list(struct libusb_context *,
- struct discovered_devs **);
-static int netbsd_open(struct libusb_device_handle *);
-static void netbsd_close(struct libusb_device_handle *);
-
-static int netbsd_get_active_config_descriptor(struct libusb_device *,
- void *, size_t);
-static int netbsd_get_config_descriptor(struct libusb_device *, uint8_t,
- void *, size_t);
-
-static int netbsd_get_configuration(struct libusb_device_handle *, uint8_t *);
-static int netbsd_set_configuration(struct libusb_device_handle *, int);
-
-static int netbsd_claim_interface(struct libusb_device_handle *, uint8_t);
-static int netbsd_release_interface(struct libusb_device_handle *, uint8_t);
-
-static int netbsd_set_interface_altsetting(struct libusb_device_handle *,
- uint8_t, uint8_t);
-static int netbsd_clear_halt(struct libusb_device_handle *, unsigned char);
-static void netbsd_destroy_device(struct libusb_device *);
-
-static int netbsd_submit_transfer(struct usbi_transfer *);
-static int netbsd_cancel_transfer(struct usbi_transfer *);
-static int netbsd_handle_transfer_completion(struct usbi_transfer *);
-
-/*
- * Private functions
- */
-static int _errno_to_libusb(int);
-static int _cache_active_config_descriptor(struct libusb_device *, int);
-static int _sync_control_transfer(struct usbi_transfer *);
-static int _sync_gen_transfer(struct usbi_transfer *);
-static int _access_endpoint(struct libusb_transfer *);
-
-const struct usbi_os_backend usbi_backend = {
- .name = "Synchronous NetBSD backend",
- .caps = 0,
- .get_device_list = netbsd_get_device_list,
- .open = netbsd_open,
- .close = netbsd_close,
-
- .get_active_config_descriptor = netbsd_get_active_config_descriptor,
- .get_config_descriptor = netbsd_get_config_descriptor,
-
- .get_configuration = netbsd_get_configuration,
- .set_configuration = netbsd_set_configuration,
-
- .claim_interface = netbsd_claim_interface,
- .release_interface = netbsd_release_interface,
-
- .set_interface_altsetting = netbsd_set_interface_altsetting,
- .clear_halt = netbsd_clear_halt,
-
- .destroy_device = netbsd_destroy_device,
-
- .submit_transfer = netbsd_submit_transfer,
- .cancel_transfer = netbsd_cancel_transfer,
-
- .handle_transfer_completion = netbsd_handle_transfer_completion,
-
- .device_priv_size = sizeof(struct device_priv),
- .device_handle_priv_size = sizeof(struct handle_priv),
-};
-
-int
-netbsd_get_device_list(struct libusb_context * ctx,
- struct discovered_devs **discdevs)
-{
- struct libusb_device *dev;
- struct device_priv *dpriv;
- struct usb_device_info di;
- usb_device_descriptor_t ddesc;
- unsigned long session_id;
- char devnode[16];
- int fd, err, i;
-
- usbi_dbg(ctx, " ");
-
- /* Only ugen(4) is supported */
- for (i = 0; i < USB_MAX_DEVICES; i++) {
- /* Control endpoint is always .00 */
- snprintf(devnode, sizeof(devnode), "/dev/ugen%d.00", i);
-
- if ((fd = open(devnode, O_RDONLY)) < 0) {
- if (errno != ENOENT && errno != ENXIO)
- usbi_err(ctx, "could not open %s", devnode);
- continue;
- }
-
- if (ioctl(fd, USB_GET_DEVICEINFO, &di) < 0)
- continue;
-
- session_id = (di.udi_bus << 8 | di.udi_addr);
- dev = usbi_get_device_by_session_id(ctx, session_id);
-
- if (dev == NULL) {
- dev = usbi_alloc_device(ctx, session_id);
- if (dev == NULL)
- return (LIBUSB_ERROR_NO_MEM);
-
- dev->bus_number = di.udi_bus;
- dev->device_address = di.udi_addr;
- dev->speed = di.udi_speed;
-
- dpriv = usbi_get_device_priv(dev);
- strlcpy(dpriv->devnode, devnode, sizeof(devnode));
- dpriv->fd = -1;
-
- if (ioctl(fd, USB_GET_DEVICE_DESC, &ddesc) < 0) {
- err = errno;
- goto error;
- }
-
- static_assert(sizeof(dev->device_descriptor) == sizeof(ddesc),
- "mismatch between libusb and OS device descriptor sizes");
- memcpy(&dev->device_descriptor, &ddesc, LIBUSB_DT_DEVICE_SIZE);
- usbi_localize_device_descriptor(&dev->device_descriptor);
-
- if (_cache_active_config_descriptor(dev, fd)) {
- err = errno;
- goto error;
- }
-
- if ((err = usbi_sanitize_device(dev)))
- goto error;
- }
- close(fd);
-
- if (discovered_devs_append(*discdevs, dev) == NULL)
- return (LIBUSB_ERROR_NO_MEM);
-
- libusb_unref_device(dev);
- }
-
- return (LIBUSB_SUCCESS);
-
-error:
- close(fd);
- libusb_unref_device(dev);
- return _errno_to_libusb(err);
-}
-
-int
-netbsd_open(struct libusb_device_handle *handle)
-{
- struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
- struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
- int i;
-
- dpriv->fd = open(dpriv->devnode, O_RDWR);
- if (dpriv->fd < 0) {
- dpriv->fd = open(dpriv->devnode, O_RDONLY);
- if (dpriv->fd < 0)
- return _errno_to_libusb(errno);
- }
-
- for (i = 0; i < USB_MAX_ENDPOINTS; i++)
- hpriv->endpoints[i] = -1;
-
- usbi_dbg(HANDLE_CTX(handle), "open %s: fd %d", dpriv->devnode, dpriv->fd);
-
- return (LIBUSB_SUCCESS);
-}
-
-void
-netbsd_close(struct libusb_device_handle *handle)
-{
- struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
-
- usbi_dbg(HANDLE_CTX(handle), "close: fd %d", dpriv->fd);
-
- close(dpriv->fd);
- dpriv->fd = -1;
-}
-
-int
-netbsd_get_active_config_descriptor(struct libusb_device *dev,
- void *buf, size_t len)
-{
- struct device_priv *dpriv = usbi_get_device_priv(dev);
-
- len = MIN(len, (size_t)UGETW(dpriv->cdesc->wTotalLength));
-
- usbi_dbg(DEVICE_CTX(dev), "len %zu", len);
-
- memcpy(buf, dpriv->cdesc, len);
-
- return (int)len;
-}
-
-int
-netbsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
- void *buf, size_t len)
-{
- struct device_priv *dpriv = usbi_get_device_priv(dev);
- struct usb_full_desc ufd;
- int fd, err;
-
- usbi_dbg(DEVICE_CTX(dev), "index %u, len %zu", idx, len);
-
- /* A config descriptor may be requested before opening the device */
- if (dpriv->fd >= 0) {
- fd = dpriv->fd;
- } else {
- fd = open(dpriv->devnode, O_RDONLY);
- if (fd < 0)
- return _errno_to_libusb(errno);
- }
-
- ufd.ufd_config_index = idx;
- ufd.ufd_size = len;
- ufd.ufd_data = buf;
-
- if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
- err = errno;
- if (dpriv->fd < 0)
- close(fd);
- return _errno_to_libusb(err);
- }
-
- if (dpriv->fd < 0)
- close(fd);
-
- return (int)len;
-}
-
-int
-netbsd_get_configuration(struct libusb_device_handle *handle, uint8_t *config)
-{
- struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
- int tmp;
-
- usbi_dbg(HANDLE_CTX(handle), " ");
-
- if (ioctl(dpriv->fd, USB_GET_CONFIG, &tmp) < 0)
- return _errno_to_libusb(errno);
-
- usbi_dbg(HANDLE_CTX(handle), "configuration %d", tmp);
- *config = (uint8_t)tmp;
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-netbsd_set_configuration(struct libusb_device_handle *handle, int config)
-{
- struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
-
- usbi_dbg(HANDLE_CTX(handle), "configuration %d", config);
-
- if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0)
- return _errno_to_libusb(errno);
-
- return _cache_active_config_descriptor(handle->dev, dpriv->fd);
-}
-
-int
-netbsd_claim_interface(struct libusb_device_handle *handle, uint8_t iface)
-{
- struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
- int i;
-
- UNUSED(iface);
-
- for (i = 0; i < USB_MAX_ENDPOINTS; i++)
- hpriv->endpoints[i] = -1;
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-netbsd_release_interface(struct libusb_device_handle *handle, uint8_t iface)
-{
- struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
- int i;
-
- UNUSED(iface);
-
- for (i = 0; i < USB_MAX_ENDPOINTS; i++)
- if (hpriv->endpoints[i] >= 0)
- close(hpriv->endpoints[i]);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-netbsd_set_interface_altsetting(struct libusb_device_handle *handle, uint8_t iface,
- uint8_t altsetting)
-{
- struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
- struct usb_alt_interface intf;
-
- usbi_dbg(HANDLE_CTX(handle), "iface %u, setting %u", iface, altsetting);
-
- memset(&intf, 0, sizeof(intf));
-
- intf.uai_interface_index = iface;
- intf.uai_alt_no = altsetting;
-
- if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0)
- return _errno_to_libusb(errno);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-netbsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
-{
- struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
- struct usb_ctl_request req;
-
- usbi_dbg(HANDLE_CTX(handle), " ");
-
- req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT;
- req.ucr_request.bRequest = UR_CLEAR_FEATURE;
- USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT);
- USETW(req.ucr_request.wIndex, endpoint);
- USETW(req.ucr_request.wLength, 0);
-
- if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0)
- return _errno_to_libusb(errno);
-
- return (LIBUSB_SUCCESS);
-}
-
-void
-netbsd_destroy_device(struct libusb_device *dev)
-{
- struct device_priv *dpriv = usbi_get_device_priv(dev);
-
- usbi_dbg(DEVICE_CTX(dev), " ");
-
- free(dpriv->cdesc);
-}
-
-int
-netbsd_submit_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer;
- int err = 0;
-
- usbi_dbg(ITRANSFER_CTX(itransfer), " ");
-
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- err = _sync_control_transfer(itransfer);
- break;
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- if (IS_XFEROUT(transfer)) {
- /* Isochronous write is not supported */
- err = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
- err = _sync_gen_transfer(itransfer);
- break;
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- if (IS_XFEROUT(transfer) &&
- transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
- err = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
- err = _sync_gen_transfer(itransfer);
- break;
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- err = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
-
- if (err)
- return (err);
-
- usbi_signal_transfer_completion(itransfer);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-netbsd_cancel_transfer(struct usbi_transfer *itransfer)
-{
- UNUSED(itransfer);
-
- usbi_dbg(ITRANSFER_CTX(itransfer), " ");
-
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-}
-
-int
-netbsd_handle_transfer_completion(struct usbi_transfer *itransfer)
-{
- return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
-}
-
-int
-_errno_to_libusb(int err)
-{
- switch (err) {
- case EIO:
- return (LIBUSB_ERROR_IO);
- case EACCES:
- return (LIBUSB_ERROR_ACCESS);
- case ENOENT:
- return (LIBUSB_ERROR_NO_DEVICE);
- case ENOMEM:
- return (LIBUSB_ERROR_NO_MEM);
- case EWOULDBLOCK:
- case ETIMEDOUT:
- return (LIBUSB_ERROR_TIMEOUT);
- }
-
- usbi_dbg(NULL, "error: %s", strerror(err));
-
- return (LIBUSB_ERROR_OTHER);
-}
-
-int
-_cache_active_config_descriptor(struct libusb_device *dev, int fd)
-{
- struct device_priv *dpriv = usbi_get_device_priv(dev);
- struct usb_config_desc ucd;
- struct usb_full_desc ufd;
- void *buf;
- int len;
-
- usbi_dbg(DEVICE_CTX(dev), "fd %d", fd);
-
- ucd.ucd_config_index = USB_CURRENT_CONFIG_INDEX;
-
- if ((ioctl(fd, USB_GET_CONFIG_DESC, &ucd)) < 0)
- return _errno_to_libusb(errno);
-
- usbi_dbg(DEVICE_CTX(dev), "active bLength %d", ucd.ucd_desc.bLength);
-
- len = UGETW(ucd.ucd_desc.wTotalLength);
- buf = malloc((size_t)len);
- if (buf == NULL)
- return (LIBUSB_ERROR_NO_MEM);
-
- ufd.ufd_config_index = ucd.ucd_config_index;
- ufd.ufd_size = len;
- ufd.ufd_data = buf;
-
- usbi_dbg(DEVICE_CTX(dev), "index %d, len %d", ufd.ufd_config_index, len);
-
- if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
- free(buf);
- return _errno_to_libusb(errno);
- }
-
- if (dpriv->cdesc)
- free(dpriv->cdesc);
- dpriv->cdesc = buf;
-
- return (0);
-}
-
-int
-_sync_control_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer;
- struct libusb_control_setup *setup;
- struct device_priv *dpriv;
- struct usb_ctl_request req;
-
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
- setup = (struct libusb_control_setup *)transfer->buffer;
-
- usbi_dbg(ITRANSFER_CTX(itransfer), "type %d request %d value %d index %d length %d timeout %d",
- setup->bmRequestType, setup->bRequest,
- libusb_le16_to_cpu(setup->wValue),
- libusb_le16_to_cpu(setup->wIndex),
- libusb_le16_to_cpu(setup->wLength), transfer->timeout);
-
- req.ucr_request.bmRequestType = setup->bmRequestType;
- req.ucr_request.bRequest = setup->bRequest;
- /* Don't use USETW, libusb already deals with the endianness */
- (*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
- (*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
- (*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
- req.ucr_data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
-
- if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
- req.ucr_flags = USBD_SHORT_XFER_OK;
-
- if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
- return _errno_to_libusb(errno);
-
- if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0)
- return _errno_to_libusb(errno);
-
- itransfer->transferred = req.ucr_actlen;
-
- usbi_dbg(ITRANSFER_CTX(itransfer), "transferred %d", itransfer->transferred);
-
- return (0);
-}
-
-int
-_access_endpoint(struct libusb_transfer *transfer)
-{
- struct handle_priv *hpriv;
- struct device_priv *dpriv;
- char *s, devnode[16];
- int fd, endpt;
- mode_t mode;
-
- hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
- dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
-
- endpt = UE_GET_ADDR(transfer->endpoint);
- mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;
-
- usbi_dbg(TRANSFER_CTX(transfer), "endpoint %d mode %d", endpt, mode);
-
- if (hpriv->endpoints[endpt] < 0) {
- /* Pick the right node given the control one */
- strlcpy(devnode, dpriv->devnode, sizeof(devnode));
- s = strchr(devnode, '.');
- snprintf(s, 4, ".%02d", endpt);
-
- /* We may need to read/write to the same endpoint later. */
- if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
- if ((fd = open(devnode, mode)) < 0)
- return (-1);
-
- hpriv->endpoints[endpt] = fd;
- }
-
- return (hpriv->endpoints[endpt]);
-}
-
-int
-_sync_gen_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer;
- int fd, nr = 1;
-
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-
- /*
- * Bulk, Interrupt or Isochronous transfer depends on the
- * endpoint and thus the node to open.
- */
- if ((fd = _access_endpoint(transfer)) < 0)
- return _errno_to_libusb(errno);
-
- if ((ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
- return _errno_to_libusb(errno);
-
- if (IS_XFERIN(transfer)) {
- if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
- if ((ioctl(fd, USB_SET_SHORT_XFER, &nr)) < 0)
- return _errno_to_libusb(errno);
-
- nr = read(fd, transfer->buffer, transfer->length);
- } else {
- nr = write(fd, transfer->buffer, transfer->length);
- }
-
- if (nr < 0)
- return _errno_to_libusb(errno);
-
- itransfer->transferred = nr;
-
- return (0);
-}
diff --git a/src/os/null_usb.c b/src/os/null_usb.c
deleted file mode 100644
index 0cd531d..0000000
--- a/src/os/null_usb.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright © 2019 Pino Toscano <toscano.pino@tiscali.it>
- *
- * 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 "libusbi.h"
-
-static int
-null_get_device_list(struct libusb_context * ctx,
- struct discovered_devs **discdevs)
-{
- return LIBUSB_SUCCESS;
-}
-
-static int
-null_open(struct libusb_device_handle *handle)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static void
-null_close(struct libusb_device_handle *handle)
-{
-}
-
-static int
-null_get_active_config_descriptor(struct libusb_device *dev,
- void *buf, size_t len)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int
-null_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
- void *buf, size_t len)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int
-null_set_configuration(struct libusb_device_handle *handle, int config)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int
-null_claim_interface(struct libusb_device_handle *handle, uint8_t iface)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int
-null_release_interface(struct libusb_device_handle *handle, uint8_t iface)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int
-null_set_interface_altsetting(struct libusb_device_handle *handle, uint8_t iface,
- uint8_t altsetting)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int
-null_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int
-null_submit_transfer(struct usbi_transfer *itransfer)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int
-null_cancel_transfer(struct usbi_transfer *itransfer)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-const struct usbi_os_backend usbi_backend = {
- .name = "Null backend",
- .caps = 0,
- .get_device_list = null_get_device_list,
- .open = null_open,
- .close = null_close,
- .get_active_config_descriptor = null_get_active_config_descriptor,
- .get_config_descriptor = null_get_config_descriptor,
- .set_configuration = null_set_configuration,
- .claim_interface = null_claim_interface,
- .release_interface = null_release_interface,
- .set_interface_altsetting = null_set_interface_altsetting,
- .clear_halt = null_clear_halt,
- .submit_transfer = null_submit_transfer,
- .cancel_transfer = null_cancel_transfer,
-};
diff --git a/src/os/openbsd_usb.c b/src/os/openbsd_usb.c
deleted file mode 100644
index 9a5c604..0000000
--- a/src/os/openbsd_usb.c
+++ /dev/null
@@ -1,700 +0,0 @@
-/*
- * Copyright © 2011-2013 Martin Pieuchot <mpi@openbsd.org>
- *
- * 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 <sys/time.h>
-#include <sys/types.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <dev/usb/usb.h>
-
-#include "libusbi.h"
-
-struct device_priv {
- char *devname; /* name of the ugen(4) node */
- int fd; /* device file descriptor */
-
- usb_config_descriptor_t *cdesc; /* active config descriptor */
-};
-
-struct handle_priv {
- int endpoints[USB_MAX_ENDPOINTS];
-};
-
-/*
- * Backend functions
- */
-static int obsd_get_device_list(struct libusb_context *,
- struct discovered_devs **);
-static int obsd_open(struct libusb_device_handle *);
-static void obsd_close(struct libusb_device_handle *);
-
-static int obsd_get_active_config_descriptor(struct libusb_device *,
- void *, size_t);
-static int obsd_get_config_descriptor(struct libusb_device *, uint8_t,
- void *, size_t);
-
-static int obsd_get_configuration(struct libusb_device_handle *, uint8_t *);
-static int obsd_set_configuration(struct libusb_device_handle *, int);
-
-static int obsd_claim_interface(struct libusb_device_handle *, uint8_t);
-static int obsd_release_interface(struct libusb_device_handle *, uint8_t);
-
-static int obsd_set_interface_altsetting(struct libusb_device_handle *, uint8_t,
- uint8_t);
-static int obsd_clear_halt(struct libusb_device_handle *, unsigned char);
-static void obsd_destroy_device(struct libusb_device *);
-
-static int obsd_submit_transfer(struct usbi_transfer *);
-static int obsd_cancel_transfer(struct usbi_transfer *);
-static int obsd_handle_transfer_completion(struct usbi_transfer *);
-
-/*
- * Private functions
- */
-static int _errno_to_libusb(int);
-static int _cache_active_config_descriptor(struct libusb_device *);
-static int _sync_control_transfer(struct usbi_transfer *);
-static int _sync_gen_transfer(struct usbi_transfer *);
-static int _access_endpoint(struct libusb_transfer *);
-
-static int _bus_open(int);
-
-
-const struct usbi_os_backend usbi_backend = {
- .name = "Synchronous OpenBSD backend",
- .get_device_list = obsd_get_device_list,
- .open = obsd_open,
- .close = obsd_close,
-
- .get_active_config_descriptor = obsd_get_active_config_descriptor,
- .get_config_descriptor = obsd_get_config_descriptor,
-
- .get_configuration = obsd_get_configuration,
- .set_configuration = obsd_set_configuration,
-
- .claim_interface = obsd_claim_interface,
- .release_interface = obsd_release_interface,
-
- .set_interface_altsetting = obsd_set_interface_altsetting,
- .clear_halt = obsd_clear_halt,
- .destroy_device = obsd_destroy_device,
-
- .submit_transfer = obsd_submit_transfer,
- .cancel_transfer = obsd_cancel_transfer,
-
- .handle_transfer_completion = obsd_handle_transfer_completion,
-
- .device_priv_size = sizeof(struct device_priv),
- .device_handle_priv_size = sizeof(struct handle_priv),
-};
-
-#define DEVPATH "/dev/"
-#define USBDEV DEVPATH "usb"
-
-int
-obsd_get_device_list(struct libusb_context * ctx,
- struct discovered_devs **discdevs)
-{
- struct discovered_devs *ddd;
- struct libusb_device *dev;
- struct device_priv *dpriv;
- struct usb_device_info di;
- struct usb_device_ddesc dd;
- unsigned long session_id;
- char devices[USB_MAX_DEVICES];
- char busnode[16];
- char *udevname;
- int fd, addr, i, j;
-
- usbi_dbg(ctx, " ");
-
- for (i = 0; i < 8; i++) {
- snprintf(busnode, sizeof(busnode), USBDEV "%d", i);
-
- if ((fd = open(busnode, O_RDWR)) < 0) {
- if (errno != ENOENT && errno != ENXIO)
- usbi_err(ctx, "could not open %s", busnode);
- continue;
- }
-
- bzero(devices, sizeof(devices));
- for (addr = 1; addr < USB_MAX_DEVICES; addr++) {
- if (devices[addr])
- continue;
-
- di.udi_addr = addr;
- if (ioctl(fd, USB_DEVICEINFO, &di) < 0)
- continue;
-
- /*
- * XXX If ugen(4) is attached to the USB device
- * it will be used.
- */
- udevname = NULL;
- for (j = 0; j < USB_MAX_DEVNAMES; j++)
- if (!strncmp("ugen", di.udi_devnames[j], 4)) {
- udevname = strdup(di.udi_devnames[j]);
- break;
- }
-
- session_id = (di.udi_bus << 8 | di.udi_addr);
- dev = usbi_get_device_by_session_id(ctx, session_id);
-
- if (dev == NULL) {
- dev = usbi_alloc_device(ctx, session_id);
- if (dev == NULL) {
- close(fd);
- return (LIBUSB_ERROR_NO_MEM);
- }
-
- dev->bus_number = di.udi_bus;
- dev->device_address = di.udi_addr;
- dev->speed = di.udi_speed;
- dev->port_number = di.udi_port;
-
- dpriv = usbi_get_device_priv(dev);
- dpriv->fd = -1;
- dpriv->devname = udevname;
-
- dd.udd_bus = di.udi_bus;
- dd.udd_addr = di.udi_addr;
- if (ioctl(fd, USB_DEVICE_GET_DDESC, &dd) < 0) {
- libusb_unref_device(dev);
- continue;
- }
-
- static_assert(sizeof(dev->device_descriptor) == sizeof(dd.udd_desc),
- "mismatch between libusb and OS device descriptor sizes");
- memcpy(&dev->device_descriptor, &dd.udd_desc, LIBUSB_DT_DEVICE_SIZE);
- usbi_localize_device_descriptor(&dev->device_descriptor);
-
- if (_cache_active_config_descriptor(dev)) {
- libusb_unref_device(dev);
- continue;
- }
-
- if (usbi_sanitize_device(dev)) {
- libusb_unref_device(dev);
- continue;
- }
- }
-
- ddd = discovered_devs_append(*discdevs, dev);
- if (ddd == NULL) {
- close(fd);
- return (LIBUSB_ERROR_NO_MEM);
- }
- libusb_unref_device(dev);
-
- *discdevs = ddd;
- devices[addr] = 1;
- }
-
- close(fd);
- }
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-obsd_open(struct libusb_device_handle *handle)
-{
- struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
- char devnode[16];
-
- if (dpriv->devname) {
- int fd;
- /*
- * Only open ugen(4) attached devices read-write, all
- * read-only operations are done through the bus node.
- */
- snprintf(devnode, sizeof(devnode), DEVPATH "%s.00",
- dpriv->devname);
- fd = open(devnode, O_RDWR);
- if (fd < 0)
- return _errno_to_libusb(errno);
- dpriv->fd = fd;
-
- usbi_dbg(HANDLE_CTX(handle), "open %s: fd %d", devnode, dpriv->fd);
- }
-
- return (LIBUSB_SUCCESS);
-}
-
-void
-obsd_close(struct libusb_device_handle *handle)
-{
- struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
-
- if (dpriv->devname) {
- usbi_dbg(HANDLE_CTX(handle), "close: fd %d", dpriv->fd);
-
- close(dpriv->fd);
- dpriv->fd = -1;
- }
-}
-
-int
-obsd_get_active_config_descriptor(struct libusb_device *dev,
- void *buf, size_t len)
-{
- struct device_priv *dpriv = usbi_get_device_priv(dev);
-
- len = MIN(len, (size_t)UGETW(dpriv->cdesc->wTotalLength));
-
- usbi_dbg(DEVICE_CTX(dev), "len %zu", len);
-
- memcpy(buf, dpriv->cdesc, len);
-
- return ((int)len);
-}
-
-int
-obsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
- void *buf, size_t len)
-{
- struct usb_device_fdesc udf;
- int fd, err;
-
- if ((fd = _bus_open(dev->bus_number)) < 0)
- return _errno_to_libusb(errno);
-
- udf.udf_bus = dev->bus_number;
- udf.udf_addr = dev->device_address;
- udf.udf_config_index = idx;
- udf.udf_size = len;
- udf.udf_data = buf;
-
- usbi_dbg(DEVICE_CTX(dev), "index %d, len %zu", udf.udf_config_index, len);
-
- if (ioctl(fd, USB_DEVICE_GET_FDESC, &udf) < 0) {
- err = errno;
- close(fd);
- return _errno_to_libusb(err);
- }
- close(fd);
-
- return ((int)len);
-}
-
-int
-obsd_get_configuration(struct libusb_device_handle *handle, uint8_t *config)
-{
- struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
-
- *config = dpriv->cdesc->bConfigurationValue;
-
- usbi_dbg(HANDLE_CTX(handle), "bConfigurationValue %u", *config);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-obsd_set_configuration(struct libusb_device_handle *handle, int config)
-{
- struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
-
- if (dpriv->devname == NULL)
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-
- usbi_dbg(HANDLE_CTX(handle), "bConfigurationValue %d", config);
-
- if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0)
- return _errno_to_libusb(errno);
-
- return _cache_active_config_descriptor(handle->dev);
-}
-
-int
-obsd_claim_interface(struct libusb_device_handle *handle, uint8_t iface)
-{
- struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
- int i;
-
- UNUSED(iface);
-
- for (i = 0; i < USB_MAX_ENDPOINTS; i++)
- hpriv->endpoints[i] = -1;
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-obsd_release_interface(struct libusb_device_handle *handle, uint8_t iface)
-{
- struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
- int i;
-
- UNUSED(iface);
-
- for (i = 0; i < USB_MAX_ENDPOINTS; i++)
- if (hpriv->endpoints[i] >= 0)
- close(hpriv->endpoints[i]);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-obsd_set_interface_altsetting(struct libusb_device_handle *handle, uint8_t iface,
- uint8_t altsetting)
-{
- struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
- struct usb_alt_interface intf;
-
- if (dpriv->devname == NULL)
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-
- usbi_dbg(HANDLE_CTX(handle), "iface %u, setting %u", iface, altsetting);
-
- memset(&intf, 0, sizeof(intf));
-
- intf.uai_interface_index = iface;
- intf.uai_alt_no = altsetting;
-
- if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0)
- return _errno_to_libusb(errno);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-obsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
-{
- struct usb_ctl_request req;
- int fd, err;
-
- if ((fd = _bus_open(handle->dev->bus_number)) < 0)
- return _errno_to_libusb(errno);
-
- usbi_dbg(HANDLE_CTX(handle), " ");
-
- req.ucr_addr = handle->dev->device_address;
- req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT;
- req.ucr_request.bRequest = UR_CLEAR_FEATURE;
- USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT);
- USETW(req.ucr_request.wIndex, endpoint);
- USETW(req.ucr_request.wLength, 0);
-
- if (ioctl(fd, USB_REQUEST, &req) < 0) {
- err = errno;
- close(fd);
- return _errno_to_libusb(err);
- }
- close(fd);
-
- return (LIBUSB_SUCCESS);
-}
-
-void
-obsd_destroy_device(struct libusb_device *dev)
-{
- struct device_priv *dpriv = usbi_get_device_priv(dev);
-
- usbi_dbg(DEVICE_CTX(dev), " ");
-
- free(dpriv->cdesc);
- free(dpriv->devname);
-}
-
-int
-obsd_submit_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer;
- int err = 0;
-
- usbi_dbg(ITRANSFER_CTX(itransfer), " ");
-
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- err = _sync_control_transfer(itransfer);
- break;
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- if (IS_XFEROUT(transfer)) {
- /* Isochronous write is not supported */
- err = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
- err = _sync_gen_transfer(itransfer);
- break;
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- if (IS_XFEROUT(transfer) &&
- transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
- err = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
- err = _sync_gen_transfer(itransfer);
- break;
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- err = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
-
- if (err)
- return (err);
-
- usbi_signal_transfer_completion(itransfer);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-obsd_cancel_transfer(struct usbi_transfer *itransfer)
-{
- UNUSED(itransfer);
-
- usbi_dbg(ITRANSFER_CTX(itransfer), " ");
-
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-}
-
-int
-obsd_handle_transfer_completion(struct usbi_transfer *itransfer)
-{
- return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
-}
-
-int
-_errno_to_libusb(int err)
-{
- usbi_dbg(NULL, "error: %s (%d)", strerror(err), err);
-
- switch (err) {
- case EIO:
- return (LIBUSB_ERROR_IO);
- case EACCES:
- return (LIBUSB_ERROR_ACCESS);
- case ENOENT:
- return (LIBUSB_ERROR_NO_DEVICE);
- case ENOMEM:
- return (LIBUSB_ERROR_NO_MEM);
- case ETIMEDOUT:
- return (LIBUSB_ERROR_TIMEOUT);
- }
-
- return (LIBUSB_ERROR_OTHER);
-}
-
-int
-_cache_active_config_descriptor(struct libusb_device *dev)
-{
- struct device_priv *dpriv = usbi_get_device_priv(dev);
- struct usb_device_cdesc udc;
- struct usb_device_fdesc udf;
- void *buf;
- int fd, len, err;
-
- if ((fd = _bus_open(dev->bus_number)) < 0)
- return _errno_to_libusb(errno);
-
- usbi_dbg(DEVICE_CTX(dev), "fd %d, addr %d", fd, dev->device_address);
-
- udc.udc_bus = dev->bus_number;
- udc.udc_addr = dev->device_address;
- udc.udc_config_index = USB_CURRENT_CONFIG_INDEX;
- if (ioctl(fd, USB_DEVICE_GET_CDESC, &udc) < 0) {
- err = errno;
- close(fd);
- return _errno_to_libusb(errno);
- }
-
- usbi_dbg(DEVICE_CTX(dev), "active bLength %d", udc.udc_desc.bLength);
-
- len = UGETW(udc.udc_desc.wTotalLength);
- buf = malloc((size_t)len);
- if (buf == NULL)
- return (LIBUSB_ERROR_NO_MEM);
-
- udf.udf_bus = dev->bus_number;
- udf.udf_addr = dev->device_address;
- udf.udf_config_index = udc.udc_config_index;
- udf.udf_size = len;
- udf.udf_data = buf;
-
- usbi_dbg(DEVICE_CTX(dev), "index %d, len %d", udf.udf_config_index, len);
-
- if (ioctl(fd, USB_DEVICE_GET_FDESC, &udf) < 0) {
- err = errno;
- close(fd);
- free(buf);
- return _errno_to_libusb(err);
- }
- close(fd);
-
- if (dpriv->cdesc)
- free(dpriv->cdesc);
- dpriv->cdesc = buf;
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-_sync_control_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer;
- struct libusb_control_setup *setup;
- struct device_priv *dpriv;
- struct usb_ctl_request req;
-
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
- setup = (struct libusb_control_setup *)transfer->buffer;
-
- usbi_dbg(ITRANSFER_CTX(itransfer), "type 0x%x request 0x%x value 0x%x index %d length %d timeout %d",
- setup->bmRequestType, setup->bRequest,
- libusb_le16_to_cpu(setup->wValue),
- libusb_le16_to_cpu(setup->wIndex),
- libusb_le16_to_cpu(setup->wLength), transfer->timeout);
-
- req.ucr_addr = transfer->dev_handle->dev->device_address;
- req.ucr_request.bmRequestType = setup->bmRequestType;
- req.ucr_request.bRequest = setup->bRequest;
- /* Don't use USETW, libusb already deals with the endianness */
- (*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
- (*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
- (*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
- req.ucr_data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
-
- if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
- req.ucr_flags = USBD_SHORT_XFER_OK;
-
- if (dpriv->devname == NULL) {
- /*
- * XXX If the device is not attached to ugen(4) it is
- * XXX still possible to submit a control transfer but
- * XXX with the default timeout only.
- */
- int fd, err;
-
- if ((fd = _bus_open(transfer->dev_handle->dev->bus_number)) < 0)
- return _errno_to_libusb(errno);
-
- if ((ioctl(fd, USB_REQUEST, &req)) < 0) {
- err = errno;
- close(fd);
- return _errno_to_libusb(err);
- }
- close(fd);
- } else {
- if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
- return _errno_to_libusb(errno);
-
- if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0)
- return _errno_to_libusb(errno);
- }
-
- itransfer->transferred = req.ucr_actlen;
-
- usbi_dbg(ITRANSFER_CTX(itransfer), "transferred %d", itransfer->transferred);
-
- return (0);
-}
-
-int
-_access_endpoint(struct libusb_transfer *transfer)
-{
- struct handle_priv *hpriv;
- struct device_priv *dpriv;
- char devnode[16];
- int fd, endpt;
- mode_t mode;
-
- hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
- dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
-
- endpt = UE_GET_ADDR(transfer->endpoint);
- mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;
-
- usbi_dbg(TRANSFER_CTX(transfer), "endpoint %d mode %d", endpt, mode);
-
- if (hpriv->endpoints[endpt] < 0) {
- /* Pick the right endpoint node */
- snprintf(devnode, sizeof(devnode), DEVPATH "%s.%02d",
- dpriv->devname, endpt);
-
- /* We may need to read/write to the same endpoint later. */
- if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
- if ((fd = open(devnode, mode)) < 0)
- return (-1);
-
- hpriv->endpoints[endpt] = fd;
- }
-
- return (hpriv->endpoints[endpt]);
-}
-
-int
-_sync_gen_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer;
- struct device_priv *dpriv;
- int fd, nr = 1;
-
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
-
- if (dpriv->devname == NULL)
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-
- /*
- * Bulk, Interrupt or Isochronous transfer depends on the
- * endpoint and thus the node to open.
- */
- if ((fd = _access_endpoint(transfer)) < 0)
- return _errno_to_libusb(errno);
-
- if ((ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
- return _errno_to_libusb(errno);
-
- if (IS_XFERIN(transfer)) {
- if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
- if ((ioctl(fd, USB_SET_SHORT_XFER, &nr)) < 0)
- return _errno_to_libusb(errno);
-
- nr = read(fd, transfer->buffer, transfer->length);
- } else {
- nr = write(fd, transfer->buffer, transfer->length);
- }
-
- if (nr < 0)
- return _errno_to_libusb(errno);
-
- itransfer->transferred = nr;
-
- return (0);
-}
-
-int
-_bus_open(int number)
-{
- char busnode[16];
-
- snprintf(busnode, sizeof(busnode), USBDEV "%d", number);
-
- return open(busnode, O_RDWR);
-}
diff --git a/src/os/sunos_usb.c b/src/os/sunos_usb.c
deleted file mode 100644
index 28b167f..0000000
--- a/src/os/sunos_usb.c
+++ /dev/null
@@ -1,1609 +0,0 @@
-/*
- *
- * Copyright (c) 2016, Oracle and/or its affiliates.
- *
- * 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 <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <strings.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wait.h>
-#include <unistd.h>
-#include <aio.h>
-#include <libdevinfo.h>
-#include <sys/nvpair.h>
-#include <sys/devctl.h>
-#include <sys/usb/clients/ugen/usb_ugen.h>
-#include <sys/usb/usba.h>
-#include <sys/pci.h>
-
-#include "libusbi.h"
-#include "sunos_usb.h"
-
-#define UPDATEDRV_PATH "/usr/sbin/update_drv"
-#define UPDATEDRV "update_drv"
-
-#define DEFAULT_LISTSIZE 6
-
-typedef struct {
- int nargs;
- int listsize;
- char **string;
-} string_list_t;
-
-/*
- * Backend functions
- */
-static int sunos_get_device_list(struct libusb_context *,
- struct discovered_devs **);
-static int sunos_open(struct libusb_device_handle *);
-static void sunos_close(struct libusb_device_handle *);
-static int sunos_get_active_config_descriptor(struct libusb_device *,
- void *, size_t);
-static int sunos_get_config_descriptor(struct libusb_device *, uint8_t,
- void *, size_t);
-static int sunos_get_configuration(struct libusb_device_handle *, uint8_t *);
-static int sunos_set_configuration(struct libusb_device_handle *, int);
-static int sunos_claim_interface(struct libusb_device_handle *, uint8_t);
-static int sunos_release_interface(struct libusb_device_handle *, uint8_t);
-static int sunos_set_interface_altsetting(struct libusb_device_handle *,
- uint8_t, uint8_t);
-static int sunos_clear_halt(struct libusb_device_handle *, unsigned char);
-static void sunos_destroy_device(struct libusb_device *);
-static int sunos_submit_transfer(struct usbi_transfer *);
-static int sunos_cancel_transfer(struct usbi_transfer *);
-static int sunos_handle_transfer_completion(struct usbi_transfer *);
-static int sunos_kernel_driver_active(struct libusb_device_handle *, uint8_t);
-static int sunos_detach_kernel_driver(struct libusb_device_handle *, uint8_t);
-static int sunos_attach_kernel_driver(struct libusb_device_handle *, uint8_t);
-static int sunos_usb_open_ep0(sunos_dev_handle_priv_t *hpriv, sunos_dev_priv_t *dpriv);
-static int sunos_usb_ioctl(struct libusb_device *dev, int cmd);
-
-static int sunos_get_link(di_devlink_t devlink, void *arg)
-{
- walk_link_t *larg = (walk_link_t *)arg;
- const char *p;
- const char *q;
-
- if (larg->path) {
- char *content = (char *)di_devlink_content(devlink);
- char *start = strstr(content, "/devices/");
- start += strlen("/devices");
- usbi_dbg(NULL, "%s", start);
-
- /* line content must have minor node */
- if (start == NULL ||
- strncmp(start, larg->path, larg->len) != 0 ||
- start[larg->len] != ':')
- return (DI_WALK_CONTINUE);
- }
-
- p = di_devlink_path(devlink);
- q = strrchr(p, '/');
- usbi_dbg(NULL, "%s", q);
-
- *(larg->linkpp) = strndup(p, strlen(p) - strlen(q));
-
- return (DI_WALK_TERMINATE);
-}
-
-
-static int sunos_physpath_to_devlink(
- const char *node_path, const char *match, char **link_path)
-{
- walk_link_t larg;
- di_devlink_handle_t hdl;
-
- *link_path = NULL;
- larg.linkpp = link_path;
- if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
- usbi_dbg(NULL, "di_devlink_init failure");
- return (-1);
- }
-
- larg.len = strlen(node_path);
- larg.path = (char *)node_path;
-
- (void) di_devlink_walk(hdl, match, NULL, DI_PRIMARY_LINK,
- (void *)&larg, sunos_get_link);
-
- (void) di_devlink_fini(&hdl);
-
- if (*link_path == NULL) {
- usbi_dbg(NULL, "there is no devlink for this path");
- return (-1);
- }
-
- return 0;
-}
-
-static int
-sunos_usb_ioctl(struct libusb_device *dev, int cmd)
-{
- int fd;
- nvlist_t *nvlist;
- char *end;
- char *phypath;
- char *hubpath;
- char path_arg[PATH_MAX];
- sunos_dev_priv_t *dpriv;
- devctl_ap_state_t devctl_ap_state;
- struct devctl_iocdata iocdata;
-
- dpriv = usbi_get_device_priv(dev);
- phypath = dpriv->phypath;
-
- end = strrchr(phypath, '/');
- if (end == NULL)
- return (-1);
- hubpath = strndup(phypath, end - phypath);
- if (hubpath == NULL)
- return (-1);
-
- end = strrchr(hubpath, '@');
- if (end == NULL) {
- free(hubpath);
- return (-1);
- }
- end++;
- usbi_dbg(DEVICE_CTX(dev), "unitaddr: %s", end);
-
- nvlist_alloc(&nvlist, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
- nvlist_add_int32(nvlist, "port", dev->port_number);
- //find the hub path
- snprintf(path_arg, sizeof(path_arg), "/devices%s:hubd", hubpath);
- usbi_dbg(DEVICE_CTX(dev), "ioctl hub path: %s", path_arg);
-
- fd = open(path_arg, O_RDONLY);
- if (fd < 0) {
- usbi_err(DEVICE_CTX(dev), "open failed: errno %d (%s)", errno, strerror(errno));
- nvlist_free(nvlist);
- free(hubpath);
- return (-1);
- }
-
- memset(&iocdata, 0, sizeof(iocdata));
- memset(&devctl_ap_state, 0, sizeof(devctl_ap_state));
-
- nvlist_pack(nvlist, (char **)&iocdata.nvl_user, &iocdata.nvl_usersz, NV_ENCODE_NATIVE, 0);
-
- iocdata.cmd = DEVCTL_AP_GETSTATE;
- iocdata.flags = 0;
- iocdata.c_nodename = (char *)"hub";
- iocdata.c_unitaddr = end;
- iocdata.cpyout_buf = &devctl_ap_state;
- usbi_dbg(DEVICE_CTX(dev), "%p, %" PRIuPTR, iocdata.nvl_user, iocdata.nvl_usersz);
-
- errno = 0;
- if (ioctl(fd, DEVCTL_AP_GETSTATE, &iocdata) == -1) {
- usbi_err(DEVICE_CTX(dev), "ioctl failed: fd %d, cmd %x, errno %d (%s)",
- fd, DEVCTL_AP_GETSTATE, errno, strerror(errno));
- } else {
- usbi_dbg(DEVICE_CTX(dev), "dev rstate: %d", devctl_ap_state.ap_rstate);
- usbi_dbg(DEVICE_CTX(dev), "dev ostate: %d", devctl_ap_state.ap_ostate);
- }
-
- errno = 0;
- iocdata.cmd = cmd;
- if (ioctl(fd, (int)cmd, &iocdata) != 0) {
- usbi_err(DEVICE_CTX(dev), "ioctl failed: fd %d, cmd %x, errno %d (%s)",
- fd, cmd, errno, strerror(errno));
- sleep(2);
- }
-
- close(fd);
- free(iocdata.nvl_user);
- nvlist_free(nvlist);
- free(hubpath);
-
- return (-errno);
-}
-
-static int
-sunos_kernel_driver_active(struct libusb_device_handle *dev_handle, uint8_t interface)
-{
- sunos_dev_priv_t *dpriv = usbi_get_device_priv(dev_handle->dev);
-
- UNUSED(interface);
-
- usbi_dbg(HANDLE_CTX(dev_handle), "%s", dpriv->ugenpath);
-
- return (dpriv->ugenpath == NULL);
-}
-
-/*
- * Private functions
- */
-static int _errno_to_libusb(int);
-static int sunos_usb_get_status(struct libusb_context *ctx, int fd);
-
-static string_list_t *
-sunos_new_string_list(void)
-{
- string_list_t *list;
-
- list = calloc(1, sizeof(string_list_t));
- if (list == NULL)
- return (NULL);
- list->string = calloc(DEFAULT_LISTSIZE, sizeof(char *));
- if (list->string == NULL) {
- free(list);
- return (NULL);
- }
- list->nargs = 0;
- list->listsize = DEFAULT_LISTSIZE;
-
- return (list);
-}
-
-static int
-sunos_append_to_string_list(string_list_t *list, const char *arg)
-{
- char *str = strdup(arg);
-
- if (str == NULL)
- return (-1);
-
- if ((list->nargs + 1) == list->listsize) { /* +1 is for NULL */
- char **tmp = realloc(list->string,
- sizeof(char *) * (list->listsize + 1));
- if (tmp == NULL) {
- free(str);
- return (-1);
- }
- list->string = tmp;
- list->string[list->listsize++] = NULL;
- }
- list->string[list->nargs++] = str;
-
- return (0);
-}
-
-static void
-sunos_free_string_list(string_list_t *list)
-{
- int i;
-
- for (i = 0; i < list->nargs; i++) {
- free(list->string[i]);
- }
-
- free(list->string);
- free(list);
-}
-
-static char **
-sunos_build_argv_list(string_list_t *list)
-{
- return (list->string);
-}
-
-
-static int
-sunos_exec_command(struct libusb_context *ctx, const char *path,
- string_list_t *list)
-{
- pid_t pid;
- int status;
- int waitstat;
- int exit_status;
- char **argv_list;
-
- argv_list = sunos_build_argv_list(list);
- if (argv_list == NULL)
- return (-1);
-
- pid = fork();
- if (pid == 0) {
- /* child */
- execv(path, argv_list);
- _exit(127);
- } else if (pid > 0) {
- /* parent */
- do {
- waitstat = waitpid(pid, &status, 0);
- } while ((waitstat == -1 && errno == EINTR) ||
- (waitstat == 0 && !WIFEXITED(status) && !WIFSIGNALED(status)));
-
- if (waitstat == 0) {
- if (WIFEXITED(status))
- exit_status = WEXITSTATUS(status);
- else
- exit_status = WTERMSIG(status);
- } else {
- usbi_err(ctx, "waitpid failed: errno %d (%s)", errno, strerror(errno));
- exit_status = -1;
- }
- } else {
- /* fork failed */
- usbi_err(ctx, "fork failed: errno %d (%s)", errno, strerror(errno));
- exit_status = -1;
- }
-
- return (exit_status);
-}
-
-static int
-sunos_detach_kernel_driver(struct libusb_device_handle *dev_handle,
- uint8_t interface_number)
-{
- struct libusb_context *ctx = HANDLE_CTX(dev_handle);
- string_list_t *list;
- char path_arg[PATH_MAX];
- sunos_dev_priv_t *dpriv;
- int r;
-
- UNUSED(interface_number);
-
- dpriv = usbi_get_device_priv(dev_handle->dev);
- snprintf(path_arg, sizeof(path_arg), "\'\"%s\"\'", dpriv->phypath);
- usbi_dbg(HANDLE_CTX(dev_handle), "%s", path_arg);
-
- list = sunos_new_string_list();
- if (list == NULL)
- return (LIBUSB_ERROR_NO_MEM);
-
- /* attach ugen driver */
- r = 0;
- r |= sunos_append_to_string_list(list, UPDATEDRV);
- r |= sunos_append_to_string_list(list, "-a"); /* add rule */
- r |= sunos_append_to_string_list(list, "-i"); /* specific device */
- r |= sunos_append_to_string_list(list, path_arg); /* physical path */
- r |= sunos_append_to_string_list(list, "ugen");
- if (r) {
- sunos_free_string_list(list);
- return (LIBUSB_ERROR_NO_MEM);
- }
-
- r = sunos_exec_command(ctx, UPDATEDRV_PATH, list);
- sunos_free_string_list(list);
- if (r < 0)
- return (LIBUSB_ERROR_OTHER);
-
- /* reconfigure the driver node */
- r = 0;
- r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_DISCONNECT);
- r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
- if (r)
- usbi_warn(HANDLE_CTX(dev_handle), "one or more ioctls failed");
-
- snprintf(path_arg, sizeof(path_arg), "^usb/%x.%x",
- dev_handle->dev->device_descriptor.idVendor,
- dev_handle->dev->device_descriptor.idProduct);
- sunos_physpath_to_devlink(dpriv->phypath, path_arg, &dpriv->ugenpath);
-
- if (access(dpriv->ugenpath, F_OK) == -1) {
- usbi_err(HANDLE_CTX(dev_handle), "fail to detach kernel driver");
- return (LIBUSB_ERROR_IO);
- }
-
- return sunos_usb_open_ep0(usbi_get_device_handle_priv(dev_handle), dpriv);
-}
-
-static int
-sunos_attach_kernel_driver(struct libusb_device_handle *dev_handle,
- uint8_t interface_number)
-{
- struct libusb_context *ctx = HANDLE_CTX(dev_handle);
- string_list_t *list;
- char path_arg[PATH_MAX];
- sunos_dev_priv_t *dpriv;
- int r;
-
- UNUSED(interface_number);
-
- /* we open the dev in detach driver, so we need close it first. */
- sunos_close(dev_handle);
-
- dpriv = usbi_get_device_priv(dev_handle->dev);
- snprintf(path_arg, sizeof(path_arg), "\'\"%s\"\'", dpriv->phypath);
- usbi_dbg(HANDLE_CTX(dev_handle), "%s", path_arg);
-
- list = sunos_new_string_list();
- if (list == NULL)
- return (LIBUSB_ERROR_NO_MEM);
-
- /* detach ugen driver */
- r = 0;
- r |= sunos_append_to_string_list(list, UPDATEDRV);
- r |= sunos_append_to_string_list(list, "-d"); /* add rule */
- r |= sunos_append_to_string_list(list, "-i"); /* specific device */
- r |= sunos_append_to_string_list(list, path_arg); /* physical path */
- r |= sunos_append_to_string_list(list, "ugen");
- if (r) {
- sunos_free_string_list(list);
- return (LIBUSB_ERROR_NO_MEM);
- }
-
- r = sunos_exec_command(ctx, UPDATEDRV_PATH, list);
- sunos_free_string_list(list);
- if (r < 0)
- return (LIBUSB_ERROR_OTHER);
-
- /* reconfigure the driver node */
- r = 0;
- r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
- r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_DISCONNECT);
- r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
- if (r)
- usbi_warn(HANDLE_CTX(dev_handle), "one or more ioctls failed");
-
- return 0;
-}
-
-static int
-sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev)
-{
- int proplen;
- int *i, n, *addr, *port_prop;
- char *phypath;
- uint8_t *rdata;
- sunos_dev_priv_t *dpriv = usbi_get_device_priv(dev);
- char match_str[PATH_MAX];
-
- /* Device descriptors */
- proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
- "usb-dev-descriptor", &rdata);
- if (proplen <= 0) {
- return (LIBUSB_ERROR_IO);
- }
- bcopy(rdata, &dev->device_descriptor, LIBUSB_DT_DEVICE_SIZE);
-
- /* Raw configuration descriptors */
- proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
- "usb-raw-cfg-descriptors", &rdata);
- if (proplen <= 0) {
- usbi_dbg(DEVICE_CTX(dev), "can't find raw config descriptors");
-
- return (LIBUSB_ERROR_IO);
- }
- dpriv->raw_cfgdescr = calloc(1, proplen);
- if (dpriv->raw_cfgdescr == NULL) {
- return (LIBUSB_ERROR_NO_MEM);
- } else {
- bcopy(rdata, dpriv->raw_cfgdescr, proplen);
- dpriv->cfgvalue = ((struct libusb_config_descriptor *)
- rdata)->bConfigurationValue;
- }
-
- n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &port_prop);
-
- if ((n != 1) || (*port_prop <= 0)) {
- return (LIBUSB_ERROR_IO);
- }
- dev->port_number = *port_prop;
-
- /* device physical path */
- phypath = di_devfs_path(node);
- if (phypath) {
- dpriv->phypath = strdup(phypath);
- snprintf(match_str, sizeof(match_str), "^usb/%x.%x",
- dev->device_descriptor.idVendor,
- dev->device_descriptor.idProduct);
- usbi_dbg(DEVICE_CTX(dev), "match is %s", match_str);
- sunos_physpath_to_devlink(dpriv->phypath, match_str, &dpriv->ugenpath);
- di_devfs_path_free(phypath);
-
- } else {
- free(dpriv->raw_cfgdescr);
-
- return (LIBUSB_ERROR_IO);
- }
-
- /* address */
- n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "assigned-address", &addr);
- if (n != 1 || *addr == 0) {
- usbi_dbg(DEVICE_CTX(dev), "can't get address");
- } else {
- dev->device_address = *addr;
- }
-
- /* speed */
- if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "low-speed", &i) >= 0) {
- dev->speed = LIBUSB_SPEED_LOW;
- } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "high-speed", &i) >= 0) {
- dev->speed = LIBUSB_SPEED_HIGH;
- } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "full-speed", &i) >= 0) {
- dev->speed = LIBUSB_SPEED_FULL;
- } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "super-speed", &i) >= 0) {
- dev->speed = LIBUSB_SPEED_SUPER;
- }
-
- usbi_dbg(DEVICE_CTX(dev), "vid=%x pid=%x, path=%s, bus_nmber=0x%x, port_number=%d, speed=%d",
- dev->device_descriptor.idVendor, dev->device_descriptor.idProduct,
- dpriv->phypath, dev->bus_number, dev->port_number, dev->speed);
-
- return (LIBUSB_SUCCESS);
-}
-
-static int
-sunos_add_devices(di_devlink_t link, void *arg)
-{
- struct devlink_cbarg *largs = (struct devlink_cbarg *)arg;
- struct node_args *nargs;
- di_node_t myself, dn;
- uint64_t session_id = 0;
- uint64_t sid = 0;
- uint64_t bdf = 0;
- struct libusb_device *dev;
- sunos_dev_priv_t *devpriv;
- int n, *j;
- int i = 0;
- int *addr_prop;
- uint8_t bus_number = 0;
- uint32_t * regbuf = NULL;
- uint32_t reg;
-
- UNUSED(link);
-
- nargs = (struct node_args *)largs->nargs;
- myself = largs->myself;
-
- /*
- * Construct session ID.
- * session ID = dev_addr | hub addr |parent hub addr|...|root hub bdf
- * 8 bits 8bits 8 bits 16bits
- */
- if (myself == DI_NODE_NIL)
- return (DI_WALK_CONTINUE);
-
- dn = myself;
- /* find the root hub */
- while (di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "root-hub", &j) != 0) {
- usbi_dbg(NULL, "find_root_hub:%s", di_devfs_path(dn));
- n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn,
- "assigned-address", &addr_prop);
- session_id |= ((addr_prop[0] & 0xff) << i++ * 8);
- dn = di_parent_node(dn);
- }
-
- /* dn is the root hub node */
- n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "reg", (int **)&regbuf);
- reg = regbuf[0];
- bdf = (PCI_REG_BUS_G(reg) << 8) | (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
- /* bdf must larger than i*8 bits */
- session_id |= (bdf << i * 8);
- bus_number = (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
-
- usbi_dbg(NULL, "device bus address=%s:%x, name:%s",
- di_bus_addr(myself), bus_number, di_node_name(dn));
- usbi_dbg(NULL, "session id org:%" PRIx64, session_id);
-
- /* dn is the usb device */
- for (dn = di_child_node(myself); dn != DI_NODE_NIL; dn = di_sibling_node(dn)) {
- usbi_dbg(NULL, "device path:%s", di_devfs_path(dn));
- /* skip hub devices, because its driver can not been unload */
- if (di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "usb-port-count", &addr_prop) != -1)
- continue;
- /* usb_addr */
- n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn,
- "assigned-address", &addr_prop);
- if ((n != 1) || (addr_prop[0] == 0)) {
- usbi_dbg(NULL, "cannot get valid usb_addr");
- continue;
- }
-
- sid = (session_id << 8) | (addr_prop[0] & 0xff) ;
- usbi_dbg(NULL, "session id %" PRIX64, sid);
-
- dev = usbi_get_device_by_session_id(nargs->ctx, sid);
- if (dev == NULL) {
- dev = usbi_alloc_device(nargs->ctx, sid);
- if (dev == NULL) {
- usbi_dbg(NULL, "can't alloc device");
- continue;
- }
- devpriv = usbi_get_device_priv(dev);
- dev->bus_number = bus_number;
-
- if (sunos_fill_in_dev_info(dn, dev) != LIBUSB_SUCCESS) {
- libusb_unref_device(dev);
- usbi_dbg(NULL, "get information fail");
- continue;
- }
- if (usbi_sanitize_device(dev) < 0) {
- libusb_unref_device(dev);
- usbi_dbg(NULL, "sanatize failed: ");
- return (DI_WALK_TERMINATE);
- }
- } else {
- devpriv = usbi_get_device_priv(dev);
- usbi_dbg(NULL, "Dev %s exists", devpriv->ugenpath);
- }
-
- if (discovered_devs_append(*(nargs->discdevs), dev) == NULL) {
- usbi_dbg(NULL, "cannot append device");
- }
-
- /*
- * we alloc and hence ref this dev. We don't need to ref it
- * hereafter. Front end or app should take care of their ref.
- */
- libusb_unref_device(dev);
-
- usbi_dbg(NULL, "Device %s %s id=0x%" PRIx64 ", devcount:%" PRIuPTR
- ", bdf=%" PRIx64,
- devpriv->ugenpath, di_devfs_path(dn), (uint64_t)sid,
- (*nargs->discdevs)->len, bdf);
- }
-
- return (DI_WALK_CONTINUE);
-}
-
-static int
-sunos_walk_minor_node_link(di_node_t node, void *args)
-{
- di_minor_t minor = DI_MINOR_NIL;
- char *minor_path;
- struct devlink_cbarg arg;
- struct node_args *nargs = (struct node_args *)args;
- di_devlink_handle_t devlink_hdl = nargs->dlink_hdl;
-
- /* walk each minor to find usb devices */
- while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
- minor_path = di_devfs_minor_path(minor);
- arg.nargs = args;
- arg.myself = node;
- arg.minor = minor;
- (void) di_devlink_walk(devlink_hdl,
- "^usb/hub[0-9]+", minor_path,
- DI_PRIMARY_LINK, (void *)&arg, sunos_add_devices);
- di_devfs_path_free(minor_path);
- }
-
- /* switch to a different node */
- nargs->last_ugenpath = NULL;
-
- return (DI_WALK_CONTINUE);
-}
-
-int
-sunos_get_device_list(struct libusb_context * ctx,
- struct discovered_devs **discdevs)
-{
- di_node_t root_node;
- struct node_args args;
- di_devlink_handle_t devlink_hdl;
-
- args.ctx = ctx;
- args.discdevs = discdevs;
- args.last_ugenpath = NULL;
- if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
- usbi_dbg(ctx, "di_int() failed: errno %d (%s)", errno, strerror(errno));
- return (LIBUSB_ERROR_IO);
- }
-
- if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
- di_fini(root_node);
- usbi_dbg(ctx, "di_devlink_init() failed: errno %d (%s)", errno, strerror(errno));
-
- return (LIBUSB_ERROR_IO);
- }
- args.dlink_hdl = devlink_hdl;
-
- /* walk each node to find USB devices */
- if (di_walk_node(root_node, DI_WALK_SIBFIRST, &args,
- sunos_walk_minor_node_link) == -1) {
- usbi_dbg(ctx, "di_walk_node() failed: errno %d (%s)", errno, strerror(errno));
- di_fini(root_node);
-
- return (LIBUSB_ERROR_IO);
- }
-
- di_fini(root_node);
- di_devlink_fini(&devlink_hdl);
-
- usbi_dbg(ctx, "%zu devices", (*discdevs)->len);
-
- return ((*discdevs)->len);
-}
-
-static int
-sunos_usb_open_ep0(sunos_dev_handle_priv_t *hpriv, sunos_dev_priv_t *dpriv)
-{
- char filename[PATH_MAX + 1];
-
- if (hpriv->eps[0].datafd > 0) {
- return (LIBUSB_SUCCESS);
- }
- snprintf(filename, PATH_MAX, "%s/cntrl0", dpriv->ugenpath);
-
- usbi_dbg(NULL, "opening %s", filename);
- hpriv->eps[0].datafd = open(filename, O_RDWR);
- if (hpriv->eps[0].datafd < 0) {
- return(_errno_to_libusb(errno));
- }
-
- snprintf(filename, PATH_MAX, "%s/cntrl0stat", dpriv->ugenpath);
- hpriv->eps[0].statfd = open(filename, O_RDONLY);
- if (hpriv->eps[0].statfd < 0) {
- close(hpriv->eps[0].datafd);
- hpriv->eps[0].datafd = -1;
-
- return(_errno_to_libusb(errno));
- }
-
- return (LIBUSB_SUCCESS);
-}
-
-static void
-sunos_usb_close_all_eps(sunos_dev_handle_priv_t *hdev)
-{
- int i;
-
- /* not close ep0 */
- for (i = 1; i < USB_MAXENDPOINTS; i++) {
- if (hdev->eps[i].datafd != -1) {
- (void) close(hdev->eps[i].datafd);
- hdev->eps[i].datafd = -1;
- }
- if (hdev->eps[i].statfd != -1) {
- (void) close(hdev->eps[i].statfd);
- hdev->eps[i].statfd = -1;
- }
- }
-}
-
-static void
-sunos_usb_close_ep0(sunos_dev_handle_priv_t *hdev)
-{
- if (hdev->eps[0].datafd >= 0) {
- close(hdev->eps[0].datafd);
- close(hdev->eps[0].statfd);
- hdev->eps[0].datafd = -1;
- hdev->eps[0].statfd = -1;
- }
-}
-
-static uchar_t
-sunos_usb_ep_index(uint8_t ep_addr)
-{
- return ((ep_addr & LIBUSB_ENDPOINT_ADDRESS_MASK) +
- ((ep_addr & LIBUSB_ENDPOINT_DIR_MASK) ? 16 : 0));
-}
-
-static int
-sunos_find_interface(struct libusb_device_handle *hdev,
- uint8_t endpoint, uint8_t *interface)
-{
- struct libusb_config_descriptor *config;
- int r;
- int iface_idx;
-
- r = libusb_get_active_config_descriptor(hdev->dev, &config);
- if (r < 0) {
- return (LIBUSB_ERROR_INVALID_PARAM);
- }
-
- for (iface_idx = 0; iface_idx < config->bNumInterfaces; iface_idx++) {
- const struct libusb_interface *iface =
- &config->interface[iface_idx];
- int altsetting_idx;
-
- for (altsetting_idx = 0; altsetting_idx < iface->num_altsetting;
- altsetting_idx++) {
- const struct libusb_interface_descriptor *altsetting =
- &iface->altsetting[altsetting_idx];
- int ep_idx;
-
- for (ep_idx = 0; ep_idx < altsetting->bNumEndpoints;
- ep_idx++) {
- const struct libusb_endpoint_descriptor *ep =
- &altsetting->endpoint[ep_idx];
- if (ep->bEndpointAddress == endpoint) {
- *interface = iface_idx;
- libusb_free_config_descriptor(config);
-
- return (LIBUSB_SUCCESS);
- }
- }
- }
- }
- libusb_free_config_descriptor(config);
-
- return (LIBUSB_ERROR_INVALID_PARAM);
-}
-
-static int
-sunos_check_device_and_status_open(struct libusb_device_handle *hdl,
- uint8_t ep_addr, int ep_type)
-{
- char filename[PATH_MAX + 1], statfilename[PATH_MAX + 1];
- char cfg_num[16], alt_num[16];
- int fd, fdstat, mode;
- uint8_t ifc = 0;
- uint8_t ep_index;
- sunos_dev_handle_priv_t *hpriv;
-
- usbi_dbg(HANDLE_CTX(hdl), "open ep 0x%02x", ep_addr);
- hpriv = usbi_get_device_handle_priv(hdl);
- ep_index = sunos_usb_ep_index(ep_addr);
- /* ep already opened */
- if ((hpriv->eps[ep_index].datafd > 0) &&
- (hpriv->eps[ep_index].statfd > 0)) {
- usbi_dbg(HANDLE_CTX(hdl), "ep 0x%02x already opened, return success",
- ep_addr);
-
- return (0);
- }
-
- if (sunos_find_interface(hdl, ep_addr, &ifc) < 0) {
- usbi_dbg(HANDLE_CTX(hdl), "can't find interface for endpoint 0x%02x",
- ep_addr);
-
- return (EACCES);
- }
-
- /* create filename */
- if (hpriv->config_index > 0) {
- (void) snprintf(cfg_num, sizeof(cfg_num), "cfg%d",
- hpriv->config_index + 1);
- } else {
- bzero(cfg_num, sizeof(cfg_num));
- }
-
- if (hpriv->altsetting[ifc] > 0) {
- (void) snprintf(alt_num, sizeof(alt_num), ".%d",
- hpriv->altsetting[ifc]);
- } else {
- bzero(alt_num, sizeof(alt_num));
- }
-
- (void) snprintf(filename, PATH_MAX, "%s/%sif%d%s%s%d",
- hpriv->dpriv->ugenpath, cfg_num, ifc, alt_num,
- (ep_addr & LIBUSB_ENDPOINT_DIR_MASK) ? "in" :
- "out", (ep_addr & LIBUSB_ENDPOINT_ADDRESS_MASK));
- (void) snprintf(statfilename, PATH_MAX, "%sstat", filename);
-
- /*
- * In case configuration has been switched, the xfer endpoint needs
- * to be opened before the status endpoint, due to a ugen issue.
- * However, to enable the one transfer mode for an Interrupt-In pipe,
- * the status endpoint needs to be opened before the xfer endpoint.
- * So, open the xfer mode first and close it immediately
- * as a workaround. This will handle the configuration switch.
- * Then, open the status endpoint. If for an Interrupt-in pipe,
- * write the USB_EP_INTR_ONE_XFER control to the status endpoint
- * to enable the one transfer mode. Then, re-open the xfer mode.
- */
- if (ep_type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
- mode = O_RDWR;
- } else if (ep_addr & LIBUSB_ENDPOINT_IN) {
- mode = O_RDONLY;
- } else {
- mode = O_WRONLY;
- }
- /* Open the xfer endpoint first */
- if ((fd = open(filename, mode)) == -1) {
- usbi_dbg(HANDLE_CTX(hdl), "can't open %s: errno %d (%s)", filename, errno,
- strerror(errno));
-
- return (errno);
- }
- /* And immediately close the xfer endpoint */
- (void) close(fd);
-
- /*
- * Open the status endpoint.
- * If for an Interrupt-IN pipe, need to enable the one transfer mode
- * by writing USB_EP_INTR_ONE_XFER control to the status endpoint
- * before opening the xfer endpoint
- */
- if ((ep_type == LIBUSB_TRANSFER_TYPE_INTERRUPT) &&
- (ep_addr & LIBUSB_ENDPOINT_IN)) {
- char control = USB_EP_INTR_ONE_XFER;
- ssize_t count;
-
- /* Open the status endpoint with RDWR */
- if ((fdstat = open(statfilename, O_RDWR)) == -1) {
- usbi_dbg(HANDLE_CTX(hdl), "can't open %s RDWR: errno %d (%s)",
- statfilename, errno, strerror(errno));
-
- return (errno);
- } else {
- count = write(fdstat, &control, sizeof(control));
- if (count != 1) {
- /* this should have worked */
- usbi_dbg(HANDLE_CTX(hdl), "can't write to %s: errno %d (%s)",
- statfilename, errno, strerror(errno));
- (void) close(fdstat);
-
- return (errno);
- }
- }
- } else {
- if ((fdstat = open(statfilename, O_RDONLY)) == -1) {
- usbi_dbg(HANDLE_CTX(hdl), "can't open %s: errno %d (%s)", statfilename, errno,
- strerror(errno));
-
- return (errno);
- }
- }
-
- /* Re-open the xfer endpoint */
- if ((fd = open(filename, mode)) == -1) {
- usbi_dbg(HANDLE_CTX(hdl), "can't open %s: errno %d (%s)", filename, errno,
- strerror(errno));
- (void) close(fdstat);
-
- return (errno);
- }
-
- hpriv->eps[ep_index].datafd = fd;
- hpriv->eps[ep_index].statfd = fdstat;
- usbi_dbg(HANDLE_CTX(hdl), "ep=0x%02x datafd=%d, statfd=%d", ep_addr, fd, fdstat);
-
- return (0);
-}
-
-int
-sunos_open(struct libusb_device_handle *handle)
-{
- sunos_dev_handle_priv_t *hpriv;
- sunos_dev_priv_t *dpriv;
- int i;
- int ret;
-
- hpriv = usbi_get_device_handle_priv(handle);
- dpriv = usbi_get_device_priv(handle->dev);
- hpriv->dpriv = dpriv;
-
- /* set all file descriptors to "closed" */
- for (i = 0; i < USB_MAXENDPOINTS; i++) {
- hpriv->eps[i].datafd = -1;
- hpriv->eps[i].statfd = -1;
- }
-
- if (sunos_kernel_driver_active(handle, 0)) {
- /* pretend we can open the device */
- return (LIBUSB_SUCCESS);
- }
-
- if ((ret = sunos_usb_open_ep0(hpriv, dpriv)) != LIBUSB_SUCCESS) {
- usbi_dbg(HANDLE_CTX(handle), "fail: %d", ret);
- return (ret);
- }
-
- return (LIBUSB_SUCCESS);
-}
-
-void
-sunos_close(struct libusb_device_handle *handle)
-{
- sunos_dev_handle_priv_t *hpriv;
-
- usbi_dbg(HANDLE_CTX(handle), " ");
-
- hpriv = usbi_get_device_handle_priv(handle);
-
- sunos_usb_close_all_eps(hpriv);
- sunos_usb_close_ep0(hpriv);
-}
-
-int
-sunos_get_active_config_descriptor(struct libusb_device *dev,
- void *buf, size_t len)
-{
- sunos_dev_priv_t *dpriv = usbi_get_device_priv(dev);
- struct libusb_config_descriptor *cfg;
- int proplen;
- di_node_t node;
- uint8_t *rdata;
-
- /*
- * Keep raw configuration descriptors updated, in case config
- * has ever been changed through setCfg.
- */
- if ((node = di_init(dpriv->phypath, DINFOCPYALL)) == DI_NODE_NIL) {
- usbi_dbg(DEVICE_CTX(dev), "di_int() failed: errno %d (%s)", errno,
- strerror(errno));
- return (LIBUSB_ERROR_IO);
- }
- proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
- "usb-raw-cfg-descriptors", &rdata);
- if (proplen <= 0) {
- usbi_dbg(DEVICE_CTX(dev), "can't find raw config descriptors");
-
- return (LIBUSB_ERROR_IO);
- }
- dpriv->raw_cfgdescr = realloc(dpriv->raw_cfgdescr, proplen);
- if (dpriv->raw_cfgdescr == NULL) {
- return (LIBUSB_ERROR_NO_MEM);
- } else {
- bcopy(rdata, dpriv->raw_cfgdescr, proplen);
- dpriv->cfgvalue = ((struct libusb_config_descriptor *)
- rdata)->bConfigurationValue;
- }
- di_fini(node);
-
- cfg = (struct libusb_config_descriptor *)dpriv->raw_cfgdescr;
- len = MIN(len, libusb_le16_to_cpu(cfg->wTotalLength));
- memcpy(buf, dpriv->raw_cfgdescr, len);
- usbi_dbg(DEVICE_CTX(dev), "path:%s len %zu", dpriv->phypath, len);
-
- return (len);
-}
-
-int
-sunos_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
- void *buf, size_t len)
-{
- UNUSED(idx);
- /* XXX */
- return(sunos_get_active_config_descriptor(dev, buf, len));
-}
-
-int
-sunos_get_configuration(struct libusb_device_handle *handle, uint8_t *config)
-{
- sunos_dev_priv_t *dpriv = usbi_get_device_priv(handle->dev);
-
- *config = dpriv->cfgvalue;
-
- usbi_dbg(HANDLE_CTX(handle), "bConfigurationValue %u", *config);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-sunos_set_configuration(struct libusb_device_handle *handle, int config)
-{
- sunos_dev_priv_t *dpriv = usbi_get_device_priv(handle->dev);
- sunos_dev_handle_priv_t *hpriv;
-
- usbi_dbg(HANDLE_CTX(handle), "bConfigurationValue %d", config);
- hpriv = usbi_get_device_handle_priv(handle);
-
- if (dpriv->ugenpath == NULL)
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-
- if (config < 1)
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-
- dpriv->cfgvalue = config;
- hpriv->config_index = config - 1;
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-sunos_claim_interface(struct libusb_device_handle *handle, uint8_t iface)
-{
- UNUSED(handle);
-
- usbi_dbg(HANDLE_CTX(handle), "iface %u", iface);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-sunos_release_interface(struct libusb_device_handle *handle, uint8_t iface)
-{
- sunos_dev_handle_priv_t *hpriv = usbi_get_device_handle_priv(handle);
-
- usbi_dbg(HANDLE_CTX(handle), "iface %u", iface);
-
- /* XXX: can we release it? */
- hpriv->altsetting[iface] = 0;
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-sunos_set_interface_altsetting(struct libusb_device_handle *handle, uint8_t iface,
- uint8_t altsetting)
-{
- sunos_dev_priv_t *dpriv = usbi_get_device_priv(handle->dev);
- sunos_dev_handle_priv_t *hpriv = usbi_get_device_handle_priv(handle);
-
- usbi_dbg(HANDLE_CTX(handle), "iface %u, setting %u", iface, altsetting);
-
- if (dpriv->ugenpath == NULL)
- return (LIBUSB_ERROR_NOT_FOUND);
-
- /* XXX: can we switch altsetting? */
- hpriv->altsetting[iface] = altsetting;
-
- return (LIBUSB_SUCCESS);
-}
-
-static void
-usb_dump_data(const void *data, size_t size)
-{
- const uint8_t *p = data;
- size_t i;
-
- if (getenv("LIBUSB_DEBUG") == NULL) {
- return;
- }
-
- (void) fprintf(stderr, "data dump:");
- for (i = 0; i < size; i++) {
- if (i % 16 == 0) {
- (void) fprintf(stderr, "\n%08zx ", i);
- }
- (void) fprintf(stderr, "%02x ", p[i]);
- }
- (void) fprintf(stderr, "\n");
-}
-
-static void
-sunos_async_callback(union sigval arg)
-{
- struct sunos_transfer_priv *tpriv =
- (struct sunos_transfer_priv *)arg.sival_ptr;
- struct libusb_transfer *xfer = tpriv->transfer;
- struct aiocb *aiocb = &tpriv->aiocb;
- int ret;
- sunos_dev_handle_priv_t *hpriv;
- uint8_t ep;
- libusb_device_handle *dev_handle;
-
- dev_handle = xfer->dev_handle;
-
- /* libusb can forcibly interrupt transfer in do_close() */
- if (dev_handle != NULL) {
- hpriv = usbi_get_device_handle_priv(dev_handle);
- ep = sunos_usb_ep_index(xfer->endpoint);
-
- ret = aio_error(aiocb);
- if (ret != 0) {
- xfer->status = sunos_usb_get_status(TRANSFER_CTX(xfer), hpriv->eps[ep].statfd);
- } else {
- xfer->actual_length =
- LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer)->transferred =
- aio_return(aiocb);
- }
-
- usb_dump_data(xfer->buffer, xfer->actual_length);
-
- usbi_dbg(TRANSFER_CTX(xfer), "ret=%d, len=%d, actual_len=%d", ret, xfer->length,
- xfer->actual_length);
-
- /* async notification */
- usbi_signal_transfer_completion(LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer));
- }
-}
-
-static int
-sunos_do_async_io(struct libusb_transfer *transfer)
-{
- int ret = -1;
- struct aiocb *aiocb;
- sunos_dev_handle_priv_t *hpriv;
- uint8_t ep;
- struct sunos_transfer_priv *tpriv;
-
- usbi_dbg(TRANSFER_CTX(transfer), " ");
-
- tpriv = usbi_get_transfer_priv(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer));
- hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
- ep = sunos_usb_ep_index(transfer->endpoint);
-
- tpriv->transfer = transfer;
- aiocb = &tpriv->aiocb;
- bzero(aiocb, sizeof(*aiocb));
- aiocb->aio_fildes = hpriv->eps[ep].datafd;
- aiocb->aio_buf = transfer->buffer;
- aiocb->aio_nbytes = transfer->length;
- aiocb->aio_lio_opcode =
- ((transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK) ==
- LIBUSB_ENDPOINT_IN) ? LIO_READ:LIO_WRITE;
- aiocb->aio_sigevent.sigev_notify = SIGEV_THREAD;
- aiocb->aio_sigevent.sigev_value.sival_ptr = tpriv;
- aiocb->aio_sigevent.sigev_notify_function = sunos_async_callback;
-
- if (aiocb->aio_lio_opcode == LIO_READ) {
- ret = aio_read(aiocb);
- } else {
- ret = aio_write(aiocb);
- }
-
- return (ret);
-}
-
-/* return the number of bytes read/written */
-static ssize_t
-usb_do_io(struct libusb_context *ctx, int fd, int stat_fd, void *data, size_t size, int flag, int *status)
-{
- int error;
- ssize_t ret = -1;
-
- usbi_dbg(ctx, "usb_do_io(): datafd=%d statfd=%d size=0x%zx flag=%s",
- fd, stat_fd, size, flag? "WRITE":"READ");
-
- switch (flag) {
- case READ:
- errno = 0;
- ret = read(fd, data, size);
- usb_dump_data(data, size);
- break;
- case WRITE:
- usb_dump_data(data, size);
- errno = 0;
- ret = write(fd, data, size);
- break;
- }
-
- usbi_dbg(ctx, "usb_do_io(): amount=%zd", ret);
-
- if (ret < 0) {
- int save_errno = errno;
-
- usbi_dbg(ctx, "TID=%x io %s errno %d (%s)", pthread_self(),
- flag?"WRITE":"READ", errno, strerror(errno));
-
- /* sunos_usb_get_status will do a read and overwrite errno */
- error = sunos_usb_get_status(ctx, stat_fd);
- usbi_dbg(ctx, "io status=%d errno %d (%s)", error,
- save_errno, strerror(save_errno));
-
- if (status) {
- *status = save_errno;
- }
-
- return (save_errno);
-
- } else if (status) {
- *status = 0;
- }
-
- return (ret);
-}
-
-static int
-solaris_submit_ctrl_on_default(struct libusb_transfer *transfer)
-{
- ssize_t ret = -1, setup_ret;
- int status;
- sunos_dev_handle_priv_t *hpriv;
- struct libusb_device_handle *hdl = transfer->dev_handle;
- uint16_t wLength;
- uint8_t *data = transfer->buffer;
-
- hpriv = usbi_get_device_handle_priv(hdl);
- wLength = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
-
- if (hpriv->eps[0].datafd == -1) {
- usbi_dbg(TRANSFER_CTX(transfer), "ep0 not opened");
-
- return (LIBUSB_ERROR_NOT_FOUND);
- }
-
- if ((data[0] & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) {
- usbi_dbg(TRANSFER_CTX(transfer), "IN request");
- ret = usb_do_io(TRANSFER_CTX(transfer), hpriv->eps[0].datafd,
- hpriv->eps[0].statfd, data, LIBUSB_CONTROL_SETUP_SIZE,
- WRITE, &status);
- } else {
- usbi_dbg(TRANSFER_CTX(transfer), "OUT request");
- ret = usb_do_io(TRANSFER_CTX(transfer), hpriv->eps[0].datafd, hpriv->eps[0].statfd,
- transfer->buffer, transfer->length, WRITE,
- (int *)&transfer->status);
- }
-
- setup_ret = ret;
- if (ret < (ssize_t)LIBUSB_CONTROL_SETUP_SIZE) {
- usbi_dbg(TRANSFER_CTX(transfer), "error sending control msg: %zd", ret);
-
- return (LIBUSB_ERROR_IO);
- }
-
- ret = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
-
- /* Read the remaining bytes for IN request */
- if ((wLength) && ((data[0] & LIBUSB_ENDPOINT_DIR_MASK) ==
- LIBUSB_ENDPOINT_IN)) {
- usbi_dbg(TRANSFER_CTX(transfer), "DATA: %d", transfer->length - (int)setup_ret);
- ret = usb_do_io(TRANSFER_CTX(transfer), hpriv->eps[0].datafd,
- hpriv->eps[0].statfd,
- transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE,
- wLength, READ, (int *)&transfer->status);
- }
-
- if (ret >= 0) {
- LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->transferred = ret;
- }
- usbi_dbg(TRANSFER_CTX(transfer), "Done: ctrl data bytes %zd", ret);
-
- /**
- * Sync transfer handling.
- * We should release transfer lock here and later get it back
- * as usbi_handle_transfer_completion() takes its own transfer lock.
- */
- usbi_mutex_unlock(&LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->lock);
- ret = usbi_handle_transfer_completion(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer),
- transfer->status);
- usbi_mutex_lock(&LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->lock);
-
- return (ret);
-}
-
-int
-sunos_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
-{
- int ret;
-
- usbi_dbg(HANDLE_CTX(handle), "endpoint=0x%02x", endpoint);
-
- ret = libusb_control_transfer(handle, LIBUSB_ENDPOINT_OUT |
- LIBUSB_RECIPIENT_ENDPOINT | LIBUSB_REQUEST_TYPE_STANDARD,
- LIBUSB_REQUEST_CLEAR_FEATURE, 0, endpoint, NULL, 0, 1000);
-
- usbi_dbg(HANDLE_CTX(handle), "ret=%d", ret);
-
- return (ret);
-}
-
-void
-sunos_destroy_device(struct libusb_device *dev)
-{
- sunos_dev_priv_t *dpriv = usbi_get_device_priv(dev);
-
- usbi_dbg(DEVICE_CTX(dev), "destroy everything");
- free(dpriv->raw_cfgdescr);
- free(dpriv->ugenpath);
- free(dpriv->phypath);
-}
-
-int
-sunos_submit_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer;
- struct libusb_device_handle *hdl;
- int err = 0;
-
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- hdl = transfer->dev_handle;
-
- err = sunos_check_device_and_status_open(hdl,
- transfer->endpoint, transfer->type);
- if (err < 0) {
-
- return (_errno_to_libusb(err));
- }
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- /* sync transfer */
- usbi_dbg(ITRANSFER_CTX(itransfer), "CTRL transfer: %d", transfer->length);
- err = solaris_submit_ctrl_on_default(transfer);
- break;
-
- case LIBUSB_TRANSFER_TYPE_BULK:
- /* fallthru */
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- if (transfer->type == LIBUSB_TRANSFER_TYPE_BULK)
- usbi_dbg(ITRANSFER_CTX(itransfer), "BULK transfer: %d", transfer->length);
- else
- usbi_dbg(ITRANSFER_CTX(itransfer), "INTR transfer: %d", transfer->length);
- err = sunos_do_async_io(transfer);
- break;
-
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- /* Isochronous/Stream is not supported */
-
- /* fallthru */
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS)
- usbi_dbg(ITRANSFER_CTX(itransfer), "ISOC transfer: %d", transfer->length);
- else
- usbi_dbg(ITRANSFER_CTX(itransfer), "BULK STREAM transfer: %d", transfer->length);
- err = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
-
- return (err);
-}
-
-int
-sunos_cancel_transfer(struct usbi_transfer *itransfer)
-{
- sunos_xfer_priv_t *tpriv;
- sunos_dev_handle_priv_t *hpriv;
- struct libusb_transfer *transfer;
- struct aiocb *aiocb;
- uint8_t ep;
- int ret;
-
- tpriv = usbi_get_transfer_priv(itransfer);
- aiocb = &tpriv->aiocb;
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
- ep = sunos_usb_ep_index(transfer->endpoint);
-
- ret = aio_cancel(hpriv->eps[ep].datafd, aiocb);
-
- usbi_dbg(ITRANSFER_CTX(itransfer), "aio->fd=%d fd=%d ret = %d, %s", aiocb->aio_fildes,
- hpriv->eps[ep].datafd, ret, (ret == AIO_CANCELED)?
- strerror(0):strerror(errno));
-
- if (ret != AIO_CANCELED) {
- ret = _errno_to_libusb(errno);
- } else {
- /*
- * we don't need to call usbi_handle_transfer_cancellation(),
- * because we'll handle everything in sunos_async_callback.
- */
- ret = LIBUSB_SUCCESS;
- }
-
- return (ret);
-}
-
-int
-sunos_handle_transfer_completion(struct usbi_transfer *itransfer)
-{
- return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
-}
-
-int
-_errno_to_libusb(int err)
-{
- usbi_dbg(NULL, "error: %s (%d)", strerror(err), err);
-
- switch (err) {
- case EIO:
- return (LIBUSB_ERROR_IO);
- case EACCES:
- return (LIBUSB_ERROR_ACCESS);
- case ENOENT:
- return (LIBUSB_ERROR_NO_DEVICE);
- case ENOMEM:
- return (LIBUSB_ERROR_NO_MEM);
- case ETIMEDOUT:
- return (LIBUSB_ERROR_TIMEOUT);
- }
-
- return (LIBUSB_ERROR_OTHER);
-}
-
-/*
- * sunos_usb_get_status:
- * gets status of endpoint
- *
- * Returns: ugen's last cmd status
- */
-static int
-sunos_usb_get_status(struct libusb_context *ctx, int fd)
-{
- int status;
- ssize_t ret;
-
- usbi_dbg(ctx, "sunos_usb_get_status(): fd=%d", fd);
-
- ret = read(fd, &status, sizeof(status));
- if (ret == sizeof(status)) {
- switch (status) {
- case USB_LC_STAT_NOERROR:
- usbi_dbg(ctx, "No Error");
- break;
- case USB_LC_STAT_CRC:
- usbi_dbg(ctx, "CRC Timeout Detected\n");
- break;
- case USB_LC_STAT_BITSTUFFING:
- usbi_dbg(ctx, "Bit Stuffing Violation\n");
- break;
- case USB_LC_STAT_DATA_TOGGLE_MM:
- usbi_dbg(ctx, "Data Toggle Mismatch\n");
- break;
- case USB_LC_STAT_STALL:
- usbi_dbg(ctx, "End Point Stalled\n");
- break;
- case USB_LC_STAT_DEV_NOT_RESP:
- usbi_dbg(ctx, "Device is Not Responding\n");
- break;
- case USB_LC_STAT_PID_CHECKFAILURE:
- usbi_dbg(ctx, "PID Check Failure\n");
- break;
- case USB_LC_STAT_UNEXP_PID:
- usbi_dbg(ctx, "Unexpected PID\n");
- break;
- case USB_LC_STAT_DATA_OVERRUN:
- usbi_dbg(ctx, "Data Exceeded Size\n");
- break;
- case USB_LC_STAT_DATA_UNDERRUN:
- usbi_dbg(ctx, "Less data received\n");
- break;
- case USB_LC_STAT_BUFFER_OVERRUN:
- usbi_dbg(ctx, "Buffer Size Exceeded\n");
- break;
- case USB_LC_STAT_BUFFER_UNDERRUN:
- usbi_dbg(ctx, "Buffer Underrun\n");
- break;
- case USB_LC_STAT_TIMEOUT:
- usbi_dbg(ctx, "Command Timed Out\n");
- break;
- case USB_LC_STAT_NOT_ACCESSED:
- usbi_dbg(ctx, "Not Accessed by h/w\n");
- break;
- case USB_LC_STAT_UNSPECIFIED_ERR:
- usbi_dbg(ctx, "Unspecified Error\n");
- break;
- case USB_LC_STAT_NO_BANDWIDTH:
- usbi_dbg(ctx, "No Bandwidth\n");
- break;
- case USB_LC_STAT_HW_ERR:
- usbi_dbg(ctx, "Host Controller h/w Error\n");
- break;
- case USB_LC_STAT_SUSPENDED:
- usbi_dbg(ctx, "Device was Suspended\n");
- break;
- case USB_LC_STAT_DISCONNECTED:
- usbi_dbg(ctx, "Device was Disconnected\n");
- break;
- case USB_LC_STAT_INTR_BUF_FULL:
- usbi_dbg(ctx, "Interrupt buffer was full\n");
- break;
- case USB_LC_STAT_INVALID_REQ:
- usbi_dbg(ctx, "Request was Invalid\n");
- break;
- case USB_LC_STAT_INTERRUPTED:
- usbi_dbg(ctx, "Request was Interrupted\n");
- break;
- case USB_LC_STAT_NO_RESOURCES:
- usbi_dbg(ctx, "No resources available for "
- "request\n");
- break;
- case USB_LC_STAT_INTR_POLLING_FAILED:
- usbi_dbg(ctx, "Failed to Restart Poll");
- break;
- default:
- usbi_dbg(ctx, "Error Not Determined %d\n",
- status);
- break;
- }
- } else {
- usbi_dbg(ctx, "read stat error: %s",strerror(errno));
- status = -1;
- }
-
- return (status);
-}
-
-const struct usbi_os_backend usbi_backend = {
- .name = "Solaris",
- .caps = 0,
- .get_device_list = sunos_get_device_list,
- .get_active_config_descriptor = sunos_get_active_config_descriptor,
- .get_config_descriptor = sunos_get_config_descriptor,
- .open = sunos_open,
- .close = sunos_close,
- .get_configuration = sunos_get_configuration,
- .set_configuration = sunos_set_configuration,
- .claim_interface = sunos_claim_interface,
- .release_interface = sunos_release_interface,
- .set_interface_altsetting = sunos_set_interface_altsetting,
- .clear_halt = sunos_clear_halt,
- .kernel_driver_active = sunos_kernel_driver_active,
- .detach_kernel_driver = sunos_detach_kernel_driver,
- .attach_kernel_driver = sunos_attach_kernel_driver,
- .destroy_device = sunos_destroy_device,
- .submit_transfer = sunos_submit_transfer,
- .cancel_transfer = sunos_cancel_transfer,
- .handle_transfer_completion = sunos_handle_transfer_completion,
- .device_priv_size = sizeof(sunos_dev_priv_t),
- .device_handle_priv_size = sizeof(sunos_dev_handle_priv_t),
- .transfer_priv_size = sizeof(sunos_xfer_priv_t),
-};
diff --git a/src/os/sunos_usb.h b/src/os/sunos_usb.h
deleted file mode 100644
index 2988398..0000000
--- a/src/os/sunos_usb.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- *
- * Copyright (c) 2016, Oracle and/or its affiliates.
- *
- * 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_SUNOS_H
-#define LIBUSB_SUNOS_H
-
-#include <libdevinfo.h>
-#include <pthread.h>
-#include "libusbi.h"
-
-#define READ 0
-#define WRITE 1
-
-typedef struct sunos_device_priv {
- uint8_t cfgvalue; /* active config value */
- uint8_t *raw_cfgdescr; /* active config descriptor */
- char *ugenpath; /* name of the ugen(4) node */
- char *phypath; /* physical path */
-} sunos_dev_priv_t;
-
-typedef struct endpoint {
- int datafd; /* data file */
- int statfd; /* state file */
-} sunos_ep_priv_t;
-
-typedef struct sunos_device_handle_priv {
- uint8_t altsetting[USB_MAXINTERFACES]; /* a interface's alt */
- uint8_t config_index;
- sunos_ep_priv_t eps[USB_MAXENDPOINTS];
- sunos_dev_priv_t *dpriv; /* device private */
-} sunos_dev_handle_priv_t;
-
-typedef struct sunos_transfer_priv {
- struct aiocb aiocb;
- struct libusb_transfer *transfer;
-} sunos_xfer_priv_t;
-
-struct node_args {
- struct libusb_context *ctx;
- struct discovered_devs **discdevs;
- const char *last_ugenpath;
- di_devlink_handle_t dlink_hdl;
-};
-
-struct devlink_cbarg {
- struct node_args *nargs; /* di node walk arguments */
- di_node_t myself; /* the di node */
- di_minor_t minor;
-};
-
-typedef struct walk_link {
- char *path;
- int len;
- char **linkpp;
-} walk_link_t;
-
-/* AIO callback args */
-struct aio_callback_args{
- struct libusb_transfer *transfer;
- struct aiocb aiocb;
-};
-
-#endif /* LIBUSB_SUNOS_H */
diff --git a/src/os/threads_windows.c b/src/os/threads_windows.c
deleted file mode 100644
index 4a57f42..0000000
--- a/src/os/threads_windows.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * libusb synchronization on Microsoft Windows
- *
- * Copyright © 2010 Michael Plante <michael.plante@gmail.com>
- * Copyright © 2020 Chris Dickens <christopher.a.dickens@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 "libusbi.h"
-
-int usbi_cond_timedwait(usbi_cond_t *cond,
- usbi_mutex_t *mutex, const struct timeval *tv)
-{
- DWORD millis;
-
- millis = (DWORD)(tv->tv_sec * 1000L) + (tv->tv_usec / 1000L);
- /* round up to next millisecond */
- if (tv->tv_usec % 1000L)
- millis++;
-
- if (SleepConditionVariableCS(cond, mutex, millis))
- return 0;
- else if (GetLastError() == ERROR_TIMEOUT)
- return LIBUSB_ERROR_TIMEOUT;
- else
- return LIBUSB_ERROR_OTHER;
-}
diff --git a/src/os/threads_windows.h b/src/os/threads_windows.h
deleted file mode 100644
index dfef158..0000000
--- a/src/os/threads_windows.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * libusb synchronization on Microsoft Windows
- *
- * Copyright © 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 WINAPI_CHECK(expression) ASSERT_NE(expression, 0)
-
-#define USBI_MUTEX_INITIALIZER 0L
-typedef LONG usbi_mutex_static_t;
-static inline void usbi_mutex_static_lock(usbi_mutex_static_t *mutex)
-{
- while (InterlockedExchange(mutex, 1L) == 1L)
- SleepEx(0, TRUE);
-}
-static inline void usbi_mutex_static_unlock(usbi_mutex_static_t *mutex)
-{
- InterlockedExchange(mutex, 0L);
-}
-
-typedef CRITICAL_SECTION usbi_mutex_t;
-static inline void usbi_mutex_init(usbi_mutex_t *mutex)
-{
- InitializeCriticalSection(mutex);
-}
-static inline void usbi_mutex_lock(usbi_mutex_t *mutex)
-{
- EnterCriticalSection(mutex);
-}
-static inline void usbi_mutex_unlock(usbi_mutex_t *mutex)
-{
- LeaveCriticalSection(mutex);
-}
-static inline int usbi_mutex_trylock(usbi_mutex_t *mutex)
-{
- return TryEnterCriticalSection(mutex) != 0;
-}
-static inline void usbi_mutex_destroy(usbi_mutex_t *mutex)
-{
- DeleteCriticalSection(mutex);
-}
-
-#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 */
-
-typedef CONDITION_VARIABLE usbi_cond_t;
-static inline void usbi_cond_init(usbi_cond_t *cond)
-{
- InitializeConditionVariable(cond);
-}
-static inline void usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
-{
- WINAPI_CHECK(SleepConditionVariableCS(cond, mutex, INFINITE));
-}
-int usbi_cond_timedwait(usbi_cond_t *cond,
- usbi_mutex_t *mutex, const struct timeval *tv);
-static inline void usbi_cond_broadcast(usbi_cond_t *cond)
-{
- WakeAllConditionVariable(cond);
-}
-static inline void usbi_cond_destroy(usbi_cond_t *cond)
-{
- UNUSED(cond);
-}
-
-typedef DWORD usbi_tls_key_t;
-static inline void usbi_tls_key_create(usbi_tls_key_t *key)
-{
- *key = TlsAlloc();
- assert(*key != TLS_OUT_OF_INDEXES);
-}
-static inline void *usbi_tls_key_get(usbi_tls_key_t key)
-{
- return TlsGetValue(key);
-}
-static inline void usbi_tls_key_set(usbi_tls_key_t key, void *ptr)
-{
- WINAPI_CHECK(TlsSetValue(key, ptr));
-}
-static inline void usbi_tls_key_delete(usbi_tls_key_t key)
-{
- WINAPI_CHECK(TlsFree(key));
-}
-
-static inline unsigned int usbi_get_tid(void)
-{
- return (unsigned int)GetCurrentThreadId();
-}
-
-#endif /* LIBUSB_THREADS_WINDOWS_H */
diff --git a/src/os/windows_common.c b/src/os/windows_common.c
deleted file mode 100644
index eefd01e..0000000
--- a/src/os/windows_common.c
+++ /dev/null
@@ -1,904 +0,0 @@
-/*
- * windows backend for libusb 1.0
- * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
- * 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
- */
-
-#include <config.h>
-
-#include <stdio.h>
-
-#include "libusbi.h"
-#include "windows_common.h"
-
-#define EPOCH_TIME UINT64_C(116444736000000000) // 1970.01.01 00:00:000 in MS Filetime
-
-#define STATUS_SUCCESS ((ULONG_PTR)0UL)
-
-// Public
-enum windows_version windows_version = WINDOWS_UNDEFINED;
-
-// Global variables for init/exit
-static unsigned int init_count;
-static bool usbdk_available;
-
-/*
-* Converts a windows error to human readable string
-* uses retval as errorcode, or, if 0, use GetLastError()
-*/
-#if defined(ENABLE_LOGGING)
-const char *windows_error_str(DWORD error_code)
-{
- static char err_string[256];
-
- DWORD size;
- int len;
-
- if (error_code == 0)
- error_code = GetLastError();
-
- len = sprintf(err_string, "[%lu] ", ULONG_CAST(error_code));
-
- // Translate codes returned by SetupAPI. The ones we are dealing with are either
- // in 0x0000xxxx or 0xE000xxxx and can be distinguished from standard error codes.
- // See http://msdn.microsoft.com/en-us/library/windows/hardware/ff545011.aspx
- switch (error_code & 0xE0000000) {
- case 0:
- error_code = HRESULT_FROM_WIN32(error_code); // Still leaves ERROR_SUCCESS unmodified
- break;
- case 0xE0000000:
- error_code = 0x80000000 | (FACILITY_SETUPAPI << 16) | (error_code & 0x0000FFFF);
- break;
- default:
- break;
- }
-
- size = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- &err_string[len], sizeof(err_string) - len, NULL);
- if (size == 0) {
- DWORD format_error = GetLastError();
- if (format_error)
- snprintf(err_string, sizeof(err_string),
- "Windows error code %lu (FormatMessage error code %lu)",
- ULONG_CAST(error_code), ULONG_CAST(format_error));
- else
- snprintf(err_string, sizeof(err_string), "Unknown error code %lu",
- ULONG_CAST(error_code));
- } else {
- // Remove CRLF from end of message, if present
- size_t pos = len + size - 2;
- if (err_string[pos] == '\r')
- err_string[pos] = '\0';
- }
-
- return err_string;
-}
-#endif
-
-/*
- * Dynamically loads a DLL from the Windows system directory. Unlike the
- * LoadLibraryA() function, this function will not search through any
- * directories to try and find the library.
- */
-HMODULE load_system_library(struct libusb_context *ctx, const char *name)
-{
- char library_path[MAX_PATH];
- char *filename_start;
- UINT length;
-
- length = GetSystemDirectoryA(library_path, sizeof(library_path));
- if ((length == 0) || (length >= (UINT)sizeof(library_path))) {
- usbi_err(ctx, "program assertion failed - could not get system directory");
- return NULL;
- }
-
- filename_start = library_path + length;
- // Append '\' + name + ".dll" + NUL
- length += 1 + (UINT)strlen(name) + 4 + 1;
- if (length >= (UINT)sizeof(library_path)) {
- usbi_err(ctx, "program assertion failed - library path buffer overflow");
- return NULL;
- }
-
- sprintf(filename_start, "\\%s.dll", name);
- return LoadLibraryA(library_path);
-}
-
-/* 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) */
-
-#define HTAB_SIZE 1021UL // *MUST* be a prime number!!
-
-typedef struct htab_entry {
- unsigned long used;
- char *str;
-} htab_entry;
-
-static htab_entry *htab_table;
-static usbi_mutex_t htab_mutex;
-static unsigned long htab_filled;
-
-/* 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. */
-static bool htab_create(struct libusb_context *ctx)
-{
- if (htab_table != NULL) {
- usbi_err(ctx, "program assertion failed - hash table already allocated");
- return true;
- }
-
- // Create a mutex
- usbi_mutex_init(&htab_mutex);
-
- usbi_dbg(ctx, "using %lu entries hash table", HTAB_SIZE);
- htab_filled = 0;
-
- // allocate memory and zero out.
- htab_table = calloc(HTAB_SIZE + 1, sizeof(htab_entry));
- if (htab_table == NULL) {
- usbi_err(ctx, "could not allocate space for hash table");
- return false;
- }
-
- return true;
-}
-
-/* After using the hash table it has to be destroyed. */
-static void htab_destroy(void)
-{
- unsigned long i;
-
- if (htab_table == NULL)
- return;
-
- for (i = 0; i < HTAB_SIZE; i++)
- free(htab_table[i].str);
-
- safe_free(htab_table);
-
- usbi_mutex_destroy(&htab_mutex);
-}
-
-/* This is the search function. It uses double hashing with open addressing.
- We use a 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(const char *str)
-{
- unsigned long hval, hval2;
- unsigned long idx;
- unsigned long r = 5381UL;
- int c;
- const char *sz = str;
-
- if (str == NULL)
- return 0;
-
- // Compute main hash value (algorithm suggested by Nokia)
- while ((c = *sz++) != 0)
- 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;
-
- // Mutually exclusive access (R/W lock would be better)
- usbi_mutex_lock(&htab_mutex);
-
- if (htab_table[idx].used) {
- if ((htab_table[idx].used == hval) && (strcmp(str, htab_table[idx].str) == 0))
- goto out_unlock; // existing hash
-
- usbi_dbg(NULL, "hash collision ('%s' vs '%s')", str, htab_table[idx].str);
-
- // Second hash function, as suggested in [Knuth]
- hval2 = 1UL + 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) && (strcmp(str, htab_table[idx].str) == 0))
- goto out_unlock;
- } 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 (%lu entries)", HTAB_SIZE);
- idx = 0UL;
- goto out_unlock;
- }
-
- htab_table[idx].str = _strdup(str);
- if (htab_table[idx].str == NULL) {
- usbi_err(NULL, "could not duplicate string for hash table");
- idx = 0UL;
- goto out_unlock;
- }
-
- htab_table[idx].used = hval;
- ++htab_filled;
-
-out_unlock:
- usbi_mutex_unlock(&htab_mutex);
-
- return idx;
-}
-
-enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS status)
-{
- if (USBD_SUCCESS(status))
- return LIBUSB_TRANSFER_COMPLETED;
-
- switch (status) {
- case USBD_STATUS_TIMEOUT:
- return LIBUSB_TRANSFER_TIMED_OUT;
- case USBD_STATUS_CANCELED:
- return LIBUSB_TRANSFER_CANCELLED;
- case USBD_STATUS_ENDPOINT_HALTED:
- return LIBUSB_TRANSFER_STALL;
- case USBD_STATUS_DEVICE_GONE:
- return LIBUSB_TRANSFER_NO_DEVICE;
- default:
- usbi_dbg(NULL, "USBD_STATUS 0x%08lx translated to LIBUSB_TRANSFER_ERROR", ULONG_CAST(status));
- return LIBUSB_TRANSFER_ERROR;
- }
-}
-
-/*
- * Make a transfer complete synchronously
- */
-void windows_force_sync_completion(struct usbi_transfer *itransfer, ULONG size)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct windows_context_priv *priv = usbi_get_context_priv(TRANSFER_CTX(transfer));
- struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
- OVERLAPPED *overlapped = &transfer_priv->overlapped;
-
- usbi_dbg(TRANSFER_CTX(transfer), "transfer %p, length %lu", transfer, ULONG_CAST(size));
-
- overlapped->Internal = (ULONG_PTR)STATUS_SUCCESS;
- overlapped->InternalHigh = (ULONG_PTR)size;
-
- if (!PostQueuedCompletionStatus(priv->completion_port, (DWORD)size, (ULONG_PTR)transfer->dev_handle, overlapped))
- usbi_err(TRANSFER_CTX(transfer), "failed to post I/O completion: %s", windows_error_str(0));
-}
-
-/* Windows version detection */
-static BOOL is_x64(void)
-{
- BOOL ret = FALSE;
-
- // Detect if we're running a 32 or 64 bit system
- if (sizeof(uintptr_t) < 8) {
- IsWow64Process(GetCurrentProcess(), &ret);
- } else {
- ret = TRUE;
- }
-
- return ret;
-}
-
-static enum windows_version get_windows_version(void)
-{
- enum windows_version winver;
- OSVERSIONINFOEXA vi, vi2;
- unsigned major, minor, version;
- ULONGLONG major_equal, minor_equal;
- const char *w, *arch;
- bool ws;
-
- memset(&vi, 0, sizeof(vi));
- vi.dwOSVersionInfoSize = sizeof(vi);
- if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
- memset(&vi, 0, sizeof(vi));
- vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
- if (!GetVersionExA((OSVERSIONINFOA *)&vi))
- return WINDOWS_UNDEFINED;
- }
-
- if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT)
- return WINDOWS_UNDEFINED;
-
- if ((vi.dwMajorVersion > 6) || ((vi.dwMajorVersion == 6) && (vi.dwMinorVersion >= 2))) {
- // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version
- // See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
-
- major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
- for (major = vi.dwMajorVersion; major <= 9; major++) {
- memset(&vi2, 0, sizeof(vi2));
- vi2.dwOSVersionInfoSize = sizeof(vi2);
- vi2.dwMajorVersion = major;
- if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal))
- continue;
-
- if (vi.dwMajorVersion < major) {
- vi.dwMajorVersion = major;
- vi.dwMinorVersion = 0;
- }
-
- minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
- for (minor = vi.dwMinorVersion; minor <= 9; minor++) {
- memset(&vi2, 0, sizeof(vi2));
- vi2.dwOSVersionInfoSize = sizeof(vi2);
- vi2.dwMinorVersion = minor;
- if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal))
- continue;
-
- vi.dwMinorVersion = minor;
- break;
- }
-
- break;
- }
- }
-
- if ((vi.dwMajorVersion > 0xf) || (vi.dwMinorVersion > 0xf))
- return WINDOWS_UNDEFINED;
-
- ws = (vi.wProductType <= VER_NT_WORKSTATION);
- version = vi.dwMajorVersion << 4 | vi.dwMinorVersion;
- switch (version) {
- case 0x50: winver = WINDOWS_2000; w = "2000"; break;
- case 0x51: winver = WINDOWS_XP; w = "XP"; break;
- case 0x52: winver = WINDOWS_2003; w = "2003"; break;
- case 0x60: winver = WINDOWS_VISTA; w = (ws ? "Vista" : "2008"); break;
- case 0x61: winver = WINDOWS_7; w = (ws ? "7" : "2008_R2"); break;
- case 0x62: winver = WINDOWS_8; w = (ws ? "8" : "2012"); break;
- case 0x63: winver = WINDOWS_8_1; w = (ws ? "8.1" : "2012_R2"); break;
- case 0x64: // Early Windows 10 Insider Previews and Windows Server 2017 Technical Preview 1 used version 6.4
- case 0xA0: winver = WINDOWS_10; w = (ws ? "10" : "2016"); break;
- default:
- if (version < 0x50)
- return WINDOWS_UNDEFINED;
- winver = WINDOWS_11_OR_LATER;
- w = "11 or later";
- }
-
- arch = is_x64() ? "64-bit" : "32-bit";
-
- if (vi.wServicePackMinor)
- usbi_dbg(NULL, "Windows %s SP%u.%u %s", w, vi.wServicePackMajor, vi.wServicePackMinor, arch);
- else if (vi.wServicePackMajor)
- usbi_dbg(NULL, "Windows %s SP%u %s", w, vi.wServicePackMajor, arch);
- else
- usbi_dbg(NULL, "Windows %s %s", w, arch);
-
- return winver;
-}
-
-static unsigned __stdcall windows_iocp_thread(void *arg)
-{
- struct libusb_context *ctx = arg;
- struct windows_context_priv *priv = usbi_get_context_priv(ctx);
- HANDLE iocp = priv->completion_port;
- DWORD num_bytes;
- ULONG_PTR completion_key;
- OVERLAPPED *overlapped;
- struct libusb_device_handle *dev_handle;
- struct libusb_device_handle *opened_device_handle;
- struct windows_device_handle_priv *handle_priv;
- struct windows_transfer_priv *transfer_priv;
- struct usbi_transfer *itransfer;
- bool found;
-
- usbi_dbg(ctx, "I/O completion thread started");
-
- while (true) {
- overlapped = NULL;
- if (!GetQueuedCompletionStatus(iocp, &num_bytes, &completion_key, &overlapped, INFINITE) && (overlapped == NULL)) {
- usbi_err(ctx, "GetQueuedCompletionStatus failed: %s", windows_error_str(0));
- break;
- }
-
- if (overlapped == NULL) {
- // Signal to quit
- if (completion_key != (ULONG_PTR)ctx)
- usbi_err(ctx, "program assertion failed - overlapped is NULL");
- break;
- }
-
- // Find the transfer associated with the OVERLAPPED that just completed.
- // If we cannot find a match, the I/O operation originated from outside of libusb
- // (e.g. within libusbK) and we need to ignore it.
- dev_handle = (struct libusb_device_handle *)completion_key;
-
- found = false;
- transfer_priv = NULL;
-
- // Issue 912: lock opened device handles in context to search the current device handle
- // to avoid accessing unallocated memory after device has been closed
- usbi_mutex_lock(&ctx->open_devs_lock);
- for_each_open_device(ctx, opened_device_handle) {
- if (dev_handle == opened_device_handle) {
- handle_priv = usbi_get_device_handle_priv(dev_handle);
-
- usbi_mutex_lock(&dev_handle->lock);
- list_for_each_entry(transfer_priv, &handle_priv->active_transfers, list, struct windows_transfer_priv) {
- if (overlapped == &transfer_priv->overlapped) {
- // This OVERLAPPED belongs to us, remove the transfer from the device handle's list
- list_del(&transfer_priv->list);
- found = true;
- break;
- }
- }
- usbi_mutex_unlock(&dev_handle->lock);
- }
- }
- usbi_mutex_unlock(&ctx->open_devs_lock);
-
- if (!found) {
- usbi_dbg(ctx, "ignoring overlapped %p for handle %p (device %u.%u)",
- overlapped, dev_handle, dev_handle->dev->bus_number, dev_handle->dev->device_address);
- continue;
- }
-
- itransfer = (struct usbi_transfer *)((unsigned char *)transfer_priv + PTR_ALIGN(sizeof(*transfer_priv)));
- usbi_dbg(ctx, "transfer %p completed, length %lu",
- USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer), ULONG_CAST(num_bytes));
- usbi_signal_transfer_completion(itransfer);
- }
-
- usbi_dbg(ctx, "I/O completion thread exiting");
-
- return 0;
-}
-
-static int windows_init(struct libusb_context *ctx)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(ctx);
- bool winusb_backend_init = false;
- int r;
-
- // 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 (++init_count == 1) { // First init?
- windows_version = get_windows_version();
- if (windows_version == WINDOWS_UNDEFINED) {
- usbi_err(ctx, "failed to detect Windows version");
- r = LIBUSB_ERROR_NOT_SUPPORTED;
- goto init_exit;
- } else if (windows_version < WINDOWS_VISTA) {
- usbi_err(ctx, "Windows version is too old");
- r = LIBUSB_ERROR_NOT_SUPPORTED;
- goto init_exit;
- }
-
- if (!htab_create(ctx)) {
- r = LIBUSB_ERROR_NO_MEM;
- goto init_exit;
- }
-
- r = winusb_backend.init(ctx);
- if (r != LIBUSB_SUCCESS)
- goto init_exit;
- winusb_backend_init = true;
-
- r = usbdk_backend.init(ctx);
- if (r == LIBUSB_SUCCESS) {
- usbi_dbg(ctx, "UsbDk backend is available");
- usbdk_available = true;
- } else {
- usbi_info(ctx, "UsbDk backend is not available");
- // Do not report this as an error
- }
- }
-
- // By default, new contexts will use the WinUSB backend
- priv->backend = &winusb_backend;
-
- r = LIBUSB_ERROR_NO_MEM;
-
- // Use an I/O completion port to manage all transfers for this context
- priv->completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
- if (priv->completion_port == NULL) {
- usbi_err(ctx, "failed to create I/O completion port: %s", windows_error_str(0));
- goto init_exit;
- }
-
- // And a dedicated thread to wait for I/O completions
- priv->completion_port_thread = (HANDLE)_beginthreadex(NULL, 0, windows_iocp_thread, ctx, 0, NULL);
- if (priv->completion_port_thread == NULL) {
- usbi_err(ctx, "failed to create I/O completion port thread");
- CloseHandle(priv->completion_port);
- goto init_exit;
- }
-
- r = LIBUSB_SUCCESS;
-
-init_exit: // Holds semaphore here
- if ((init_count == 1) && (r != LIBUSB_SUCCESS)) { // First init failed?
- if (usbdk_available) {
- usbdk_backend.exit(ctx);
- usbdk_available = false;
- }
- if (winusb_backend_init)
- winusb_backend.exit(ctx);
- htab_destroy();
- --init_count;
- }
-
- return r;
-}
-
-static void windows_exit(struct libusb_context *ctx)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(ctx);
-
- // A NULL completion status will indicate to the thread that it is time to exit
- if (!PostQueuedCompletionStatus(priv->completion_port, 0, (ULONG_PTR)ctx, NULL))
- usbi_err(ctx, "failed to post I/O completion: %s", windows_error_str(0));
-
- if (WaitForSingleObject(priv->completion_port_thread, INFINITE) == WAIT_FAILED)
- usbi_err(ctx, "failed to wait for I/O completion port thread: %s", windows_error_str(0));
-
- CloseHandle(priv->completion_port_thread);
- CloseHandle(priv->completion_port);
-
- // Only works if exits and inits are balanced exactly
- if (--init_count == 0) { // Last exit
- if (usbdk_available) {
- usbdk_backend.exit(ctx);
- usbdk_available = false;
- }
- winusb_backend.exit(ctx);
- htab_destroy();
- }
-}
-
-static int windows_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(ctx);
-
- UNUSED(ap);
-
- if (option == LIBUSB_OPTION_USE_USBDK) {
- if (!usbdk_available) {
- usbi_err(ctx, "UsbDk backend not available");
- return LIBUSB_ERROR_NOT_FOUND;
- }
- usbi_dbg(ctx, "switching context %p to use UsbDk backend", ctx);
- priv->backend = &usbdk_backend;
- return LIBUSB_SUCCESS;
- }
-
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **discdevs)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(ctx);
- return priv->backend->get_device_list(ctx, discdevs);
-}
-
-static int windows_open(struct libusb_device_handle *dev_handle)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
- struct windows_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle);
-
- list_init(&handle_priv->active_transfers);
- return priv->backend->open(dev_handle);
-}
-
-static void windows_close(struct libusb_device_handle *dev_handle)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
- priv->backend->close(dev_handle);
-}
-
-static int windows_get_active_config_descriptor(struct libusb_device *dev,
- void *buffer, size_t len)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(DEVICE_CTX(dev));
- return priv->backend->get_active_config_descriptor(dev, buffer, len);
-}
-
-static int windows_get_config_descriptor(struct libusb_device *dev,
- uint8_t config_index, void *buffer, size_t len)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(DEVICE_CTX(dev));
- return priv->backend->get_config_descriptor(dev, config_index, buffer, len);
-}
-
-static int windows_get_config_descriptor_by_value(struct libusb_device *dev,
- uint8_t bConfigurationValue, void **buffer)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(DEVICE_CTX(dev));
- return priv->backend->get_config_descriptor_by_value(dev, bConfigurationValue, buffer);
-}
-
-static int windows_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
- return priv->backend->get_configuration(dev_handle, config);
-}
-
-static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
- if (config == -1)
- config = 0;
- return priv->backend->set_configuration(dev_handle, (uint8_t)config);
-}
-
-static int windows_claim_interface(struct libusb_device_handle *dev_handle, uint8_t interface_number)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
- return priv->backend->claim_interface(dev_handle, interface_number);
-}
-
-static int windows_release_interface(struct libusb_device_handle *dev_handle, uint8_t interface_number)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
- return priv->backend->release_interface(dev_handle, interface_number);
-}
-
-static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle,
- uint8_t interface_number, uint8_t altsetting)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
- return priv->backend->set_interface_altsetting(dev_handle, interface_number, altsetting);
-}
-
-static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
- return priv->backend->clear_halt(dev_handle, endpoint);
-}
-
-static int windows_reset_device(struct libusb_device_handle *dev_handle)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
- return priv->backend->reset_device(dev_handle);
-}
-
-static void windows_destroy_device(struct libusb_device *dev)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(DEVICE_CTX(dev));
- priv->backend->destroy_device(dev);
-}
-
-static int windows_submit_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct libusb_device_handle *dev_handle = transfer->dev_handle;
- struct libusb_context *ctx = HANDLE_CTX(dev_handle);
- struct windows_context_priv *priv = usbi_get_context_priv(ctx);
- struct windows_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle);
- struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
- int r;
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- break;
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- usbi_warn(ctx, "bulk stream transfers are not yet supported on this platform");
- return LIBUSB_ERROR_NOT_SUPPORTED;
- default:
- usbi_err(ctx, "unknown endpoint type %d", transfer->type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- if (transfer_priv->handle != NULL) {
- usbi_err(ctx, "program assertion failed - transfer HANDLE is not NULL");
- transfer_priv->handle = NULL;
- }
-
- // Add transfer to the device handle's list
- usbi_mutex_lock(&dev_handle->lock);
- list_add_tail(&transfer_priv->list, &handle_priv->active_transfers);
- usbi_mutex_unlock(&dev_handle->lock);
-
- r = priv->backend->submit_transfer(itransfer);
- if (r != LIBUSB_SUCCESS) {
- // Remove the unsuccessful transfer from the device handle's list
- usbi_mutex_lock(&dev_handle->lock);
- list_del(&transfer_priv->list);
- usbi_mutex_unlock(&dev_handle->lock);
-
- // Always call the backend's clear_transfer_priv() function on failure
- priv->backend->clear_transfer_priv(itransfer);
- transfer_priv->handle = NULL;
- return r;
- }
-
- // The backend should set the HANDLE used for each submitted transfer
- // by calling set_transfer_priv_handle()
- if (transfer_priv->handle == NULL)
- usbi_err(ctx, "program assertion failed - transfer HANDLE is NULL after transfer was submitted");
-
- return r;
-}
-
-static int windows_cancel_transfer(struct usbi_transfer *itransfer)
-{
- struct windows_context_priv *priv = usbi_get_context_priv(ITRANSFER_CTX(itransfer));
- struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
-
- // Try CancelIoEx() on the transfer
- // If that fails, fall back to the backend's cancel_transfer()
- // function if it is available
- if (CancelIoEx(transfer_priv->handle, &transfer_priv->overlapped))
- return LIBUSB_SUCCESS;
- else if (GetLastError() == ERROR_NOT_FOUND)
- return LIBUSB_ERROR_NOT_FOUND;
-
- if (priv->backend->cancel_transfer)
- return priv->backend->cancel_transfer(itransfer);
-
- usbi_warn(ITRANSFER_CTX(itransfer), "cancellation not supported for this transfer's driver");
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int windows_handle_transfer_completion(struct usbi_transfer *itransfer)
-{
- struct libusb_context *ctx = ITRANSFER_CTX(itransfer);
- struct windows_context_priv *priv = usbi_get_context_priv(ctx);
- const struct windows_backend *backend = priv->backend;
- struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
- enum libusb_transfer_status status, istatus;
- DWORD result, bytes_transferred;
-
- if (GetOverlappedResult(transfer_priv->handle, &transfer_priv->overlapped, &bytes_transferred, FALSE))
- result = NO_ERROR;
- else
- result = GetLastError();
-
- usbi_dbg(ctx, "handling transfer %p completion with errcode %lu, length %lu",
- USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer), ULONG_CAST(result), ULONG_CAST(bytes_transferred));
-
- switch (result) {
- case NO_ERROR:
- status = backend->copy_transfer_data(itransfer, bytes_transferred);
- break;
- case ERROR_GEN_FAILURE:
- usbi_dbg(ctx, "detected endpoint stall");
- status = LIBUSB_TRANSFER_STALL;
- break;
- case ERROR_SEM_TIMEOUT:
- usbi_dbg(ctx, "detected semaphore timeout");
- status = LIBUSB_TRANSFER_TIMED_OUT;
- break;
- case ERROR_OPERATION_ABORTED:
- istatus = backend->copy_transfer_data(itransfer, bytes_transferred);
- if (istatus != LIBUSB_TRANSFER_COMPLETED)
- usbi_dbg(ctx, "failed to copy partial data in aborted operation: %d", (int)istatus);
-
- usbi_dbg(ctx, "detected operation aborted");
- status = LIBUSB_TRANSFER_CANCELLED;
- break;
- case ERROR_FILE_NOT_FOUND:
- case ERROR_DEVICE_NOT_CONNECTED:
- case ERROR_NO_SUCH_DEVICE:
- usbi_dbg(ctx, "detected device removed");
- status = LIBUSB_TRANSFER_NO_DEVICE;
- break;
- default:
- usbi_err(ctx, "detected I/O error %lu: %s",
- ULONG_CAST(result), windows_error_str(result));
- status = LIBUSB_TRANSFER_ERROR;
- break;
- }
-
- transfer_priv->handle = NULL;
-
- // Backend-specific cleanup
- backend->clear_transfer_priv(itransfer);
-
- if (status == LIBUSB_TRANSFER_CANCELLED)
- return usbi_handle_transfer_cancellation(itransfer);
- else
- return usbi_handle_transfer_completion(itransfer, status);
-}
-
-void usbi_get_monotonic_time(struct timespec *tp)
-{
- static LONG hires_counter_init;
- static uint64_t hires_ticks_to_ps;
- static uint64_t hires_frequency;
- LARGE_INTEGER hires_counter;
-
- if (InterlockedExchange(&hires_counter_init, 1L) == 0L) {
- LARGE_INTEGER li_frequency;
-
- // Microsoft says that the QueryPerformanceFrequency() and
- // QueryPerformanceCounter() functions always succeed on XP and later
- QueryPerformanceFrequency(&li_frequency);
-
- // The hires frequency can go as high as 4 GHz, so we'll use a conversion
- // to picoseconds to compute the tv_nsecs part
- hires_frequency = li_frequency.QuadPart;
- hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
- }
-
- QueryPerformanceCounter(&hires_counter);
- tp->tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
- tp->tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) * hires_ticks_to_ps) / UINT64_C(1000));
-}
-
-// NB: MSVC6 does not support named initializers.
-const struct usbi_os_backend usbi_backend = {
- "Windows",
- USBI_CAP_HAS_HID_ACCESS,
- windows_init,
- windows_exit,
- windows_set_option,
- windows_get_device_list,
- NULL, /* hotplug_poll */
- NULL, /* wrap_sys_device */
- windows_open,
- windows_close,
- windows_get_active_config_descriptor,
- windows_get_config_descriptor,
- windows_get_config_descriptor_by_value,
- windows_get_configuration,
- windows_set_configuration,
- windows_claim_interface,
- windows_release_interface,
- windows_set_interface_altsetting,
- windows_clear_halt,
- windows_reset_device,
- NULL, /* alloc_streams */
- NULL, /* free_streams */
- NULL, /* dev_mem_alloc */
- NULL, /* dev_mem_free */
- NULL, /* kernel_driver_active */
- NULL, /* detach_kernel_driver */
- NULL, /* attach_kernel_driver */
- windows_destroy_device,
- windows_submit_transfer,
- windows_cancel_transfer,
- NULL, /* clear_transfer_priv */
- NULL, /* handle_events */
- windows_handle_transfer_completion,
- sizeof(struct windows_context_priv),
- sizeof(union windows_device_priv),
- sizeof(struct windows_device_handle_priv),
- sizeof(struct windows_transfer_priv),
-};
diff --git a/src/os/windows_common.h b/src/os/windows_common.h
deleted file mode 100644
index 792a31e..0000000
--- a/src/os/windows_common.h
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * Windows backend common header for libusb 1.0
- *
- * This file brings together header code common between
- * the desktop Windows backends.
- * Copyright © 2012-2013 RealVNC Ltd.
- * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
- * Copyright © 2014-2020 Chris Dickens <christopher.a.dickens@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
- */
-
-#ifndef LIBUSB_WINDOWS_COMMON_H
-#define LIBUSB_WINDOWS_COMMON_H
-
-#include <stdbool.h>
-
-/*
- * Workaround for the mess that exists with the DWORD and ULONG types.
- * Visual Studio unconditionally defines these types as 'unsigned long'
- * and a long is always 32-bits, even on 64-bit builds. GCC on the other
- * hand varies the width of a long, matching it to the build. To make
- * matters worse, the platform headers for these GCC builds define a
- * DWORD/ULONG to be 'unsigned long' on 32-bit builds and 'unsigned int'
- * on 64-bit builds. This creates a great deal of warnings for compilers
- * that support printf format checking since it will never actually be
- * an unsigned long.
- */
-#if defined(_MSC_VER)
-#define ULONG_CAST(x) (x)
-#else
-#define ULONG_CAST(x) ((unsigned long)(x))
-#endif
-
-#if defined(__CYGWIN__)
-#define _stricmp strcasecmp
-#define _strdup strdup
-// _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, (LPDWORD)f)
-#else
-#include <process.h>
-#endif
-
-#define safe_free(p) do {if (p != NULL) {free((void *)p); p = NULL;}} while (0)
-
-/*
- * API macros - leveraged from libusb-win32 1.x
- */
-#define DLL_STRINGIFY(s) #s
-
-/*
- * Macros for handling DLL themselves
- */
-#define DLL_HANDLE_NAME(name) __dll_##name##_handle
-
-#define DLL_DECLARE_HANDLE(name) \
- static HMODULE DLL_HANDLE_NAME(name)
-
-#define DLL_GET_HANDLE(ctx, name) \
- do { \
- DLL_HANDLE_NAME(name) = load_system_library(ctx, \
- DLL_STRINGIFY(name)); \
- if (!DLL_HANDLE_NAME(name)) \
- return false; \
- } while (0)
-
-#define DLL_FREE_HANDLE(name) \
- do { \
- if (DLL_HANDLE_NAME(name)) { \
- FreeLibrary(DLL_HANDLE_NAME(name)); \
- DLL_HANDLE_NAME(name) = NULL; \
- } \
- } while (0)
-
-/*
- * Macros for handling functions within a DLL
- */
-#define DLL_FUNC_NAME(name) __dll_##name##_func_t
-
-#define DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefixname, name, args) \
- typedef ret (api * DLL_FUNC_NAME(name))args; \
- static DLL_FUNC_NAME(name) prefixname
-
-#define DLL_DECLARE_FUNC(api, ret, name, args) \
- DLL_DECLARE_FUNC_PREFIXNAME(api, ret, name, name, args)
-#define DLL_DECLARE_FUNC_PREFIXED(api, ret, prefix, name, args) \
- DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefix##name, name, args)
-
-#define DLL_LOAD_FUNC_PREFIXNAME(dll, prefixname, name, ret_on_failure) \
- do { \
- HMODULE h = DLL_HANDLE_NAME(dll); \
- prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
- DLL_STRINGIFY(name)); \
- if (prefixname) \
- break; \
- prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
- DLL_STRINGIFY(name) DLL_STRINGIFY(A)); \
- if (prefixname) \
- break; \
- prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
- DLL_STRINGIFY(name) DLL_STRINGIFY(W)); \
- if (prefixname) \
- break; \
- if (ret_on_failure) \
- return false; \
- } while (0)
-
-#define DLL_LOAD_FUNC(dll, name, ret_on_failure) \
- DLL_LOAD_FUNC_PREFIXNAME(dll, name, name, ret_on_failure)
-#define DLL_LOAD_FUNC_PREFIXED(dll, prefix, name, ret_on_failure) \
- DLL_LOAD_FUNC_PREFIXNAME(dll, prefix##name, name, ret_on_failure)
-
-// https://msdn.microsoft.com/en-us/library/windows/hardware/ff539136(v=vs.85).aspx
-#if !defined(USBD_SUCCESS)
-typedef LONG USBD_STATUS;
-
-#define USBD_SUCCESS(Status) ((USBD_STATUS)(Status) >= 0)
-
-#define USBD_STATUS_ENDPOINT_HALTED ((USBD_STATUS)0xC0000030L)
-#define USBD_STATUS_TIMEOUT ((USBD_STATUS)0xC0006000L)
-#define USBD_STATUS_DEVICE_GONE ((USBD_STATUS)0xC0007000L)
-#define USBD_STATUS_CANCELED ((USBD_STATUS)0xC0010000L)
-#endif
-
-// error code added with Windows SDK 10.0.18362
-#ifndef ERROR_NO_SUCH_DEVICE
-#define ERROR_NO_SUCH_DEVICE 433L
-#endif
-
-/* Windows versions */
-enum windows_version {
- WINDOWS_UNDEFINED,
- WINDOWS_2000,
- WINDOWS_XP,
- WINDOWS_2003, // Also XP x64
- WINDOWS_VISTA,
- WINDOWS_7,
- WINDOWS_8,
- WINDOWS_8_1,
- WINDOWS_10,
- WINDOWS_11_OR_LATER
-};
-
-extern enum windows_version windows_version;
-
-#include <pshpack1.h>
-
-typedef struct USB_DEVICE_DESCRIPTOR {
- UCHAR bLength;
- UCHAR bDescriptorType;
- USHORT bcdUSB;
- UCHAR bDeviceClass;
- UCHAR bDeviceSubClass;
- UCHAR bDeviceProtocol;
- UCHAR bMaxPacketSize0;
- USHORT idVendor;
- USHORT idProduct;
- USHORT bcdDevice;
- UCHAR iManufacturer;
- UCHAR iProduct;
- UCHAR iSerialNumber;
- UCHAR bNumConfigurations;
-} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_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;
-
-#include <poppack.h>
-
-#define MAX_DEVICE_ID_LEN 200
-
-typedef struct USB_DK_DEVICE_ID {
- WCHAR DeviceID[MAX_DEVICE_ID_LEN];
- WCHAR InstanceID[MAX_DEVICE_ID_LEN];
-} USB_DK_DEVICE_ID, *PUSB_DK_DEVICE_ID;
-
-typedef struct USB_DK_DEVICE_INFO {
- USB_DK_DEVICE_ID ID;
- ULONG64 FilterID;
- ULONG64 Port;
- ULONG64 Speed;
- USB_DEVICE_DESCRIPTOR DeviceDescriptor;
-} USB_DK_DEVICE_INFO, *PUSB_DK_DEVICE_INFO;
-
-typedef struct USB_DK_ISO_TRANSFER_RESULT {
- ULONG64 ActualLength;
- ULONG64 TransferResult;
-} USB_DK_ISO_TRANSFER_RESULT, *PUSB_DK_ISO_TRANSFER_RESULT;
-
-typedef struct USB_DK_GEN_TRANSFER_RESULT {
- ULONG64 BytesTransferred;
- ULONG64 UsbdStatus; // USBD_STATUS code
-} USB_DK_GEN_TRANSFER_RESULT, *PUSB_DK_GEN_TRANSFER_RESULT;
-
-typedef struct USB_DK_TRANSFER_RESULT {
- USB_DK_GEN_TRANSFER_RESULT GenResult;
- PVOID64 IsochronousResultsArray; // array of USB_DK_ISO_TRANSFER_RESULT
-} USB_DK_TRANSFER_RESULT, *PUSB_DK_TRANSFER_RESULT;
-
-typedef struct USB_DK_TRANSFER_REQUEST {
- ULONG64 EndpointAddress;
- PVOID64 Buffer;
- ULONG64 BufferLength;
- ULONG64 TransferType;
- ULONG64 IsochronousPacketsArraySize;
- PVOID64 IsochronousPacketsArray;
- USB_DK_TRANSFER_RESULT Result;
-} USB_DK_TRANSFER_REQUEST, *PUSB_DK_TRANSFER_REQUEST;
-
-struct usbdk_device_priv {
- USB_DK_DEVICE_ID ID;
- PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors;
- HANDLE redirector_handle;
- HANDLE system_handle;
- uint8_t active_configuration;
-};
-
-struct winusb_device_priv {
- bool initialized;
- bool root_hub;
- uint8_t active_config;
- uint8_t depth; // distance to HCD
- const struct windows_usb_api_backend *apib;
- char *dev_id;
- char *path; // device interface path
- int sub_api; // for WinUSB-like APIs
- struct {
- char *path; // each interface needs a device interface path,
- const struct windows_usb_api_backend *apib; // an API backend (multiple drivers support),
- int sub_api;
- int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
- uint8_t *endpoint;
- int current_altsetting;
- 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];
- struct hid_device_priv *hid;
- PUSB_CONFIGURATION_DESCRIPTOR *config_descriptor; // list of pointers to the cached config descriptors
- GUID class_guid; // checked for change during re-enumeration
-};
-
-struct usbdk_device_handle_priv {
- // Not currently used
- char dummy;
-};
-
-enum WINUSB_ZLP {
- WINUSB_ZLP_UNSET = 0,
- WINUSB_ZLP_OFF = 1,
- WINUSB_ZLP_ON = 2
-};
-
-struct winusb_device_handle_priv {
- int active_interface;
- struct {
- HANDLE dev_handle; // WinUSB needs an extra handle for the file
- HANDLE api_handle; // used by the API to communicate with the device
- uint8_t zlp[USB_MAXENDPOINTS]; // Current per-endpoint SHORT_PACKET_TERMINATE status (enum WINUSB_ZLP)
- } interface_handle[USB_MAXINTERFACES];
- int autoclaim_count[USB_MAXINTERFACES]; // For auto-release
-};
-
-struct usbdk_transfer_priv {
- USB_DK_TRANSFER_REQUEST request;
- PULONG64 IsochronousPacketsArray;
- PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray;
-};
-
-struct winusb_transfer_priv {
- 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;
-
- // For isochronous transfers with LibUSBk driver:
- void *iso_context;
-
- // For isochronous transfers with Microsoft WinUSB driver:
- void *isoch_buffer_handle; // The isoch_buffer_handle to free at the end of the transfer
- BOOL iso_break_stream; // Whether the isoch. stream was to be continued in the last call of libusb_submit_transfer.
- // As we this structure is zeroed out upon initialization, we need to use inverse logic here.
- libusb_transfer_cb_fn iso_user_callback; // Original transfer callback of the user. Might be used for isochronous transfers.
-};
-
-struct windows_backend {
- int (*init)(struct libusb_context *ctx);
- void (*exit)(struct libusb_context *ctx);
- int (*get_device_list)(struct libusb_context *ctx,
- struct discovered_devs **discdevs);
- int (*open)(struct libusb_device_handle *dev_handle);
- void (*close)(struct libusb_device_handle *dev_handle);
- int (*get_active_config_descriptor)(struct libusb_device *device,
- void *buffer, size_t len);
- int (*get_config_descriptor)(struct libusb_device *device,
- uint8_t config_index, void *buffer, size_t len);
- int (*get_config_descriptor_by_value)(struct libusb_device *device,
- uint8_t bConfigurationValue, void **buffer);
- int (*get_configuration)(struct libusb_device_handle *dev_handle, uint8_t *config);
- int (*set_configuration)(struct libusb_device_handle *dev_handle, uint8_t config);
- int (*claim_interface)(struct libusb_device_handle *dev_handle, uint8_t interface_number);
- int (*release_interface)(struct libusb_device_handle *dev_handle, uint8_t interface_number);
- int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle,
- uint8_t interface_number, uint8_t altsetting);
- int (*clear_halt)(struct libusb_device_handle *dev_handle,
- unsigned char endpoint);
- int (*reset_device)(struct libusb_device_handle *dev_handle);
- void (*destroy_device)(struct libusb_device *dev);
- int (*submit_transfer)(struct usbi_transfer *itransfer);
- int (*cancel_transfer)(struct usbi_transfer *itransfer);
- void (*clear_transfer_priv)(struct usbi_transfer *itransfer);
- enum libusb_transfer_status (*copy_transfer_data)(struct usbi_transfer *itransfer, DWORD length);
-};
-
-struct windows_context_priv {
- const struct windows_backend *backend;
- HANDLE completion_port;
- HANDLE completion_port_thread;
-};
-
-union windows_device_priv {
- struct usbdk_device_priv usbdk_priv;
- struct winusb_device_priv winusb_priv;
-};
-
-struct windows_device_handle_priv {
- struct list_head active_transfers;
- union {
- struct usbdk_device_handle_priv usbdk_priv;
- struct winusb_device_handle_priv winusb_priv;
- };
-};
-
-struct windows_transfer_priv {
- OVERLAPPED overlapped;
- HANDLE handle;
- struct list_head list;
- union {
- struct usbdk_transfer_priv usbdk_priv;
- struct winusb_transfer_priv winusb_priv;
- };
-};
-
-static inline struct usbdk_device_handle_priv *get_usbdk_device_handle_priv(struct libusb_device_handle *dev_handle)
-{
- struct windows_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle);
- return &handle_priv->usbdk_priv;
-}
-
-static inline struct winusb_device_handle_priv *get_winusb_device_handle_priv(struct libusb_device_handle *dev_handle)
-{
- struct windows_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle);
- return &handle_priv->winusb_priv;
-}
-
-static inline OVERLAPPED *get_transfer_priv_overlapped(struct usbi_transfer *itransfer)
-{
- struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
- return &transfer_priv->overlapped;
-}
-
-static inline void set_transfer_priv_handle(struct usbi_transfer *itransfer, HANDLE handle)
-{
- struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
- transfer_priv->handle = handle;
-}
-
-static inline struct usbdk_transfer_priv *get_usbdk_transfer_priv(struct usbi_transfer *itransfer)
-{
- struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
- return &transfer_priv->usbdk_priv;
-}
-
-static inline struct winusb_transfer_priv *get_winusb_transfer_priv(struct usbi_transfer *itransfer)
-{
- struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
- return &transfer_priv->winusb_priv;
-}
-
-extern const struct windows_backend usbdk_backend;
-extern const struct windows_backend winusb_backend;
-
-HMODULE load_system_library(struct libusb_context *ctx, const char *name);
-unsigned long htab_hash(const char *str);
-enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS status);
-void windows_force_sync_completion(struct usbi_transfer *itransfer, ULONG size);
-
-#if defined(ENABLE_LOGGING)
-const char *windows_error_str(DWORD error_code);
-#endif
-
-#endif
diff --git a/src/os/windows_usbdk.c b/src/os/windows_usbdk.c
deleted file mode 100644
index 9f52b48..0000000
--- a/src/os/windows_usbdk.c
+++ /dev/null
@@ -1,724 +0,0 @@
-/*
- * windows UsbDk backend for libusb 1.0
- * Copyright © 2014 Red Hat, Inc.
-
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Pavel Gurvich <pavel@daynix.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 <windows.h>
-#include <stdio.h>
-
-#include "libusbi.h"
-#include "windows_usbdk.h"
-
-#if !defined(STATUS_SUCCESS)
-typedef LONG NTSTATUS;
-#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
-#endif
-
-#if !defined(STATUS_CANCELLED)
-#define STATUS_CANCELLED ((NTSTATUS)0xC0000120L)
-#endif
-
-#if !defined(STATUS_REQUEST_CANCELED)
-#define STATUS_REQUEST_CANCELED ((NTSTATUS)0xC0000703L)
-#endif
-
-static struct {
- HMODULE module;
-
- USBDK_GET_DEVICES_LIST GetDevicesList;
- USBDK_RELEASE_DEVICES_LIST ReleaseDevicesList;
- USBDK_START_REDIRECT StartRedirect;
- USBDK_STOP_REDIRECT StopRedirect;
- USBDK_GET_CONFIGURATION_DESCRIPTOR GetConfigurationDescriptor;
- USBDK_RELEASE_CONFIGURATION_DESCRIPTOR ReleaseConfigurationDescriptor;
- USBDK_READ_PIPE ReadPipe;
- USBDK_WRITE_PIPE WritePipe;
- USBDK_ABORT_PIPE AbortPipe;
- USBDK_RESET_PIPE ResetPipe;
- USBDK_SET_ALTSETTING SetAltsetting;
- USBDK_RESET_DEVICE ResetDevice;
- USBDK_GET_REDIRECTOR_SYSTEM_HANDLE GetRedirectorSystemHandle;
-} usbdk_helper;
-
-static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name)
-{
- FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name);
-
- if (api_ptr == NULL)
- usbi_err(ctx, "UsbDkHelper API %s not found: %s", api_name, windows_error_str(0));
-
- return api_ptr;
-}
-
-static void unload_usbdk_helper_dll(void)
-{
- if (usbdk_helper.module != NULL) {
- FreeLibrary(usbdk_helper.module);
- usbdk_helper.module = NULL;
- }
-}
-
-static int load_usbdk_helper_dll(struct libusb_context *ctx)
-{
- usbdk_helper.module = load_system_library(ctx, "UsbDkHelper");
- if (usbdk_helper.module == NULL) {
- usbi_err(ctx, "Failed to load UsbDkHelper.dll: %s", windows_error_str(0));
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbdk_helper.GetDevicesList = (USBDK_GET_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_GetDevicesList");
- if (usbdk_helper.GetDevicesList == NULL)
- goto error_unload;
-
- usbdk_helper.ReleaseDevicesList = (USBDK_RELEASE_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseDevicesList");
- if (usbdk_helper.ReleaseDevicesList == NULL)
- goto error_unload;
-
- usbdk_helper.StartRedirect = (USBDK_START_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StartRedirect");
- if (usbdk_helper.StartRedirect == NULL)
- goto error_unload;
-
- usbdk_helper.StopRedirect = (USBDK_STOP_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StopRedirect");
- if (usbdk_helper.StopRedirect == NULL)
- goto error_unload;
-
- usbdk_helper.GetConfigurationDescriptor = (USBDK_GET_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_GetConfigurationDescriptor");
- if (usbdk_helper.GetConfigurationDescriptor == NULL)
- goto error_unload;
-
- usbdk_helper.ReleaseConfigurationDescriptor = (USBDK_RELEASE_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseConfigurationDescriptor");
- if (usbdk_helper.ReleaseConfigurationDescriptor == NULL)
- goto error_unload;
-
- usbdk_helper.ReadPipe = (USBDK_READ_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ReadPipe");
- if (usbdk_helper.ReadPipe == NULL)
- goto error_unload;
-
- usbdk_helper.WritePipe = (USBDK_WRITE_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_WritePipe");
- if (usbdk_helper.WritePipe == NULL)
- goto error_unload;
-
- usbdk_helper.AbortPipe = (USBDK_ABORT_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_AbortPipe");
- if (usbdk_helper.AbortPipe == NULL)
- goto error_unload;
-
- usbdk_helper.ResetPipe = (USBDK_RESET_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ResetPipe");
- if (usbdk_helper.ResetPipe == NULL)
- goto error_unload;
-
- usbdk_helper.SetAltsetting = (USBDK_SET_ALTSETTING)get_usbdk_proc_addr(ctx, "UsbDk_SetAltsetting");
- if (usbdk_helper.SetAltsetting == NULL)
- goto error_unload;
-
- usbdk_helper.ResetDevice = (USBDK_RESET_DEVICE)get_usbdk_proc_addr(ctx, "UsbDk_ResetDevice");
- if (usbdk_helper.ResetDevice == NULL)
- goto error_unload;
-
- usbdk_helper.GetRedirectorSystemHandle = (USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)get_usbdk_proc_addr(ctx, "UsbDk_GetRedirectorSystemHandle");
- if (usbdk_helper.GetRedirectorSystemHandle == NULL)
- goto error_unload;
-
- return LIBUSB_SUCCESS;
-
-error_unload:
- FreeLibrary(usbdk_helper.module);
- usbdk_helper.module = NULL;
- return LIBUSB_ERROR_NOT_FOUND;
-}
-
-typedef SC_HANDLE (WINAPI *POPENSCMANAGERA)(LPCSTR, LPCSTR, DWORD);
-typedef SC_HANDLE (WINAPI *POPENSERVICEA)(SC_HANDLE, LPCSTR, DWORD);
-typedef BOOL (WINAPI *PCLOSESERVICEHANDLE)(SC_HANDLE);
-
-static int usbdk_init(struct libusb_context *ctx)
-{
- POPENSCMANAGERA pOpenSCManagerA;
- POPENSERVICEA pOpenServiceA;
- PCLOSESERVICEHANDLE pCloseServiceHandle;
- SC_HANDLE managerHandle;
- SC_HANDLE serviceHandle;
- HMODULE h;
-
- h = load_system_library(ctx, "Advapi32");
- if (h == NULL) {
- usbi_warn(ctx, "failed to open Advapi32\n");
- return LIBUSB_ERROR_OTHER;
- }
-
- pOpenSCManagerA = (POPENSCMANAGERA)GetProcAddress(h, "OpenSCManagerA");
- if (pOpenSCManagerA == NULL) {
- usbi_warn(ctx, "failed to find %s in Advapi32\n", "OpenSCManagerA");
- goto error_free_library;
- }
- pOpenServiceA = (POPENSERVICEA)GetProcAddress(h, "OpenServiceA");
- if (pOpenServiceA == NULL) {
- usbi_warn(ctx, "failed to find %s in Advapi32\n", "OpenServiceA");
- goto error_free_library;
- }
- pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(h, "CloseServiceHandle");
- if (pCloseServiceHandle == NULL) {
- usbi_warn(ctx, "failed to find %s in Advapi32\n", "CloseServiceHandle");
- goto error_free_library;
- }
-
- managerHandle = pOpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
- if (managerHandle == NULL) {
- usbi_warn(ctx, "failed to open service control manager: %s", windows_error_str(0));
- goto error_free_library;
- }
-
- serviceHandle = pOpenServiceA(managerHandle, "UsbDk", GENERIC_READ);
- pCloseServiceHandle(managerHandle);
-
- if (serviceHandle == NULL) {
- if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
- usbi_warn(ctx, "failed to open UsbDk service: %s", windows_error_str(0));
- FreeLibrary(h);
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- pCloseServiceHandle(serviceHandle);
- FreeLibrary(h);
-
- return load_usbdk_helper_dll(ctx);
-
-error_free_library:
- FreeLibrary(h);
- return LIBUSB_ERROR_OTHER;
-}
-
-static void usbdk_exit(struct libusb_context *ctx)
-{
- UNUSED(ctx);
- unload_usbdk_helper_dll();
-}
-
-static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
- PUSB_DK_DEVICE_ID id, unsigned long *session_id)
-{
- char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID) + 1];
-
- if (snprintf(dev_identity, sizeof(dev_identity), "%S%S", id->DeviceID, id->InstanceID) == -1) {
- usbi_warn(ctx, "cannot form device identity");
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-
- *session_id = htab_hash(dev_identity);
-
- return LIBUSB_SUCCESS;
-}
-
-static void usbdk_release_config_descriptors(struct usbdk_device_priv *priv, uint8_t count)
-{
- uint8_t i;
-
- for (i = 0; i < count; i++)
- usbdk_helper.ReleaseConfigurationDescriptor(priv->config_descriptors[i]);
-
- free(priv->config_descriptors);
- priv->config_descriptors = NULL;
-}
-
-static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
- struct usbdk_device_priv *priv, PUSB_DK_DEVICE_INFO info)
-{
- uint8_t i;
- USB_DK_CONFIG_DESCRIPTOR_REQUEST Request;
- Request.ID = info->ID;
-
- priv->config_descriptors = calloc(info->DeviceDescriptor.bNumConfigurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
- if (priv->config_descriptors == NULL) {
- usbi_err(ctx, "failed to allocate configuration descriptors holder");
- return LIBUSB_ERROR_NO_MEM;
- }
-
- for (i = 0; i < info->DeviceDescriptor.bNumConfigurations; i++) {
- ULONG Length;
-
- Request.Index = i;
- if (!usbdk_helper.GetConfigurationDescriptor(&Request, &priv->config_descriptors[i], &Length)) {
- usbi_err(ctx, "failed to retrieve configuration descriptors");
- usbdk_release_config_descriptors(priv, i);
- return LIBUSB_ERROR_OTHER;
- }
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static inline int usbdk_device_priv_init(struct libusb_context *ctx, struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
-{
- struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
-
- priv->ID = info->ID;
- priv->active_configuration = 0;
-
- return usbdk_cache_config_descriptors(ctx, priv, info);
-}
-
-static void usbdk_device_init(struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
-{
- dev->bus_number = (uint8_t)info->FilterID;
- dev->port_number = (uint8_t)info->Port;
- dev->parent_dev = NULL;
-
- // Addresses in libusb are 1-based
- dev->device_address = (uint8_t)(info->Port + 1);
-
- static_assert(sizeof(dev->device_descriptor) == sizeof(info->DeviceDescriptor),
- "mismatch between libusb and OS device descriptor sizes");
- memcpy(&dev->device_descriptor, &info->DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE);
- usbi_localize_device_descriptor(&dev->device_descriptor);
-
- switch (info->Speed) {
- case LowSpeed:
- dev->speed = LIBUSB_SPEED_LOW;
- break;
- case FullSpeed:
- dev->speed = LIBUSB_SPEED_FULL;
- break;
- case HighSpeed:
- dev->speed = LIBUSB_SPEED_HIGH;
- break;
- case SuperSpeed:
- dev->speed = LIBUSB_SPEED_SUPER;
- break;
- case NoSpeed:
- default:
- dev->speed = LIBUSB_SPEED_UNKNOWN;
- break;
- }
-}
-
-static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
-{
- int r = LIBUSB_SUCCESS;
- ULONG i;
- struct discovered_devs *discdevs = NULL;
- ULONG dev_number;
- PUSB_DK_DEVICE_INFO devices;
-
- if (!usbdk_helper.GetDevicesList(&devices, &dev_number))
- return LIBUSB_ERROR_OTHER;
-
- for (i = 0; i < dev_number; i++) {
- unsigned long session_id;
- struct libusb_device *dev = NULL;
-
- if (usbdk_get_session_id_for_device(ctx, &devices[i].ID, &session_id))
- continue;
-
- dev = usbi_get_device_by_session_id(ctx, session_id);
- if (dev == NULL) {
- dev = usbi_alloc_device(ctx, session_id);
- if (dev == NULL) {
- usbi_err(ctx, "failed to allocate a new device structure");
- continue;
- }
-
- usbdk_device_init(dev, &devices[i]);
- if (usbdk_device_priv_init(ctx, dev, &devices[i]) != LIBUSB_SUCCESS) {
- libusb_unref_device(dev);
- continue;
- }
- }
-
- discdevs = discovered_devs_append(*_discdevs, dev);
- libusb_unref_device(dev);
- if (!discdevs) {
- usbi_err(ctx, "cannot append new device to list");
- r = LIBUSB_ERROR_NO_MEM;
- goto func_exit;
- }
-
- *_discdevs = discdevs;
- }
-
-func_exit:
- usbdk_helper.ReleaseDevicesList(devices);
- return r;
-}
-
-static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, void *buffer, size_t len)
-{
- struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
- PUSB_CONFIGURATION_DESCRIPTOR config_header;
- size_t size;
-
- config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptors[config_index];
-
- size = min(config_header->wTotalLength, len);
- memcpy(buffer, config_header, size);
- return (int)size;
-}
-
-static int usbdk_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
- void **buffer)
-{
- struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
- PUSB_CONFIGURATION_DESCRIPTOR config_header;
- uint8_t index;
-
- for (index = 0; index < dev->device_descriptor.bNumConfigurations; index++) {
- config_header = priv->config_descriptors[index];
- if (config_header->bConfigurationValue == bConfigurationValue) {
- *buffer = priv->config_descriptors[index];
- return (int)config_header->wTotalLength;
- }
- }
-
- return LIBUSB_ERROR_NOT_FOUND;
-}
-
-static int usbdk_get_active_config_descriptor(struct libusb_device *dev, void *buffer, size_t len)
-{
- struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
-
- return usbdk_get_config_descriptor(dev, priv->active_configuration, buffer, len);
-}
-
-static int usbdk_open(struct libusb_device_handle *dev_handle)
-{
- struct libusb_device *dev = dev_handle->dev;
- struct libusb_context *ctx = DEVICE_CTX(dev);
- struct windows_context_priv *priv = usbi_get_context_priv(ctx);
- struct usbdk_device_priv *device_priv = usbi_get_device_priv(dev);
-
- device_priv->redirector_handle = usbdk_helper.StartRedirect(&device_priv->ID);
- if (device_priv->redirector_handle == INVALID_HANDLE_VALUE) {
- usbi_err(ctx, "Redirector startup failed");
- device_priv->redirector_handle = NULL;
- return LIBUSB_ERROR_OTHER;
- }
-
- device_priv->system_handle = usbdk_helper.GetRedirectorSystemHandle(device_priv->redirector_handle);
-
- if (CreateIoCompletionPort(device_priv->system_handle, priv->completion_port, (ULONG_PTR)dev_handle, 0) == NULL) {
- usbi_err(ctx, "failed to associate handle to I/O completion port: %s", windows_error_str(0));
- usbdk_helper.StopRedirect(device_priv->redirector_handle);
- device_priv->system_handle = NULL;
- device_priv->redirector_handle = NULL;
- return LIBUSB_ERROR_OTHER;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static void usbdk_close(struct libusb_device_handle *dev_handle)
-{
- struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- if (!usbdk_helper.StopRedirect(priv->redirector_handle))
- usbi_err(HANDLE_CTX(dev_handle), "Redirector shutdown failed");
-
- priv->system_handle = NULL;
- priv->redirector_handle = NULL;
-}
-
-static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config)
-{
- struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- *config = priv->active_configuration;
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_set_configuration(struct libusb_device_handle *dev_handle, uint8_t config)
-{
- UNUSED(dev_handle);
- UNUSED(config);
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, uint8_t iface)
-{
- UNUSED(dev_handle);
- UNUSED(iface);
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting)
-{
- struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) {
- usbi_err(HANDLE_CTX(dev_handle), "SetAltsetting failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_release_interface(struct libusb_device_handle *dev_handle, uint8_t iface)
-{
- UNUSED(dev_handle);
- UNUSED(iface);
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
-{
- struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) {
- usbi_err(HANDLE_CTX(dev_handle), "ResetPipe failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
-{
- struct usbdk_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- if (!usbdk_helper.ResetDevice(priv->redirector_handle)) {
- usbi_err(HANDLE_CTX(dev_handle), "ResetDevice failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static void usbdk_destroy_device(struct libusb_device *dev)
-{
- struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
-
- if (priv->config_descriptors != NULL)
- usbdk_release_config_descriptors(priv, dev->device_descriptor.bNumConfigurations);
-}
-
-static void usbdk_clear_transfer_priv(struct usbi_transfer *itransfer)
-{
- struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-
- if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
- safe_free(transfer_priv->IsochronousPacketsArray);
- safe_free(transfer_priv->IsochronousResultsArray);
- }
-}
-
-static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct usbdk_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
- OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
- TransferResult transResult;
-
- transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
- transfer_priv->request.BufferLength = transfer->length;
- transfer_priv->request.TransferType = ControlTransferType;
-
- set_transfer_priv_handle(itransfer, priv->system_handle);
-
- if (transfer->buffer[0] & LIBUSB_ENDPOINT_IN)
- transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
- else
- transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
-
- switch (transResult) {
- case TransferSuccess:
- windows_force_sync_completion(itransfer, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
- break;
- case TransferSuccessAsync:
- break;
- case TransferFailure:
- usbi_err(TRANSFER_CTX(transfer), "ControlTransfer failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_IO;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct usbdk_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
- OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
- TransferResult transferRes;
-
- transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
- transfer_priv->request.BufferLength = transfer->length;
- transfer_priv->request.EndpointAddress = transfer->endpoint;
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_BULK:
- transfer_priv->request.TransferType = BulkTransferType;
- break;
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- transfer_priv->request.TransferType = InterruptTransferType;
- break;
- }
-
- set_transfer_priv_handle(itransfer, priv->system_handle);
-
- if (IS_XFERIN(transfer))
- transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
- else
- transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
-
- switch (transferRes) {
- case TransferSuccess:
- windows_force_sync_completion(itransfer, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
- break;
- case TransferSuccessAsync:
- break;
- case TransferFailure:
- usbi_err(TRANSFER_CTX(transfer), "ReadPipe/WritePipe failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_IO;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct usbdk_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
- OVERLAPPED *overlapped = get_transfer_priv_overlapped(itransfer);
- TransferResult transferRes;
- int i;
-
- transfer_priv->request.Buffer = (PVOID64)transfer->buffer;
- transfer_priv->request.BufferLength = transfer->length;
- transfer_priv->request.EndpointAddress = transfer->endpoint;
- transfer_priv->request.TransferType = IsochronousTransferType;
- transfer_priv->request.IsochronousPacketsArraySize = transfer->num_iso_packets;
- transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64));
- transfer_priv->request.IsochronousPacketsArray = (PVOID64)transfer_priv->IsochronousPacketsArray;
- if (!transfer_priv->IsochronousPacketsArray) {
- usbi_err(TRANSFER_CTX(transfer), "Allocation of IsochronousPacketsArray failed");
- return LIBUSB_ERROR_NO_MEM;
- }
-
- transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT));
- transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)transfer_priv->IsochronousResultsArray;
- if (!transfer_priv->IsochronousResultsArray) {
- usbi_err(TRANSFER_CTX(transfer), "Allocation of isochronousResultsArray failed");
- return LIBUSB_ERROR_NO_MEM;
- }
-
- for (i = 0; i < transfer->num_iso_packets; i++)
- transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
-
- set_transfer_priv_handle(itransfer, priv->system_handle);
-
- if (IS_XFERIN(transfer))
- transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, overlapped);
- else
- transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, overlapped);
-
- switch (transferRes) {
- case TransferSuccess:
- windows_force_sync_completion(itransfer, (ULONG)transfer_priv->request.Result.GenResult.BytesTransferred);
- break;
- case TransferSuccessAsync:
- break;
- case TransferFailure:
- return LIBUSB_ERROR_IO;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_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 usbdk_do_control_transfer(itransfer);
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
- return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk
- return usbdk_do_bulk_transfer(itransfer);
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- return usbdk_do_iso_transfer(itransfer);
- default:
- // Should not get here since windows_submit_transfer() validates
- // the transfer->type field
- usbi_err(TRANSFER_CTX(transfer), "unsupported endpoint type %d", transfer->type);
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-}
-
-static enum libusb_transfer_status usbdk_copy_transfer_data(struct usbi_transfer *itransfer, DWORD length)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct usbdk_transfer_priv *transfer_priv = get_usbdk_transfer_priv(itransfer);
-
- UNUSED(length);
-
- if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
- ULONG64 i;
-
- for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
- struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
-
- switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
- case STATUS_SUCCESS:
- case STATUS_CANCELLED:
- case STATUS_REQUEST_CANCELED:
- lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS
- break;
- default:
- lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION;
- break;
- }
-
- lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength;
- }
- }
-
- itransfer->transferred += (int)transfer_priv->request.Result.GenResult.BytesTransferred;
- return usbd_status_to_libusb_transfer_status((USBD_STATUS)transfer_priv->request.Result.GenResult.UsbdStatus);
-}
-
-const struct windows_backend usbdk_backend = {
- usbdk_init,
- usbdk_exit,
- usbdk_get_device_list,
- usbdk_open,
- usbdk_close,
- usbdk_get_active_config_descriptor,
- usbdk_get_config_descriptor,
- usbdk_get_config_descriptor_by_value,
- usbdk_get_configuration,
- usbdk_set_configuration,
- usbdk_claim_interface,
- usbdk_release_interface,
- usbdk_set_interface_altsetting,
- usbdk_clear_halt,
- usbdk_reset_device,
- usbdk_destroy_device,
- usbdk_submit_transfer,
- NULL, /* cancel_transfer */
- usbdk_clear_transfer_priv,
- usbdk_copy_transfer_data,
-};
diff --git a/src/os/windows_usbdk.h b/src/os/windows_usbdk.h
deleted file mode 100644
index 0eb3779..0000000
--- a/src/os/windows_usbdk.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
-* windows UsbDk backend for libusb 1.0
-* Copyright © 2014 Red Hat, Inc.
-
-* Authors:
-* Dmitry Fleytman <dmitry@daynix.com>
-* Pavel Gurvich <pavel@daynix.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_WINDOWS_USBDK_H
-#define LIBUSB_WINDOWS_USBDK_H
-
-#include "windows_common.h"
-
-typedef struct USB_DK_CONFIG_DESCRIPTOR_REQUEST {
- USB_DK_DEVICE_ID ID;
- ULONG64 Index;
-} USB_DK_CONFIG_DESCRIPTOR_REQUEST, *PUSB_DK_CONFIG_DESCRIPTOR_REQUEST;
-
-typedef enum {
- TransferFailure = 0,
- TransferSuccess,
- TransferSuccessAsync
-} TransferResult;
-
-typedef enum {
- NoSpeed = 0,
- LowSpeed,
- FullSpeed,
- HighSpeed,
- SuperSpeed
-} USB_DK_DEVICE_SPEED;
-
-typedef enum {
- ControlTransferType,
- BulkTransferType,
- InterruptTransferType,
- IsochronousTransferType
-} USB_DK_TRANSFER_TYPE;
-
-typedef BOOL (__cdecl *USBDK_GET_DEVICES_LIST)(
- PUSB_DK_DEVICE_INFO *DeviceInfo,
- PULONG DeviceNumber
-);
-typedef void (__cdecl *USBDK_RELEASE_DEVICES_LIST)(
- PUSB_DK_DEVICE_INFO DeviceInfo
-);
-typedef HANDLE (__cdecl *USBDK_START_REDIRECT)(
- PUSB_DK_DEVICE_ID DeviceId
-);
-typedef BOOL (__cdecl *USBDK_STOP_REDIRECT)(
- HANDLE DeviceHandle
-);
-typedef BOOL (__cdecl *USBDK_GET_CONFIGURATION_DESCRIPTOR)(
- PUSB_DK_CONFIG_DESCRIPTOR_REQUEST Request,
- PUSB_CONFIGURATION_DESCRIPTOR *Descriptor,
- PULONG Length
-);
-typedef void (__cdecl *USBDK_RELEASE_CONFIGURATION_DESCRIPTOR)(
- PUSB_CONFIGURATION_DESCRIPTOR Descriptor
-);
-typedef TransferResult (__cdecl *USBDK_WRITE_PIPE)(
- HANDLE DeviceHandle,
- PUSB_DK_TRANSFER_REQUEST Request,
- LPOVERLAPPED lpOverlapped
-);
-typedef TransferResult (__cdecl *USBDK_READ_PIPE)(
- HANDLE DeviceHandle,
- PUSB_DK_TRANSFER_REQUEST Request,
- LPOVERLAPPED lpOverlapped
-);
-typedef BOOL (__cdecl *USBDK_ABORT_PIPE)(
- HANDLE DeviceHandle,
- ULONG64 PipeAddress
-);
-typedef BOOL (__cdecl *USBDK_RESET_PIPE)(
- HANDLE DeviceHandle,
- ULONG64 PipeAddress
-);
-typedef BOOL (__cdecl *USBDK_SET_ALTSETTING)(
- HANDLE DeviceHandle,
- ULONG64 InterfaceIdx,
- ULONG64 AltSettingIdx
-);
-typedef BOOL (__cdecl *USBDK_RESET_DEVICE)(
- HANDLE DeviceHandle
-);
-typedef HANDLE (__cdecl *USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)(
- HANDLE DeviceHandle
-);
-
-#endif
diff --git a/src/os/windows_winusb.c b/src/os/windows_winusb.c
deleted file mode 100644
index a03d6a5..0000000
--- a/src/os/windows_winusb.c
+++ /dev/null
@@ -1,4527 +0,0 @@
-/*
- * windows backend for libusb 1.0
- * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
- * Copyright © 2016-2018 Chris Dickens <christopher.a.dickens@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
- */
-
-#include <config.h>
-
-#include <windows.h>
-#include <setupapi.h>
-#include <ctype.h>
-#include <stdio.h>
-
-#include "libusbi.h"
-#include "windows_winusb.h"
-
-#define HANDLE_VALID(h) (((h) != NULL) && ((h) != INVALID_HANDLE_VALUE))
-
-// The below macro is used in conjunction with safe loops.
-#define LOOP_BREAK(err) \
- { \
- r = err; \
- continue; \
- }
-
-// WinUSB-like API prototypes
-static bool winusbx_init(struct libusb_context *ctx);
-static void winusbx_exit(void);
-static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle);
-static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle);
-static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
-static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
-static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
-static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting);
-static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
-static int winusbx_cancel_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
-static enum libusb_transfer_status winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length);
-// HID API prototypes
-static bool hid_init(struct libusb_context *ctx);
-static void hid_exit(void);
-static int hid_open(int sub_api, struct libusb_device_handle *dev_handle);
-static void hid_close(int sub_api, struct libusb_device_handle *dev_handle);
-static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
-static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
-static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting);
-static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
-static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
-static enum libusb_transfer_status hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length);
-// Composite API prototypes
-static int composite_open(int sub_api, struct libusb_device_handle *dev_handle);
-static void composite_close(int sub_api, struct libusb_device_handle *dev_handle);
-static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
-static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting);
-static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
-static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
-static int composite_cancel_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
-static enum libusb_transfer_status composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length);
-
-static usbi_mutex_t autoclaim_lock;
-
-// API globals
-static struct winusb_interface WinUSBX[SUB_API_MAX];
-#define CHECK_WINUSBX_AVAILABLE(sub_api) \
- do { \
- if (sub_api == SUB_API_NOTSET) \
- sub_api = priv->sub_api; \
- if (WinUSBX[sub_api].hDll == NULL) \
- return LIBUSB_ERROR_ACCESS; \
- } while (0)
-
-#define CHECK_HID_AVAILABLE \
- do { \
- if (DLL_HANDLE_NAME(hid) == NULL) \
- return LIBUSB_ERROR_ACCESS; \
- } while (0)
-
-#if defined(ENABLE_LOGGING)
-static const char *guid_to_string(const GUID *guid, char guid_string[MAX_GUID_STRING_LENGTH])
-{
- if (guid == NULL) {
- guid_string[0] = '\0';
- return guid_string;
- }
-
- sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
- (unsigned int)guid->Data1, guid->Data2, guid->Data3,
- 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
-
-static bool string_to_guid(const char guid_string[MAX_GUID_STRING_LENGTH], GUID *guid)
-{
- unsigned short tmp[4];
- int num_chars = -1;
- char extra;
- int r;
-
- // Unfortunately MinGW complains that '%hhx' is not a valid format specifier,
- // even though Visual Studio 2013 and later support it. Rather than complicating
- // the logic in this function with '#ifdef's, use a temporary array on the stack
- // to store the conversions.
- r = sscanf(guid_string, "{%8x-%4hx-%4hx-%4hx-%4hx%4hx%4hx}%n%c",
- (unsigned int *)&guid->Data1, &guid->Data2, &guid->Data3,
- &tmp[0], &tmp[1], &tmp[2], &tmp[3], &num_chars, &extra);
-
- if ((r != 7) || (num_chars != 38))
- return false;
-
- // Extract the bytes from the 2-byte shorts
- guid->Data4[0] = (unsigned char)((tmp[0] >> 8) & 0xFF);
- guid->Data4[1] = (unsigned char)(tmp[0] & 0xFF);
- guid->Data4[2] = (unsigned char)((tmp[1] >> 8) & 0xFF);
- guid->Data4[3] = (unsigned char)(tmp[1] & 0xFF);
- guid->Data4[4] = (unsigned char)((tmp[2] >> 8) & 0xFF);
- guid->Data4[5] = (unsigned char)(tmp[2] & 0xFF);
- guid->Data4[6] = (unsigned char)((tmp[3] >> 8) & 0xFF);
- guid->Data4[7] = (unsigned char)(tmp[3] & 0xFF);
-
- return true;
-}
-
-/*
- * Normalize Microsoft's paths: return a duplicate of the given path
- * with all characters converted to uppercase
- */
-static char *normalize_path(const char *path)
-{
- char *ret_path = _strdup(path);
- char *p;
-
- if (ret_path == NULL)
- return NULL;
-
- for (p = ret_path; *p != '\0'; p++)
- *p = (char)toupper((unsigned char)*p);
-
- return ret_path;
-}
-
-/*
- * Cfgmgr32, AdvAPI32, OLE32 and SetupAPI DLL functions
- */
-static bool init_dlls(struct libusb_context *ctx)
-{
- DLL_GET_HANDLE(ctx, Cfgmgr32);
- DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Parent, true);
- DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Child, true);
-
- // Prefixed to avoid conflict with header files
- DLL_GET_HANDLE(ctx, AdvAPI32);
- DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExA, true);
- DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, true);
-
- DLL_GET_HANDLE(ctx, SetupAPI);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, true);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, true);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInterfaces, true);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInstanceIdA, true);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInterfaceDetailA, true);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceRegistryPropertyA, true);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiDestroyDeviceInfoList, true);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDevRegKey, true);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDeviceInterfaceRegKey, true);
-
- return true;
-}
-
-static void exit_dlls(void)
-{
- DLL_FREE_HANDLE(SetupAPI);
- DLL_FREE_HANDLE(AdvAPI32);
- DLL_FREE_HANDLE(Cfgmgr32);
-}
-
-/*
- * 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)
- * enumerator: the generic USB class 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.
- */
-static bool get_devinfo_data(struct libusb_context *ctx,
- HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const char *enumerator, unsigned _index)
-{
- if (_index == 0) {
- *dev_info = pSetupDiGetClassDevsA(NULL, enumerator, NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES);
- if (*dev_info == INVALID_HANDLE_VALUE) {
- usbi_err(ctx, "could not obtain device info set for PnP enumerator '%s': %s",
- enumerator, windows_error_str(0));
- 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 PnP enumerator '%s' index %u: %s",
- enumerator, _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.
- */
-static int get_interface_details(struct libusb_context *ctx, HDEVINFO dev_info,
- PSP_DEVINFO_DATA dev_info_data, LPCGUID guid, DWORD *_index, char **dev_interface_path)
-{
- SP_DEVICE_INTERFACE_DATA dev_interface_data;
- PSP_DEVICE_INTERFACE_DETAIL_DATA_A dev_interface_details;
- char guid_string[MAX_GUID_STRING_LENGTH];
- DWORD size;
-
- dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
- dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- for (;;) {
- if (!pSetupDiEnumDeviceInfo(dev_info, *_index, dev_info_data)) {
- if (GetLastError() != ERROR_NO_MORE_ITEMS) {
- usbi_err(ctx, "Could not obtain device info data for %s index %lu: %s",
- guid_to_string(guid, guid_string), ULONG_CAST(*_index), windows_error_str(0));
- return LIBUSB_ERROR_OTHER;
- }
-
- // No more devices
- return LIBUSB_SUCCESS;
- }
-
- // Always advance the index for the next iteration
- (*_index)++;
-
- if (pSetupDiEnumDeviceInterfaces(dev_info, dev_info_data, guid, 0, &dev_interface_data))
- break;
-
- if (GetLastError() != ERROR_NO_MORE_ITEMS) {
- usbi_err(ctx, "Could not obtain interface data for %s devInst %lX: %s",
- guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0));
- return LIBUSB_ERROR_OTHER;
- }
-
- // Device does not have an interface matching this GUID, skip
- }
-
- // 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 %s devInst %lX: %s",
- guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0));
- return LIBUSB_ERROR_OTHER;
- }
- } else {
- usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong");
- return LIBUSB_ERROR_OTHER;
- }
-
- dev_interface_details = malloc(size);
- if (dev_interface_details == NULL) {
- usbi_err(ctx, "could not allocate interface data for %s devInst %lX",
- guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst));
- return LIBUSB_ERROR_NO_MEM;
- }
-
- dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
- if (!pSetupDiGetDeviceInterfaceDetailA(dev_info, &dev_interface_data,
- dev_interface_details, size, NULL, NULL)) {
- usbi_err(ctx, "could not access interface data (actual) for %s devInst %lX: %s",
- guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0));
- free(dev_interface_details);
- return LIBUSB_ERROR_OTHER;
- }
-
- *dev_interface_path = normalize_path(dev_interface_details->DevicePath);
- free(dev_interface_details);
-
- if (*dev_interface_path == NULL) {
- usbi_err(ctx, "could not allocate interface path for %s devInst %lX",
- guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst));
- return LIBUSB_ERROR_NO_MEM;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-/* For libusb0 filter */
-static int get_interface_details_filter(struct libusb_context *ctx, HDEVINFO *dev_info,
- DWORD _index, char *filter_path, char **dev_interface_path)
-{
- const GUID *libusb0_guid = &GUID_DEVINTERFACE_LIBUSB0_FILTER;
- SP_DEVICE_INTERFACE_DATA dev_interface_data;
- PSP_DEVICE_INTERFACE_DETAIL_DATA_A dev_interface_details;
- HKEY hkey_dev_interface;
- DWORD size;
- int err = LIBUSB_ERROR_OTHER;
-
- if (_index == 0) {
- *dev_info = pSetupDiGetClassDevsA(libusb0_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
- if (*dev_info == INVALID_HANDLE_VALUE) {
- usbi_err(ctx, "could not obtain device info set: %s", windows_error_str(0));
- return LIBUSB_ERROR_OTHER;
- }
- }
-
- dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- if (!pSetupDiEnumDeviceInterfaces(*dev_info, NULL, libusb0_guid, _index, &dev_interface_data)) {
- if (GetLastError() != ERROR_NO_MORE_ITEMS) {
- usbi_err(ctx, "Could not obtain interface data for index %lu: %s",
- ULONG_CAST(_index), windows_error_str(0));
- goto err_exit;
- }
-
- pSetupDiDestroyDeviceInfoList(*dev_info);
- *dev_info = INVALID_HANDLE_VALUE;
- return LIBUSB_SUCCESS;
- }
-
- // 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 %lu: %s",
- ULONG_CAST(_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;
- }
-
- dev_interface_details = malloc(size);
- if (dev_interface_details == NULL) {
- usbi_err(ctx, "could not allocate interface data for index %lu", ULONG_CAST(_index));
- err = LIBUSB_ERROR_NO_MEM;
- 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, NULL, NULL)) {
- usbi_err(ctx, "could not access interface data (actual) for index %lu: %s",
- ULONG_CAST(_index), windows_error_str(0));
- free(dev_interface_details);
- goto err_exit;
- }
-
- *dev_interface_path = normalize_path(dev_interface_details->DevicePath);
- free(dev_interface_details);
-
- if (*dev_interface_path == NULL) {
- usbi_err(ctx, "could not allocate interface path for index %lu", ULONG_CAST(_index));
- err = LIBUSB_ERROR_NO_MEM;
- goto err_exit;
- }
-
- // [trobinso] lookup the libusb0 symbolic index.
- hkey_dev_interface = pSetupDiOpenDeviceInterfaceRegKey(*dev_info, &dev_interface_data, 0, KEY_READ);
- if (hkey_dev_interface != INVALID_HANDLE_VALUE) {
- DWORD libusb0_symboliclink_index = 0;
- DWORD value_length = sizeof(DWORD);
- LONG status;
-
- status = pRegQueryValueExA(hkey_dev_interface, "LUsb0", NULL, NULL,
- (LPBYTE)&libusb0_symboliclink_index, &value_length);
- if (status == ERROR_SUCCESS) {
- if (libusb0_symboliclink_index < 256) {
- // libusb0.sys is connected to this device instance.
- // If the the device interface guid is {F9F3FF14-AE21-48A0-8A25-8011A7A931D9} then it's a filter.
- sprintf(filter_path, "\\\\.\\libusb0-%04u", (unsigned int)libusb0_symboliclink_index);
- usbi_dbg(ctx, "assigned libusb0 symbolic link %s", filter_path);
- } else {
- // libusb0.sys was connected to this device instance at one time; but not anymore.
- }
- }
- pRegCloseKey(hkey_dev_interface);
- } else {
- usbi_warn(ctx, "could not open device interface registry key for index %lu: %s",
- ULONG_CAST(_index), windows_error_str(0));
- // TODO: should this be an error?
- }
-
- return LIBUSB_SUCCESS;
-
-err_exit:
- pSetupDiDestroyDeviceInfoList(*dev_info);
- *dev_info = INVALID_HANDLE_VALUE;
- return err;
-}
-
-/*
- * Returns the first known ancestor of a device
- */
-static struct libusb_device *get_ancestor(struct libusb_context *ctx,
- DEVINST devinst, PDEVINST _parent_devinst)
-{
- struct libusb_device *dev = NULL;
- DEVINST parent_devinst;
-
- while (dev == NULL) {
- if (CM_Get_Parent(&parent_devinst, devinst, 0) != CR_SUCCESS)
- break;
- devinst = parent_devinst;
- dev = usbi_get_device_by_session_id(ctx, (unsigned long)devinst);
- }
-
- if ((dev != NULL) && (_parent_devinst != NULL))
- *_parent_devinst = devinst;
-
- return dev;
-}
-
-/*
- * Determine which interface the given endpoint address belongs to
- */
-static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc, uint8_t ep)
-{
- const struct libusb_interface *intf;
- const struct libusb_interface_descriptor *intf_desc;
- uint8_t i, k;
- int j;
-
- for (i = 0; i < conf_desc->bNumInterfaces; i++) {
- intf = &conf_desc->interface[i];
- for (j = 0; j < intf->num_altsetting; j++) {
- intf_desc = &intf->altsetting[j];
- for (k = 0; k < intf_desc->bNumEndpoints; k++) {
- if (intf_desc->endpoint[k].bEndpointAddress == ep) {
- usbi_dbg(NULL, "found endpoint %02X on interface %d", intf_desc->bInterfaceNumber, i);
- return intf_desc->bInterfaceNumber;
- }
- }
- }
- }
-
- usbi_dbg(NULL, "endpoint %02X not found on any interface", ep);
- return LIBUSB_ERROR_NOT_FOUND;
-}
-
-/*
- * Open a device and associate the HANDLE with the context's I/O completion port
- */
-static HANDLE windows_open(struct libusb_device_handle *dev_handle, const char *path, DWORD access)
-{
- struct libusb_context *ctx = HANDLE_CTX(dev_handle);
- struct windows_context_priv *priv = usbi_get_context_priv(ctx);
- HANDLE handle;
-
- handle = CreateFileA(path, access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
- if (handle == INVALID_HANDLE_VALUE)
- return handle;
-
- if (CreateIoCompletionPort(handle, priv->completion_port, (ULONG_PTR)dev_handle, 0) == NULL) {
- usbi_err(ctx, "failed to associate handle to I/O completion port: %s", windows_error_str(0));
- CloseHandle(handle);
- return INVALID_HANDLE_VALUE;
- }
-
- return handle;
-}
-
-/*
- * Populate the endpoints addresses of the device_priv interface helper structs
- */
-static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- struct libusb_config_descriptor *conf_desc;
- const struct libusb_interface_descriptor *if_desc;
- int i, r;
-
- r = libusb_get_active_config_descriptor(dev_handle->dev, &conf_desc);
- if (r != LIBUSB_SUCCESS) {
- usbi_warn(HANDLE_CTX(dev_handle), "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(HANDLE_CTX(dev_handle), "no endpoints found for interface %u", iface);
- } else {
- priv->usb_interface[iface].endpoint = malloc(if_desc->bNumEndpoints);
- if (priv->usb_interface[iface].endpoint == NULL) {
- libusb_free_config_descriptor(conf_desc);
- return LIBUSB_ERROR_NO_MEM;
- }
- priv->usb_interface[iface].nb_endpoints = if_desc->bNumEndpoints;
- for (i = 0; i < if_desc->bNumEndpoints; i++) {
- priv->usb_interface[iface].endpoint[i] = if_desc->endpoint[i].bEndpointAddress;
- usbi_dbg(HANDLE_CTX(dev_handle), "(re)assigned endpoint %02X to interface %u", priv->usb_interface[iface].endpoint[i], iface);
- }
- }
- libusb_free_config_descriptor(conf_desc);
-
- // Extra init may be required to configure endpoints
- if (priv->apib->configure_endpoints)
- r = priv->apib->configure_endpoints(SUB_API_NOTSET, dev_handle, iface);
-
- if (r == LIBUSB_SUCCESS)
- priv->usb_interface[iface].current_altsetting = altsetting;
-
- return r;
-}
-
-// Lookup for a match in the list of API driver names
-// return -1 if not found, driver match number otherwise
-static int get_sub_api(char *driver, int api)
-{
- const char sep_str[2] = {LIST_SEPARATOR, 0};
- char *tok, *tmp_str;
- size_t len = strlen(driver);
- int i;
-
- if (len == 0)
- return SUB_API_NOTSET;
-
- tmp_str = _strdup(driver);
- if (tmp_str == NULL)
- return SUB_API_NOTSET;
-
- tok = strtok(tmp_str, sep_str);
- while (tok != NULL) {
- for (i = 0; i < usb_api_backend[api].nb_driver_names; i++) {
- if (_stricmp(tok, usb_api_backend[api].driver_name_list[i]) == 0) {
- free(tmp_str);
- return i;
- }
- }
- tok = strtok(NULL, sep_str);
- }
-
- free(tmp_str);
- return SUB_API_NOTSET;
-}
-
-/*
- * auto-claiming and auto-release helper functions
- */
-static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type)
-{
- struct winusb_device_handle_priv *handle_priv =
- get_winusb_device_handle_priv(transfer->dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- int current_interface = *interface_number;
- int r = LIBUSB_SUCCESS;
-
- switch (api_type) {
- case USB_API_WINUSBX:
- 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(TRANSFER_CTX(transfer), "auto-claimed interface %d for control request", current_interface);
- if (handle_priv->autoclaim_count[current_interface] != 0)
- usbi_err(TRANSFER_CTX(transfer), "program assertion failed - autoclaim_count was nonzero");
- handle_priv->autoclaim_count[current_interface]++;
- break;
- }
- }
- if (current_interface == USB_MAXINTERFACES) {
- usbi_err(TRANSFER_CTX(transfer), "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 winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- libusb_device_handle *dev_handle = transfer->dev_handle;
- struct winusb_device_handle_priv *handle_priv = get_winusb_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(ITRANSFER_CTX(itransfer), "auto-released interface %d", transfer_priv->interface_number);
- else
- usbi_dbg(ITRANSFER_CTX(itransfer), "failed to auto-release interface %d (%s)",
- transfer_priv->interface_number, libusb_error_name((enum libusb_error)r));
- }
- }
- usbi_mutex_unlock(&autoclaim_lock);
-}
-
-/*
- * init: libusb backend init function
- */
-static int winusb_init(struct libusb_context *ctx)
-{
- int i;
-
- // Load DLL imports
- if (!init_dlls(ctx)) {
- usbi_err(ctx, "could not resolve DLL functions");
- return LIBUSB_ERROR_OTHER;
- }
-
- // Initialize the low level APIs (we don't care about errors at this stage)
- for (i = 0; i < USB_API_MAX; i++) {
- if (usb_api_backend[i].init && !usb_api_backend[i].init(ctx))
- usbi_warn(ctx, "error initializing %s backend",
- usb_api_backend[i].designation);
- }
-
- // We need a lock for proper auto-release
- usbi_mutex_init(&autoclaim_lock);
-
- return LIBUSB_SUCCESS;
-}
-
-/*
-* exit: libusb backend deinitialization function
-*/
-static void winusb_exit(struct libusb_context *ctx)
-{
- int i;
-
- UNUSED(ctx);
-
- usbi_mutex_destroy(&autoclaim_lock);
-
- for (i = 0; i < USB_API_MAX; i++) {
- if (usb_api_backend[i].exit)
- usb_api_backend[i].exit();
- }
-
- exit_dlls();
-}
-
-/*
- * fetch and cache all the config descriptors through I/O
- */
-static void cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev);
- DWORD size, ret_size;
- uint8_t i, num_configurations;
-
- USB_CONFIGURATION_DESCRIPTOR_SHORT cd_buf_short; // dummy request
- PUSB_DESCRIPTOR_REQUEST cd_buf_actual = NULL; // actual request
- PUSB_CONFIGURATION_DESCRIPTOR cd_data;
-
- num_configurations = dev->device_descriptor.bNumConfigurations;
- if (num_configurations == 0)
- return;
-
- assert(sizeof(USB_DESCRIPTOR_REQUEST) == USB_DESCRIPTOR_REQUEST_SIZE);
-
- priv->config_descriptor = calloc(num_configurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
- if (priv->config_descriptor == NULL) {
- usbi_err(ctx, "could not allocate configuration descriptor array for '%s'", priv->dev_id);
- return;
- }
-
- for (i = 0; i <= num_configurations; i++) {
- safe_free(cd_buf_actual);
-
- if (i == num_configurations)
- break;
-
- size = sizeof(cd_buf_short);
- memset(&cd_buf_short.desc, 0, sizeof(cd_buf_short.desc));
-
- cd_buf_short.req.ConnectionIndex = (ULONG)dev->port_number;
- cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
- cd_buf_short.req.SetupPacket.bRequest = LIBUSB_REQUEST_GET_DESCRIPTOR;
- cd_buf_short.req.SetupPacket.wValue = (LIBUSB_DT_CONFIG << 8) | i;
- cd_buf_short.req.SetupPacket.wIndex = 0;
- cd_buf_short.req.SetupPacket.wLength = (USHORT)sizeof(USB_CONFIGURATION_DESCRIPTOR);
-
- // Dummy call to get the required data size. Initial failures are reported as info rather
- // than error as they can occur for non-penalizing situations, such as with some hubs.
- // coverity[tainted_data_argument]
- if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &cd_buf_short, size,
- &cd_buf_short, size, &ret_size, NULL)) {
- usbi_info(ctx, "could not access configuration descriptor %u (dummy) for '%s': %s", i, priv->dev_id, windows_error_str(0));
- continue;
- }
-
- if ((ret_size != size) || (cd_buf_short.desc.wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))) {
- usbi_info(ctx, "unexpected configuration descriptor %u size (dummy) for '%s'", i, priv->dev_id);
- continue;
- }
-
- size = sizeof(USB_DESCRIPTOR_REQUEST) + cd_buf_short.desc.wTotalLength;
- cd_buf_actual = malloc(size);
- if (cd_buf_actual == NULL) {
- usbi_err(ctx, "could not allocate configuration descriptor %u buffer for '%s'", i, priv->dev_id);
- continue;
- }
-
- // Actual call
- cd_buf_actual->ConnectionIndex = (ULONG)dev->port_number;
- cd_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
- cd_buf_actual->SetupPacket.bRequest = LIBUSB_REQUEST_GET_DESCRIPTOR;
- cd_buf_actual->SetupPacket.wValue = (LIBUSB_DT_CONFIG << 8) | i;
- cd_buf_actual->SetupPacket.wIndex = 0;
- cd_buf_actual->SetupPacket.wLength = cd_buf_short.desc.wTotalLength;
-
- 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 %u (actual) for '%s': %s", i, priv->dev_id, windows_error_str(0));
- continue;
- }
-
- cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR *)cd_buf_actual + USB_DESCRIPTOR_REQUEST_SIZE);
-
- if ((size != ret_size) || (cd_data->wTotalLength != cd_buf_short.desc.wTotalLength)) {
- usbi_err(ctx, "unexpected configuration descriptor %u size (actual) for '%s'", i, priv->dev_id);
- continue;
- }
-
- if (cd_data->bDescriptorType != LIBUSB_DT_CONFIG) {
- usbi_err(ctx, "descriptor %u not a configuration descriptor for '%s'", i, priv->dev_id);
- continue;
- }
-
- usbi_dbg(ctx, "cached config descriptor %u (bConfigurationValue=%u, %u bytes)",
- i, cd_data->bConfigurationValue, cd_data->wTotalLength);
-
- // Cache the descriptor
- priv->config_descriptor[i] = cd_data;
- cd_buf_actual = NULL;
- }
-}
-
-#define ROOT_HUB_FS_CONFIG_DESC_LENGTH 0x19
-#define ROOT_HUB_HS_CONFIG_DESC_LENGTH 0x19
-#define ROOT_HUB_SS_CONFIG_DESC_LENGTH 0x1f
-#define CONFIG_DESC_WTOTAL_LENGTH_OFFSET 0x02
-#define CONFIG_DESC_EP_MAX_PACKET_OFFSET 0x16
-#define CONFIG_DESC_EP_BINTERVAL_OFFSET 0x18
-
-static const uint8_t root_hub_config_descriptor_template[] = {
- // Configuration Descriptor
- LIBUSB_DT_CONFIG_SIZE, // bLength
- LIBUSB_DT_CONFIG, // bDescriptorType
- 0x00, 0x00, // wTotalLength (filled in)
- 0x01, // bNumInterfaces
- 0x01, // bConfigurationValue
- 0x00, // iConfiguration
- 0xc0, // bmAttributes (reserved + self-powered)
- 0x00, // bMaxPower
- // Interface Descriptor
- LIBUSB_DT_INTERFACE_SIZE, // bLength
- LIBUSB_DT_INTERFACE, // bDescriptorType
- 0x00, // bInterfaceNumber
- 0x00, // bAlternateSetting
- 0x01, // bNumEndpoints
- LIBUSB_CLASS_HUB, // bInterfaceClass
- 0x00, // bInterfaceSubClass
- 0x00, // bInterfaceProtocol
- 0x00, // iInterface
- // Endpoint Descriptor
- LIBUSB_DT_ENDPOINT_SIZE, // bLength
- LIBUSB_DT_ENDPOINT, // bDescriptorType
- 0x81, // bEndpointAddress
- 0x03, // bmAttributes (Interrupt)
- 0x00, 0x00, // wMaxPacketSize (filled in)
- 0x00, // bInterval (filled in)
- // SuperSpeed Endpoint Companion Descriptor
- LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE, // bLength
- LIBUSB_DT_SS_ENDPOINT_COMPANION, // bDescriptorType
- 0x00, // bMaxBurst
- 0x00, // bmAttributes
- 0x02, 0x00 // wBytesPerInterval
-};
-
-static int alloc_root_hub_config_desc(struct libusb_device *dev, ULONG num_ports,
- uint8_t config_desc_length, uint8_t ep_interval)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev);
- uint8_t *ptr;
-
- priv->config_descriptor = malloc(sizeof(*priv->config_descriptor));
- if (priv->config_descriptor == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- // Most config descriptors come from cache_config_descriptors() which obtains the
- // descriptors from the hub using an allocated USB_DESCRIPTOR_REQUEST structure.
- // To avoid an extra malloc + memcpy we just hold on to the USB_DESCRIPTOR_REQUEST
- // structure we already have and back up the pointer in windows_device_priv_release()
- // when freeing the descriptors. To keep a single execution path, we need to offset
- // the pointer here by the same amount.
- ptr = malloc(USB_DESCRIPTOR_REQUEST_SIZE + config_desc_length);
- if (ptr == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- ptr += USB_DESCRIPTOR_REQUEST_SIZE;
-
- memcpy(ptr, root_hub_config_descriptor_template, config_desc_length);
- ptr[CONFIG_DESC_WTOTAL_LENGTH_OFFSET] = config_desc_length;
- ptr[CONFIG_DESC_EP_MAX_PACKET_OFFSET] = (uint8_t)((num_ports + 7) / 8);
- ptr[CONFIG_DESC_EP_BINTERVAL_OFFSET] = ep_interval;
-
- priv->config_descriptor[0] = (PUSB_CONFIGURATION_DESCRIPTOR)ptr;
- priv->active_config = 1;
-
- return 0;
-}
-
-static int init_root_hub(struct libusb_device *dev)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev);
- USB_NODE_CONNECTION_INFORMATION_EX conn_info;
- USB_NODE_CONNECTION_INFORMATION_EX_V2 conn_info_v2;
- USB_NODE_INFORMATION hub_info;
- enum libusb_speed speed = LIBUSB_SPEED_UNKNOWN;
- uint8_t config_desc_length;
- uint8_t ep_interval;
- HANDLE handle;
- ULONG port_number, num_ports;
- DWORD size;
- int r;
-
- // Determining the speed of a root hub is painful. Microsoft does not directly report the speed
- // capabilities of the root hub itself, only its ports and/or connected devices. Therefore we
- // are forced to query each individual port of the root hub to try and infer the root hub's
- // speed. Note that we have to query all ports because the presence of a device on that port
- // changes if/how Windows returns any useful speed information.
- handle = CreateFileA(priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
- if (handle == INVALID_HANDLE_VALUE) {
- usbi_err(ctx, "could not open root hub %s: %s", priv->path, windows_error_str(0));
- return LIBUSB_ERROR_ACCESS;
- }
-
- if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_INFORMATION, NULL, 0, &hub_info, sizeof(hub_info), &size, NULL)) {
- usbi_warn(ctx, "could not get root hub info for '%s': %s", priv->dev_id, windows_error_str(0));
- CloseHandle(handle);
- return LIBUSB_ERROR_ACCESS;
- }
-
- num_ports = hub_info.u.HubInformation.HubDescriptor.bNumberOfPorts;
- usbi_dbg(ctx, "root hub '%s' reports %lu ports", priv->dev_id, ULONG_CAST(num_ports));
-
- if (windows_version >= WINDOWS_8) {
- // Windows 8 and later is better at reporting the speed capabilities of the root hub,
- // but it is not perfect. If no device is attached to the port being queried, the
- // returned information will only indicate whether that port supports USB 3.0 signalling.
- // That is not enough information to distinguish between SuperSpeed and SuperSpeed Plus.
- for (port_number = 1; port_number <= num_ports; port_number++) {
- conn_info_v2.ConnectionIndex = port_number;
- conn_info_v2.Length = sizeof(conn_info_v2);
- conn_info_v2.SupportedUsbProtocols.Usb300 = 1;
- if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2,
- &conn_info_v2, sizeof(conn_info_v2), &conn_info_v2, sizeof(conn_info_v2), &size, NULL)) {
- usbi_warn(ctx, "could not get node connection information (V2) for root hub '%s' port %lu: %s",
- priv->dev_id, ULONG_CAST(port_number), windows_error_str(0));
- break;
- }
-
- if (conn_info_v2.Flags.DeviceIsSuperSpeedPlusCapableOrHigher)
- speed = MAX(speed, LIBUSB_SPEED_SUPER_PLUS);
- else if (conn_info_v2.Flags.DeviceIsSuperSpeedCapableOrHigher || conn_info_v2.SupportedUsbProtocols.Usb300)
- speed = MAX(speed, LIBUSB_SPEED_SUPER);
- else if (conn_info_v2.SupportedUsbProtocols.Usb200)
- speed = MAX(speed, LIBUSB_SPEED_HIGH);
- else
- speed = MAX(speed, LIBUSB_SPEED_FULL);
- }
-
- if (speed != LIBUSB_SPEED_UNKNOWN)
- goto make_descriptors;
- }
-
- // At this point the speed is still not known, most likely because we are executing on
- // Windows 7 or earlier. The following hackery peeks into the root hub's Device ID and
- // tries to extract speed information from it, based on observed naming conventions.
- // If this does not work, we will query individual ports of the root hub.
- if (strstr(priv->dev_id, "ROOT_HUB31") != NULL)
- speed = LIBUSB_SPEED_SUPER_PLUS;
- else if (strstr(priv->dev_id, "ROOT_HUB30") != NULL)
- speed = LIBUSB_SPEED_SUPER;
- else if (strstr(priv->dev_id, "ROOT_HUB20") != NULL)
- speed = LIBUSB_SPEED_HIGH;
-
- if (speed != LIBUSB_SPEED_UNKNOWN)
- goto make_descriptors;
-
- // Windows only reports speed information about a connected device. This means that a root
- // hub with no connected devices or devices that are all operating at a speed less than the
- // highest speed that the root hub supports will not give us the correct speed.
- for (port_number = 1; port_number <= num_ports; port_number++) {
- conn_info.ConnectionIndex = port_number;
- if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, sizeof(conn_info),
- &conn_info, sizeof(conn_info), &size, NULL)) {
- usbi_warn(ctx, "could not get node connection information for root hub '%s' port %lu: %s",
- priv->dev_id, ULONG_CAST(port_number), windows_error_str(0));
- continue;
- }
-
- if (conn_info.ConnectionStatus != DeviceConnected)
- continue;
-
- if (conn_info.Speed == UsbHighSpeed) {
- speed = LIBUSB_SPEED_HIGH;
- break;
- }
- }
-
-make_descriptors:
- CloseHandle(handle);
-
- dev->device_descriptor.bLength = LIBUSB_DT_DEVICE_SIZE;
- dev->device_descriptor.bDescriptorType = LIBUSB_DT_DEVICE;
- dev->device_descriptor.bDeviceClass = LIBUSB_CLASS_HUB;
- if ((dev->device_descriptor.idVendor == 0) && (dev->device_descriptor.idProduct == 0)) {
- dev->device_descriptor.idVendor = 0x1d6b; // Linux Foundation
- dev->device_descriptor.idProduct = (uint16_t)speed;
- }
- dev->device_descriptor.bcdDevice = 0x0100;
- dev->device_descriptor.bNumConfigurations = 1;
-
- switch (speed) {
- case LIBUSB_SPEED_SUPER_PLUS:
- dev->device_descriptor.bcdUSB = 0x0310;
- config_desc_length = ROOT_HUB_SS_CONFIG_DESC_LENGTH;
- ep_interval = 0x0c; // 256ms
- break;
- case LIBUSB_SPEED_SUPER:
- dev->device_descriptor.bcdUSB = 0x0300;
- config_desc_length = ROOT_HUB_SS_CONFIG_DESC_LENGTH;
- ep_interval = 0x0c; // 256ms
- break;
- case LIBUSB_SPEED_HIGH:
- dev->device_descriptor.bcdUSB = 0x0200;
- config_desc_length = ROOT_HUB_HS_CONFIG_DESC_LENGTH;
- ep_interval = 0x0c; // 256ms
- break;
- case LIBUSB_SPEED_LOW: // Not used, but keeps compiler happy
- case LIBUSB_SPEED_UNKNOWN:
- // This case means absolutely no information about this root hub was determined.
- // There is not much choice than to be pessimistic and label this as a
- // full-speed device.
- speed = LIBUSB_SPEED_FULL;
- // fallthrough
- case LIBUSB_SPEED_FULL:
- dev->device_descriptor.bcdUSB = 0x0110;
- config_desc_length = ROOT_HUB_FS_CONFIG_DESC_LENGTH;
- ep_interval = 0xff; // 255ms
- break;
- default: // Impossible, buts keeps compiler happy
- usbi_err(ctx, "program assertion failed - unknown root hub speed");
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- if (speed >= LIBUSB_SPEED_SUPER) {
- dev->device_descriptor.bDeviceProtocol = 0x03; // USB 3.0 Hub
- dev->device_descriptor.bMaxPacketSize0 = 0x09; // 2^9 bytes
- } else {
- dev->device_descriptor.bMaxPacketSize0 = 0x40; // 64 bytes
- }
-
- dev->speed = speed;
-
- r = alloc_root_hub_config_desc(dev, num_ports, config_desc_length, ep_interval);
- if (r)
- usbi_err(ctx, "could not allocate config descriptor for root hub '%s'", priv->dev_id);
-
- return r;
-}
-
-/*
- * Populate a libusb device structure
- */
-static int init_device(struct libusb_device *dev, struct libusb_device *parent_dev,
- uint8_t port_number, DEVINST devinst)
-{
- struct libusb_context *ctx = NULL;
- struct libusb_device *tmp_dev;
- struct winusb_device_priv *priv, *parent_priv, *tmp_priv;
- USB_NODE_CONNECTION_INFORMATION_EX conn_info;
- USB_NODE_CONNECTION_INFORMATION_EX_V2 conn_info_v2;
- HANDLE hub_handle;
- DWORD size;
- uint8_t bus_number, depth;
- int r;
- int ginfotimeout;
-
- priv = usbi_get_device_priv(dev);
-
- // If the device is already initialized, we can stop here
- if (priv->initialized)
- return LIBUSB_SUCCESS;
-
- if (parent_dev != NULL) { // Not a HCD root hub
- ctx = DEVICE_CTX(dev);
- parent_priv = usbi_get_device_priv(parent_dev);
- if (parent_priv->apib->id != USB_API_HUB) {
- usbi_warn(ctx, "parent for device '%s' is not a hub", priv->dev_id);
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- // Calculate depth and fetch bus number
- bus_number = parent_dev->bus_number;
- if (bus_number == 0) {
- tmp_dev = get_ancestor(ctx, devinst, &devinst);
- if (tmp_dev != parent_dev) {
- usbi_err(ctx, "program assertion failed - first ancestor is not parent");
- return LIBUSB_ERROR_NOT_FOUND;
- }
- libusb_unref_device(tmp_dev);
-
- for (depth = 1; bus_number == 0; depth++) {
- tmp_dev = get_ancestor(ctx, devinst, &devinst);
- if (tmp_dev == NULL) {
- usbi_warn(ctx, "ancestor for device '%s' not found at depth %u", priv->dev_id, depth);
- return LIBUSB_ERROR_NO_DEVICE;
- }
- if (tmp_dev->bus_number != 0) {
- bus_number = tmp_dev->bus_number;
- tmp_priv = usbi_get_device_priv(tmp_dev);
- depth += tmp_priv->depth;
- }
- libusb_unref_device(tmp_dev);
- }
- } else {
- depth = parent_priv->depth + 1;
- }
-
- if (bus_number == 0) {
- usbi_err(ctx, "program assertion failed - bus number not found for '%s'", priv->dev_id);
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- dev->bus_number = bus_number;
- dev->port_number = port_number;
- dev->parent_dev = parent_dev;
- priv->depth = depth;
-
- hub_handle = CreateFileA(parent_priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
- if (hub_handle == INVALID_HANDLE_VALUE) {
- usbi_warn(ctx, "could not open hub %s: %s", parent_priv->path, windows_error_str(0));
- return LIBUSB_ERROR_ACCESS;
- }
-
- conn_info.ConnectionIndex = (ULONG)port_number;
- // coverity[tainted_data_argument]
- ginfotimeout = 20;
- do {
- if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, sizeof(conn_info),
- &conn_info, sizeof(conn_info), &size, NULL)) {
- usbi_warn(ctx, "could not get node connection information for device '%s': %s",
- priv->dev_id, windows_error_str(0));
- CloseHandle(hub_handle);
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- if (conn_info.ConnectionStatus == NoDeviceConnected) {
- usbi_err(ctx, "device '%s' is no longer connected!", priv->dev_id);
- CloseHandle(hub_handle);
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- if ((conn_info.DeviceDescriptor.bLength != LIBUSB_DT_DEVICE_SIZE)
- || (conn_info.DeviceDescriptor.bDescriptorType != LIBUSB_DT_DEVICE)) {
- SleepEx(50, TRUE);
- continue;
- }
-
- static_assert(sizeof(dev->device_descriptor) == sizeof(conn_info.DeviceDescriptor),
- "mismatch between libusb and OS device descriptor sizes");
- memcpy(&dev->device_descriptor, &conn_info.DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE);
- usbi_localize_device_descriptor(&dev->device_descriptor);
-
- priv->active_config = conn_info.CurrentConfigurationValue;
- if (priv->active_config == 0) {
- usbi_dbg(ctx, "0x%x:0x%x found %u configurations (not configured)",
- dev->device_descriptor.idVendor,
- dev->device_descriptor.idProduct,
- dev->device_descriptor.bNumConfigurations);
- SleepEx(50, TRUE);
- }
- } while (priv->active_config == 0 && --ginfotimeout >= 0);
-
- if ((conn_info.DeviceDescriptor.bLength != LIBUSB_DT_DEVICE_SIZE)
- || (conn_info.DeviceDescriptor.bDescriptorType != LIBUSB_DT_DEVICE)) {
- usbi_err(ctx, "device '%s' has invalid descriptor!", priv->dev_id);
- CloseHandle(hub_handle);
- return LIBUSB_ERROR_OTHER;
- }
-
- if (priv->active_config == 0) {
- usbi_info(ctx, "0x%x:0x%x found %u configurations but device isn't configured, "
- "forcing current configuration to 1",
- dev->device_descriptor.idVendor,
- dev->device_descriptor.idProduct,
- dev->device_descriptor.bNumConfigurations);
- priv->active_config = 1;
- } else {
- usbi_dbg(ctx, "found %u configurations (current config: %u)", dev->device_descriptor.bNumConfigurations, priv->active_config);
- }
-
- // Cache as many config descriptors as we can
- cache_config_descriptors(dev, hub_handle);
-
- // In their great wisdom, Microsoft decided to BREAK the USB speed report between Windows 7 and Windows 8
- if (windows_version >= WINDOWS_8) {
- conn_info_v2.ConnectionIndex = (ULONG)port_number;
- conn_info_v2.Length = sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2);
- conn_info_v2.SupportedUsbProtocols.Usb300 = 1;
- if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2,
- &conn_info_v2, sizeof(conn_info_v2), &conn_info_v2, sizeof(conn_info_v2), &size, NULL)) {
- usbi_warn(ctx, "could not get node connection information (V2) for device '%s': %s",
- priv->dev_id, windows_error_str(0));
- } else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher) {
- conn_info.Speed = UsbSuperSpeedPlus;
- } else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedOrHigher) {
- conn_info.Speed = UsbSuperSpeed;
- }
- }
-
- CloseHandle(hub_handle);
-
- if (conn_info.DeviceAddress > UINT8_MAX)
- usbi_err(ctx, "program assertion failed - device address overflow");
-
- dev->device_address = (uint8_t)conn_info.DeviceAddress;
-
- switch (conn_info.Speed) {
- case UsbLowSpeed: dev->speed = LIBUSB_SPEED_LOW; break;
- case UsbFullSpeed: dev->speed = LIBUSB_SPEED_FULL; break;
- case UsbHighSpeed: dev->speed = LIBUSB_SPEED_HIGH; break;
- case UsbSuperSpeed: dev->speed = LIBUSB_SPEED_SUPER; break;
- case UsbSuperSpeedPlus: dev->speed = LIBUSB_SPEED_SUPER_PLUS; break;
- default:
- usbi_warn(ctx, "unknown device speed %u", conn_info.Speed);
- break;
- }
- } else {
- r = init_root_hub(dev);
- if (r)
- return r;
- }
-
- r = usbi_sanitize_device(dev);
- if (r)
- return r;
-
- priv->initialized = true;
-
- usbi_dbg(ctx, "(bus: %u, addr: %u, depth: %u, port: %u): '%s'",
- dev->bus_number, dev->device_address, priv->depth, dev->port_number, priv->dev_id);
-
- return LIBUSB_SUCCESS;
-}
-
-static bool get_dev_port_number(HDEVINFO dev_info, SP_DEVINFO_DATA *dev_info_data, DWORD *port_nr)
-{
- char buffer[MAX_KEY_LENGTH];
- DWORD size;
-
- // First try SPDRP_LOCATION_INFORMATION, which returns a REG_SZ. The string *may* have a format
- // similar to "Port_#0002.Hub_#000D", in which case we can extract the port number. However, we
- // cannot extract the port if the returned string does not follow this format.
- if (pSetupDiGetDeviceRegistryPropertyA(dev_info, dev_info_data, SPDRP_LOCATION_INFORMATION,
- NULL, (PBYTE)buffer, sizeof(buffer), NULL)) {
- // Check for the required format.
- if (strncmp(buffer, "Port_#", 6) == 0) {
- *port_nr = atoi(buffer + 6);
- return true;
- }
- }
-
- // Next try SPDRP_LOCATION_PATHS, which returns a REG_MULTI_SZ (but we only examine the first
- // string in it). Each path has a format similar to,
- // "PCIROOT(B2)#PCI(0300)#PCI(0000)#USBROOT(0)#USB(1)#USB(2)#USBMI(3)", and the port number is
- // the number within the last "USB(x)" token.
- if (pSetupDiGetDeviceRegistryPropertyA(dev_info, dev_info_data, SPDRP_LOCATION_PATHS,
- NULL, (PBYTE)buffer, sizeof(buffer), NULL)) {
- // Find the last "#USB(x)" substring
- for (char *token = strrchr(buffer, '#'); token != NULL; token = strrchr(buffer, '#')) {
- if (strncmp(token, "#USB(", 5) == 0) {
- *port_nr = atoi(token + 5);
- return true;
- }
- // Shorten the string and try again.
- *token = '\0';
- }
- }
-
- // Lastly, try SPDRP_ADDRESS, which returns a REG_DWORD. The address *may* be the port number,
- // which is true for the Microsoft driver but may not be true for other drivers. However, we
- // have no other options here but to accept what it returns.
- return pSetupDiGetDeviceRegistryPropertyA(dev_info, dev_info_data, SPDRP_ADDRESS,
- NULL, (PBYTE)port_nr, sizeof(*port_nr), &size) && (size == sizeof(*port_nr));
-}
-
-static int enumerate_hcd_root_hub(struct libusb_context *ctx, const char *dev_id,
- uint8_t bus_number, DEVINST devinst)
-{
- struct libusb_device *dev;
- struct winusb_device_priv *priv;
- unsigned long session_id;
- DEVINST child_devinst;
-
- if (CM_Get_Child(&child_devinst, devinst, 0) != CR_SUCCESS) {
- usbi_warn(ctx, "could not get child devinst for '%s'", dev_id);
- return LIBUSB_SUCCESS;
- }
-
- session_id = (unsigned long)child_devinst;
- dev = usbi_get_device_by_session_id(ctx, session_id);
- if (dev == NULL) {
- usbi_err(ctx, "program assertion failed - HCD '%s' child not found", dev_id);
- return LIBUSB_SUCCESS;
- }
-
- if (dev->bus_number == 0) {
- // Only do this once
- usbi_dbg(ctx, "assigning HCD '%s' bus number %u", dev_id, bus_number);
- dev->bus_number = bus_number;
-
- if (sscanf(dev_id, "PCI\\VEN_%04hx&DEV_%04hx%*s", &dev->device_descriptor.idVendor, &dev->device_descriptor.idProduct) != 2)
- usbi_warn(ctx, "could not infer VID/PID of HCD root hub from '%s'", dev_id);
-
- priv = usbi_get_device_priv(dev);
- priv->root_hub = true;
- }
-
- libusb_unref_device(dev);
- return LIBUSB_SUCCESS;
-}
-
-// Returns the api type, or 0 if not found/unsupported
-static void get_api_type(HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data,
- int *api, int *sub_api)
-{
- // 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;
- int i, j;
-
- // 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, (PBYTE)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[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 unsupported 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;
- }
- usbi_dbg(NULL, "%s(s): %s", lookup[k].designation, lookup[k].list);
- } else {
- if (GetLastError() != ERROR_INVALID_DATA)
- usbi_dbg(NULL, "could not access %s: %s", lookup[k].designation, windows_error_str(0));
- lookup[k].list[0] = 0;
- }
- }
-
- for (i = 2; i < USB_API_MAX; i++) {
- for (k = 0; k < 3; k++) {
- j = get_sub_api(lookup[k].list, i);
- if (j >= 0) {
- usbi_dbg(NULL, "matched %s name against %s", lookup[k].designation,
- (i != USB_API_WINUSBX) ? usb_api_backend[i].designation : usb_api_backend[i].driver_name_list[j]);
- *api = i;
- *sub_api = j;
- return;
- }
- }
- }
-}
-
-static int set_composite_interface(struct libusb_context *ctx, struct libusb_device *dev,
- char *dev_interface_path, char *device_id, int api, int sub_api)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev);
- int interface_number;
- const char *mi_str;
-
- // Because MI_## are not necessarily in sequential order (some composite
- // devices will have only MI_00 & MI_03 for instance), we retrieve the actual
- // interface number from the path's MI value
- mi_str = strstr(device_id, "MI_");
- if ((mi_str != NULL) && isdigit((unsigned char)mi_str[3]) && isdigit((unsigned char)mi_str[4])) {
- interface_number = ((mi_str[3] - '0') * 10) + (mi_str[4] - '0');
- } else {
- usbi_warn(ctx, "failure to read interface number for %s, using default value", device_id);
- interface_number = 0;
- }
-
- if (interface_number >= USB_MAXINTERFACES) {
- usbi_warn(ctx, "interface %d too large - ignoring interface path %s", interface_number, dev_interface_path);
- return LIBUSB_ERROR_ACCESS;
- }
-
- if (priv->usb_interface[interface_number].path != NULL) {
- if (api == USB_API_HID) {
- // HID devices can have multiple collections (COL##) for each MI_## interface
- usbi_dbg(ctx, "interface[%d] already set - ignoring HID collection: %s",
- interface_number, device_id);
- return LIBUSB_ERROR_ACCESS;
- }
- // In other cases, just use the latest data
- safe_free(priv->usb_interface[interface_number].path);
- }
-
- usbi_dbg(ctx, "interface[%d] = %s", interface_number, dev_interface_path);
- priv->usb_interface[interface_number].path = dev_interface_path;
- priv->usb_interface[interface_number].apib = &usb_api_backend[api];
- priv->usb_interface[interface_number].sub_api = sub_api;
- if ((api == USB_API_HID) && (priv->hid == NULL)) {
- priv->hid = calloc(1, sizeof(struct hid_device_priv));
- if (priv->hid == NULL)
- return LIBUSB_ERROR_NO_MEM;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *dev,
- char *dev_interface_path)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev);
- uint8_t i;
-
- if (priv->hid == NULL) {
- usbi_err(ctx, "program assertion failed - parent is not HID");
- return LIBUSB_ERROR_NO_DEVICE;
- } else if (priv->hid->nb_interfaces == USB_MAXINTERFACES) {
- usbi_err(ctx, "program assertion failed - max USB interfaces reached for HID device");
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- for (i = 0; i < priv->hid->nb_interfaces; i++) {
- if ((priv->usb_interface[i].path != NULL) && strcmp(priv->usb_interface[i].path, dev_interface_path) == 0) {
- usbi_dbg(ctx, "interface[%u] already set to %s", i, dev_interface_path);
- return LIBUSB_ERROR_ACCESS;
- }
- }
-
- priv->usb_interface[priv->hid->nb_interfaces].path = dev_interface_path;
- priv->usb_interface[priv->hid->nb_interfaces].apib = &usb_api_backend[USB_API_HID];
- usbi_dbg(ctx, "interface[%u] = %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 winusb_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
-{
- struct discovered_devs *discdevs;
- HDEVINFO *dev_info, dev_info_intf, dev_info_enum;
- SP_DEVINFO_DATA dev_info_data;
- DWORD _index = 0;
- GUID hid_guid;
- int r = LIBUSB_SUCCESS;
- int api, sub_api;
- unsigned int pass, i, j;
- char enumerator[16];
- char dev_id[MAX_PATH_LENGTH];
- struct libusb_device *dev, *parent_dev;
- struct winusb_device_priv *priv, *parent_priv;
- char *dev_interface_path = NULL;
- unsigned long session_id;
- DWORD size, port_nr, reg_type, install_state;
- HKEY key;
- char guid_string[MAX_GUID_STRING_LENGTH];
- GUID *if_guid;
- LONG s;
-#define HUB_PASS 0
-#define DEV_PASS 1
-#define HCD_PASS 2
-#define GEN_PASS 3
-#define HID_PASS 4
-#define EXT_PASS 5
- // Keep a list of guids that will be enumerated
-#define GUID_SIZE_STEP 8
- const GUID **guid_list, **new_guid_list;
- unsigned int guid_size = GUID_SIZE_STEP;
- unsigned int nb_guids;
- // Keep a list of PnP enumerator strings that are found
- const char *usb_enumerator[8] = { "USB" };
- unsigned int nb_usb_enumerators = 1;
- unsigned int usb_enum_index = 0;
- // Keep a list of newly allocated devs to unref
-#define UNREF_SIZE_STEP 16
- libusb_device **unref_list, **new_unref_list;
- unsigned int unref_size = UNREF_SIZE_STEP;
- 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_list = malloc(guid_size * sizeof(void *));
- if (guid_list == NULL) {
- usbi_err(ctx, "failed to alloc guid list");
- return LIBUSB_ERROR_NO_MEM;
- }
-
- guid_list[HUB_PASS] = &GUID_DEVINTERFACE_USB_HUB;
- guid_list[DEV_PASS] = &GUID_DEVINTERFACE_USB_DEVICE;
- guid_list[HCD_PASS] = &GUID_DEVINTERFACE_USB_HOST_CONTROLLER;
- guid_list[GEN_PASS] = NULL;
- if (HidD_GetHidGuid != NULL) {
- HidD_GetHidGuid(&hid_guid);
- guid_list[HID_PASS] = &hid_guid;
- } else {
- guid_list[HID_PASS] = NULL;
- }
- nb_guids = EXT_PASS;
-
- unref_list = malloc(unref_size * sizeof(void *));
- if (unref_list == NULL) {
- usbi_err(ctx, "failed to alloc unref list");
- free((void *)guid_list);
- return LIBUSB_ERROR_NO_MEM;
- }
-
- dev_info_intf = pSetupDiGetClassDevsA(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
- if (dev_info_intf == INVALID_HANDLE_VALUE) {
- usbi_err(ctx, "failed to obtain device info list: %s", windows_error_str(0));
- free(unref_list);
- free((void *)guid_list);
- return LIBUSB_ERROR_OTHER;
- }
-
- for (pass = 0; ((pass < nb_guids) && (r == LIBUSB_SUCCESS)); pass++) {
-//#define ENUM_DEBUG
-#if defined(ENABLE_LOGGING) && defined(ENUM_DEBUG)
- const char * const passname[] = {"HUB", "DEV", "HCD", "GEN", "HID", "EXT"};
- usbi_dbg(ctx, "#### PROCESSING %ss %s", passname[MIN(pass, EXT_PASS)], guid_to_string(guid_list[pass], guid_string));
-#endif
- if ((pass == HID_PASS) && (guid_list[HID_PASS] == NULL))
- continue;
-
- dev_info = (pass != GEN_PASS) ? &dev_info_intf : &dev_info_enum;
-
- 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_path);
- 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 %u buses, skipping the rest", UINT8_MAX);
- break;
- }
-
- if (pass != GEN_PASS) {
- // Except for GEN, all passes deal with device interfaces
- r = get_interface_details(ctx, *dev_info, &dev_info_data, guid_list[pass], &_index, &dev_interface_path);
- if ((r != LIBUSB_SUCCESS) || (dev_interface_path == NULL)) {
- _index = 0;
- break;
- }
- } else {
- // Workaround for a Nec/Renesas USB 3.0 driver bug where root hubs are
- // being listed under the "NUSB3" PnP Symbolic Name rather than "USB".
- // The Intel USB 3.0 driver behaves similar, but uses "IUSB3"
- // The Intel Alpine Ridge USB 3.1 driver uses "IARUSB3"
- for (; usb_enum_index < nb_usb_enumerators; usb_enum_index++) {
- if (get_devinfo_data(ctx, dev_info, &dev_info_data, usb_enumerator[usb_enum_index], i))
- break;
- i = 0;
- }
- if (usb_enum_index == nb_usb_enumerators)
- break;
- }
-
- // Read the Device ID path
- if (!pSetupDiGetDeviceInstanceIdA(*dev_info, &dev_info_data, dev_id, sizeof(dev_id), NULL)) {
- usbi_warn(ctx, "could not read the device instance ID for devInst %lX, skipping",
- ULONG_CAST(dev_info_data.DevInst));
- continue;
- }
-
-#ifdef ENUM_DEBUG
- usbi_dbg(ctx, "PRO: %s", dev_id);
-#endif
-
- // Set API to use or get additional data from generic pass
- api = USB_API_UNSUPPORTED;
- sub_api = SUB_API_NOTSET;
- switch (pass) {
- case HCD_PASS:
- break;
- case HUB_PASS:
- api = USB_API_HUB;
- // Fetch the PnP enumerator class for this hub
- // This will allow us to enumerate all classes during the GEN pass
- if (!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_ENUMERATOR_NAME,
- NULL, (PBYTE)enumerator, sizeof(enumerator), NULL)) {
- usbi_err(ctx, "could not read enumerator string for device '%s': %s", dev_id, windows_error_str(0));
- LOOP_BREAK(LIBUSB_ERROR_OTHER);
- }
- for (j = 0; j < nb_usb_enumerators; j++) {
- if (strcmp(usb_enumerator[j], enumerator) == 0)
- break;
- }
- if (j == nb_usb_enumerators) {
- usbi_dbg(ctx, "found new PnP enumerator string '%s'", enumerator);
- if (nb_usb_enumerators < ARRAYSIZE(usb_enumerator)) {
- usb_enumerator[nb_usb_enumerators] = _strdup(enumerator);
- if (usb_enumerator[nb_usb_enumerators] != NULL) {
- nb_usb_enumerators++;
- } else {
- usbi_err(ctx, "could not allocate enumerator string '%s'", enumerator);
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- }
- } else {
- usbi_warn(ctx, "too many enumerator strings, some devices may not be accessible");
- }
- }
- break;
- case GEN_PASS:
- // We use the GEN pass to detect driverless devices...
- if (!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_DRIVER,
- NULL, NULL, 0, NULL) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
- usbi_info(ctx, "The following device has no driver: '%s'", dev_id);
- 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)
- break;
- // Look for both DeviceInterfaceGUIDs *and* DeviceInterfaceGUID, in that order
- // If multiple GUIDs just process the first and ignore the others
- size = sizeof(guid_string);
- s = pRegQueryValueExA(key, "DeviceInterfaceGUIDs", NULL, &reg_type,
- (LPBYTE)guid_string, &size);
- if (s == ERROR_FILE_NOT_FOUND)
- s = pRegQueryValueExA(key, "DeviceInterfaceGUID", NULL, &reg_type,
- (LPBYTE)guid_string, &size);
- pRegCloseKey(key);
- if (s == ERROR_FILE_NOT_FOUND) {
- break; /* no DeviceInterfaceGUID registered */
- } else if (s != ERROR_SUCCESS && s != ERROR_MORE_DATA) {
- usbi_warn(ctx, "unexpected error from pRegQueryValueExA for '%s'", dev_id);
- break;
- }
- // https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexa#remarks
- // - "string may not have been stored with the proper terminating null characters"
- // - "Note that REG_MULTI_SZ strings could have two terminating null characters"
- if ((reg_type == REG_SZ && size >= sizeof(guid_string) - sizeof(char))
- || (reg_type == REG_MULTI_SZ && size >= sizeof(guid_string) - 2 * sizeof(char))) {
- if (nb_guids == guid_size) {
- new_guid_list = realloc((void *)guid_list, (guid_size + GUID_SIZE_STEP) * sizeof(void *));
- if (new_guid_list == NULL) {
- usbi_err(ctx, "failed to realloc guid list");
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- }
- guid_list = new_guid_list;
- guid_size += GUID_SIZE_STEP;
- }
- if_guid = malloc(sizeof(*if_guid));
- if (if_guid == NULL) {
- usbi_err(ctx, "failed to alloc if_guid");
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- }
- if (!string_to_guid(guid_string, if_guid)) {
- usbi_warn(ctx, "device '%s' has malformed DeviceInterfaceGUID string '%s', skipping", dev_id, guid_string);
- free(if_guid);
- } else {
- // Check if we've already seen this GUID
- for (j = EXT_PASS; j < nb_guids; j++) {
- if (memcmp(guid_list[j], if_guid, sizeof(*if_guid)) == 0)
- break;
- }
- if (j == nb_guids) {
- usbi_dbg(ctx, "extra GUID: %s", guid_string);
- guid_list[nb_guids++] = if_guid;
- } else {
- // Duplicate, ignore
- free(if_guid);
- }
- }
- } else {
- usbi_warn(ctx, "unexpected type/size of DeviceInterfaceGUID for '%s'", dev_id);
- }
- 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,
- NULL, (PBYTE)&install_state, sizeof(install_state), &size)) || (size != sizeof(install_state))) {
- usbi_warn(ctx, "could not detect installation state of driver for '%s': %s",
- dev_id, windows_error_str(0));
- } else if (install_state != 0) {
- usbi_warn(ctx, "driver for device '%s' is reporting an issue (code: %lu) - skipping",
- dev_id, ULONG_CAST(install_state));
- continue;
- }
- get_api_type(dev_info, &dev_info_data, &api, &sub_api);
- break;
- }
-
- // Find parent device (for the passes that need it)
- if (pass >= GEN_PASS) {
- parent_dev = get_ancestor(ctx, dev_info_data.DevInst, NULL);
- if (parent_dev == NULL) {
- // Root hubs will not have a parent
- dev = usbi_get_device_by_session_id(ctx, (unsigned long)dev_info_data.DevInst);
- if (dev != NULL) {
- priv = usbi_get_device_priv(dev);
- if (priv->root_hub)
- goto track_unref;
- libusb_unref_device(dev);
- }
-
- usbi_dbg(ctx, "unlisted ancestor for '%s' (non USB HID, newly connected, etc.) - ignoring", dev_id);
- continue;
- }
-
- parent_priv = usbi_get_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)) {
- libusb_unref_device(parent_dev);
- continue;
- }
- }
-
- // Create new or match existing device, using the devInst as session id
- if ((pass <= GEN_PASS) && (pass != HCD_PASS)) { // For subsequent passes, we'll lookup the parent
- // These are the passes that create "new" devices
- session_id = (unsigned long)dev_info_data.DevInst;
- dev = usbi_get_device_by_session_id(ctx, session_id);
- if (dev == NULL) {
- alloc_device:
- usbi_dbg(ctx, "allocating new device for session [%lX]", session_id);
- dev = usbi_alloc_device(ctx, session_id);
- if (dev == NULL)
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
-
- priv = winusb_device_priv_init(dev);
- priv->dev_id = _strdup(dev_id);
- priv->class_guid = dev_info_data.ClassGuid;
- if (priv->dev_id == NULL) {
- libusb_unref_device(dev);
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- }
- } else {
- usbi_dbg(ctx, "found existing device for session [%lX]", session_id);
-
- priv = usbi_get_device_priv(dev);
- if (strcmp(priv->dev_id, dev_id) != 0) {
- usbi_dbg(ctx, "device instance ID for session [%lX] changed", session_id);
- usbi_disconnect_device(dev);
- libusb_unref_device(dev);
- goto alloc_device;
- }
- if (!IsEqualGUID(&priv->class_guid, &dev_info_data.ClassGuid)) {
- usbi_dbg(ctx, "device class GUID for session [%lX] changed", session_id);
- usbi_disconnect_device(dev);
- libusb_unref_device(dev);
- goto alloc_device;
- }
- }
-
- track_unref:
- // Keep track of devices that need unref
- if (unref_cur == unref_size) {
- new_unref_list = realloc(unref_list, (unref_size + UNREF_SIZE_STEP) * sizeof(void *));
- if (new_unref_list == NULL) {
- usbi_err(ctx, "could not realloc list for unref - aborting");
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- }
- unref_list = new_unref_list;
- unref_size += UNREF_SIZE_STEP;
- }
- unref_list[unref_cur++] = dev;
- }
-
- // Setup device
- switch (pass) {
- case HUB_PASS:
- case DEV_PASS:
- // If the device has already been setup, don't do it again
- if (priv->path != NULL)
- break;
- // Take care of API initialization
- priv->path = dev_interface_path;
- dev_interface_path = NULL;
- priv->apib = &usb_api_backend[api];
- priv->sub_api = sub_api;
- switch (api) {
- case USB_API_COMPOSITE:
- case USB_API_HUB:
- break;
- case USB_API_HID:
- priv->hid = calloc(1, sizeof(struct hid_device_priv));
- if (priv->hid == NULL)
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- break;
- default:
- // For other devices, the first interface is the same as the device
- priv->usb_interface[0].path = _strdup(priv->path);
- if (priv->usb_interface[0].path == NULL)
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- // 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 HCD_PASS:
- r = enumerate_hcd_root_hub(ctx, dev_id, (uint8_t)(i + 1), dev_info_data.DevInst);
- break;
- case GEN_PASS:
- port_nr = 0;
- if (!get_dev_port_number(*dev_info, &dev_info_data, &port_nr))
- usbi_warn(ctx, "could not retrieve port number for device '%s': %s", dev_id, windows_error_str(0));
- r = init_device(dev, parent_dev, (uint8_t)port_nr, dev_info_data.DevInst);
- if (r == LIBUSB_SUCCESS) {
- // 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 {
- // Failed to initialize a single device doesn't stop us from enumerating all other devices,
- // but we skip it (don't add to list of discovered devices)
- usbi_warn(ctx, "failed to initialize device '%s'", priv->dev_id);
- r = LIBUSB_SUCCESS;
- }
- break;
- default: // HID_PASS and later
- if (parent_priv->apib->id == USB_API_HID || parent_priv->apib->id == USB_API_COMPOSITE) {
- if (parent_priv->apib->id == USB_API_HID) {
- usbi_dbg(ctx, "setting HID interface for [%lX]:", parent_dev->session_data);
- r = set_hid_interface(ctx, parent_dev, dev_interface_path);
- } else {
- usbi_dbg(ctx, "setting composite interface for [%lX]:", parent_dev->session_data);
- r = set_composite_interface(ctx, parent_dev, dev_interface_path, dev_id, api, sub_api);
- }
- switch (r) {
- 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
- r = LIBUSB_SUCCESS;
- break;
- default:
- LOOP_BREAK(r);
- break;
- }
- }
- libusb_unref_device(parent_dev);
- break;
- }
- }
- }
-
- pSetupDiDestroyDeviceInfoList(dev_info_intf);
-
- // Free any additional GUIDs
- for (pass = EXT_PASS; pass < nb_guids; pass++)
- free((void *)guid_list[pass]);
- free((void *)guid_list);
-
- // Free any PnP enumerator strings
- for (i = 1; i < nb_usb_enumerators; i++)
- free((void *)usb_enumerator[i]);
-
- // Unref newly allocated devs
- for (i = 0; i < unref_cur; i++)
- libusb_unref_device(unref_list[i]);
- free(unref_list);
-
- return r;
-}
-
-static int winusb_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, void *buffer, size_t len)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev);
- PUSB_CONFIGURATION_DESCRIPTOR config_header;
-
- if ((priv->config_descriptor == NULL) || (priv->config_descriptor[config_index] == NULL))
- return LIBUSB_ERROR_NOT_FOUND;
-
- config_header = priv->config_descriptor[config_index];
-
- len = MIN(len, config_header->wTotalLength);
- memcpy(buffer, config_header, len);
- return (int)len;
-}
-
-static int winusb_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
- void **buffer)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev);
- PUSB_CONFIGURATION_DESCRIPTOR config_header;
- uint8_t index;
-
- if (priv->config_descriptor == NULL)
- return LIBUSB_ERROR_NOT_FOUND;
-
- for (index = 0; index < dev->device_descriptor.bNumConfigurations; index++) {
- config_header = priv->config_descriptor[index];
- if (config_header == NULL)
- continue;
- if (config_header->bConfigurationValue == bConfigurationValue) {
- *buffer = config_header;
- return (int)config_header->wTotalLength;
- }
- }
-
- return LIBUSB_ERROR_NOT_FOUND;
-}
-
-/*
- * return the cached copy of the active config descriptor
- */
-static int winusb_get_active_config_descriptor(struct libusb_device *dev, void *buffer, size_t len)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev);
- void *config_desc;
- int r;
-
- if (priv->active_config == 0)
- return LIBUSB_ERROR_NOT_FOUND;
-
- r = winusb_get_config_descriptor_by_value(dev, priv->active_config, &config_desc);
- if (r < 0)
- return r;
-
- len = MIN(len, (size_t)r);
- memcpy(buffer, config_desc, len);
- return (int)len;
-}
-
-static int winusb_open(struct libusb_device_handle *dev_handle)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- CHECK_SUPPORTED_API(priv->apib, open);
-
- return priv->apib->open(SUB_API_NOTSET, dev_handle);
-}
-
-static void winusb_close(struct libusb_device_handle *dev_handle)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- if (priv->apib->close)
- priv->apib->close(SUB_API_NOTSET, dev_handle);
-}
-
-static int winusb_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- *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 winusb_set_configuration(struct libusb_device_handle *dev_handle, uint8_t config)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- int r = LIBUSB_SUCCESS;
-
- r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_OUT |
- LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
- LIBUSB_REQUEST_SET_CONFIGURATION, config,
- 0, NULL, 0, 1000);
-
- if (r == LIBUSB_SUCCESS)
- priv->active_config = config;
-
- return r;
-}
-
-static int winusb_claim_interface(struct libusb_device_handle *dev_handle, uint8_t iface)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- int r;
-
- CHECK_SUPPORTED_API(priv->apib, claim_interface);
-
- safe_free(priv->usb_interface[iface].endpoint);
- priv->usb_interface[iface].nb_endpoints = 0;
-
- r = priv->apib->claim_interface(SUB_API_NOTSET, dev_handle, iface);
-
- if (r == LIBUSB_SUCCESS)
- r = windows_assign_endpoints(dev_handle, iface, 0);
-
- return r;
-}
-
-static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- int r;
-
- CHECK_SUPPORTED_API(priv->apib, set_interface_altsetting);
-
- safe_free(priv->usb_interface[iface].endpoint);
- priv->usb_interface[iface].nb_endpoints = 0;
-
- r = priv->apib->set_interface_altsetting(SUB_API_NOTSET, dev_handle, iface, altsetting);
-
- if (r == LIBUSB_SUCCESS)
- r = windows_assign_endpoints(dev_handle, iface, altsetting);
-
- return r;
-}
-
-static int winusb_release_interface(struct libusb_device_handle *dev_handle, uint8_t iface)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- CHECK_SUPPORTED_API(priv->apib, release_interface);
-
- return priv->apib->release_interface(SUB_API_NOTSET, dev_handle, iface);
-}
-
-static int winusb_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- CHECK_SUPPORTED_API(priv->apib, clear_halt);
-
- return priv->apib->clear_halt(SUB_API_NOTSET, dev_handle, endpoint);
-}
-
-static int winusb_reset_device(struct libusb_device_handle *dev_handle)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- CHECK_SUPPORTED_API(priv->apib, reset_device);
-
- return priv->apib->reset_device(SUB_API_NOTSET, dev_handle);
-}
-
-static void winusb_destroy_device(struct libusb_device *dev)
-{
- winusb_device_priv_release(dev);
-}
-
-static void winusb_clear_transfer_priv(struct usbi_transfer *itransfer)
-{
- struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- int sub_api = priv->sub_api;
-
- safe_free(transfer_priv->hid_buffer);
-
- if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS && sub_api == SUB_API_WINUSB) {
- if (transfer_priv->isoch_buffer_handle != NULL) {
- if (WinUSBX[sub_api].UnregisterIsochBuffer(transfer_priv->isoch_buffer_handle)) {
- transfer_priv->isoch_buffer_handle = NULL;
- } else {
- usbi_warn(TRANSFER_CTX(transfer), "failed to unregister WinUSB isoch buffer: %s", windows_error_str(0));
- }
- }
- }
-
- safe_free(transfer_priv->iso_context);
-
- // When auto claim is in use, attempt to release the auto-claimed interface
- auto_release(itransfer);
-}
-
-static int winusb_submit_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- int (*transfer_fn)(int, struct usbi_transfer *);
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- transfer_fn = priv->apib->submit_control_transfer;
- break;
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- transfer_fn = priv->apib->submit_bulk_transfer;
- break;
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- transfer_fn = priv->apib->submit_iso_transfer;
- break;
- default:
- // Should not get here since windows_submit_transfer() validates
- // the transfer->type field
- usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- if (transfer_fn == NULL) {
- usbi_warn(TRANSFER_CTX(transfer),
- "unsupported transfer type %d (unrecognized device driver)",
- transfer->type);
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-
- return transfer_fn(SUB_API_NOTSET, itransfer);
-}
-
-static int winusb_cancel_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
-
- CHECK_SUPPORTED_API(priv->apib, cancel_transfer);
-
- return priv->apib->cancel_transfer(SUB_API_NOTSET, itransfer);
-}
-
-static enum libusb_transfer_status winusb_copy_transfer_data(struct usbi_transfer *itransfer, DWORD length)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
-
- if (priv->apib->copy_transfer_data == NULL) {
- usbi_err(TRANSFER_CTX(transfer), "program assertion failed - no function to copy transfer data");
- return LIBUSB_TRANSFER_ERROR;
- }
-
- return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, length);
-}
-
-// NB: MSVC6 does not support named initializers.
-const struct windows_backend winusb_backend = {
- winusb_init,
- winusb_exit,
- winusb_get_device_list,
- winusb_open,
- winusb_close,
- winusb_get_active_config_descriptor,
- winusb_get_config_descriptor,
- winusb_get_config_descriptor_by_value,
- winusb_get_configuration,
- winusb_set_configuration,
- winusb_claim_interface,
- winusb_release_interface,
- winusb_set_interface_altsetting,
- winusb_clear_halt,
- winusb_reset_device,
- winusb_destroy_device,
- winusb_submit_transfer,
- winusb_cancel_transfer,
- winusb_clear_transfer_priv,
- winusb_copy_transfer_data,
-};
-
-/*
- * USB API backends
- */
-
-static const char * const composite_driver_names[] = {"USBCCGP"};
-static const char * const winusbx_driver_names[] = {"libusbK", "libusb0", "WinUSB"};
-static const char * const hid_driver_names[] = {"HIDUSB", "MOUHID", "KBDHID"};
-const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
- {
- USB_API_UNSUPPORTED,
- "Unsupported API",
- NULL, /* driver_name_list */
- 0, /* nb_driver_names */
- NULL, /* init */
- NULL, /* exit */
- NULL, /* open */
- NULL, /* close */
- NULL, /* configure_endpoints */
- NULL, /* claim_interface */
- NULL, /* set_interface_altsetting */
- NULL, /* release_interface */
- NULL, /* clear_halt */
- NULL, /* reset_device */
- NULL, /* submit_bulk_transfer */
- NULL, /* submit_iso_transfer */
- NULL, /* submit_control_transfer */
- NULL, /* cancel_transfer */
- NULL, /* copy_transfer_data */
- },
- {
- USB_API_HUB,
- "HUB API",
- NULL, /* driver_name_list */
- 0, /* nb_driver_names */
- NULL, /* init */
- NULL, /* exit */
- NULL, /* open */
- NULL, /* close */
- NULL, /* configure_endpoints */
- NULL, /* claim_interface */
- NULL, /* set_interface_altsetting */
- NULL, /* release_interface */
- NULL, /* clear_halt */
- NULL, /* reset_device */
- NULL, /* submit_bulk_transfer */
- NULL, /* submit_iso_transfer */
- NULL, /* submit_control_transfer */
- NULL, /* cancel_transfer */
- NULL, /* copy_transfer_data */
- },
- {
- USB_API_COMPOSITE,
- "Composite API",
- composite_driver_names,
- ARRAYSIZE(composite_driver_names),
- NULL, /* init */
- NULL, /* exit */
- composite_open,
- composite_close,
- NULL, /* configure_endpoints */
- 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_cancel_transfer,
- composite_copy_transfer_data,
- },
- {
- USB_API_WINUSBX,
- "WinUSB-like APIs",
- winusbx_driver_names,
- ARRAYSIZE(winusbx_driver_names),
- winusbx_init,
- winusbx_exit,
- winusbx_open,
- winusbx_close,
- winusbx_configure_endpoints,
- winusbx_claim_interface,
- winusbx_set_interface_altsetting,
- winusbx_release_interface,
- winusbx_clear_halt,
- winusbx_reset_device,
- winusbx_submit_bulk_transfer,
- winusbx_submit_iso_transfer,
- winusbx_submit_control_transfer,
- winusbx_cancel_transfer,
- winusbx_copy_transfer_data,
- },
- {
- USB_API_HID,
- "HID API",
- hid_driver_names,
- ARRAYSIZE(hid_driver_names),
- hid_init,
- hid_exit,
- hid_open,
- hid_close,
- NULL, /* configure_endpoints */
- hid_claim_interface,
- hid_set_interface_altsetting,
- hid_release_interface,
- hid_clear_halt,
- hid_reset_device,
- hid_submit_bulk_transfer,
- NULL, /* submit_iso_transfer */
- hid_submit_control_transfer,
- NULL, /* cancel_transfer */
- hid_copy_transfer_data,
- },
-};
-
-
-/*
- * WinUSB-like (WinUSB, libusb0/libusbK through libusbk DLL) API functions
- */
-#define WinUSB_Set(h, fn, required) \
- do { \
- WinUSBX[SUB_API_WINUSB].fn = (WinUsb_##fn##_t)GetProcAddress(h, "WinUsb_" #fn); \
- if (required && (WinUSBX[SUB_API_WINUSB].fn == NULL)) { \
- usbi_err(ctx, "GetProcAddress() failed for WinUsb_%s", #fn); \
- goto cleanup_winusb; \
- } \
- } while (0)
-
-#define libusbK_Set(sub_api, fn, required) \
- do { \
- pLibK_GetProcAddress((PVOID *)&WinUSBX[sub_api].fn, sub_api, KUSB_FNID_##fn); \
- if (required && (WinUSBX[sub_api].fn == NULL)) { \
- usbi_err(ctx, "LibK_GetProcAddress() failed for LibK_%s", #fn); \
- goto cleanup_libusbk; \
- } \
- } while (0)
-
-static bool winusbx_init(struct libusb_context *ctx)
-{
- HMODULE hWinUSB, hlibusbK;
-
- hWinUSB = load_system_library(ctx, "WinUSB");
- if (hWinUSB != NULL) {
- WinUSB_Set(hWinUSB, AbortPipe, true);
- WinUSB_Set(hWinUSB, ControlTransfer, true);
- WinUSB_Set(hWinUSB, FlushPipe, true);
- WinUSB_Set(hWinUSB, Free, true);
- WinUSB_Set(hWinUSB, GetAssociatedInterface, true);
- WinUSB_Set(hWinUSB, Initialize, true);
- WinUSB_Set(hWinUSB, ReadPipe, true);
- WinUSB_Set(hWinUSB, ResetPipe, true);
- WinUSB_Set(hWinUSB, SetCurrentAlternateSetting, true);
- WinUSB_Set(hWinUSB, SetPipePolicy, true);
- WinUSB_Set(hWinUSB, WritePipe, true);
-
- // Check for isochronous transfers support (available starting with Windows 8.1)
- WinUSB_Set(hWinUSB, ReadIsochPipeAsap, false);
- if (WinUSBX[SUB_API_WINUSB].ReadIsochPipeAsap != NULL) {
- WinUSB_Set(hWinUSB, QueryPipeEx, true);
- WinUSB_Set(hWinUSB, RegisterIsochBuffer, true);
- WinUSB_Set(hWinUSB, UnregisterIsochBuffer, true);
- WinUSB_Set(hWinUSB, WriteIsochPipeAsap, true);
- }
-
- WinUSBX[SUB_API_WINUSB].hDll = hWinUSB;
-
- usbi_info(ctx, "WinUSB DLL available (%s isoch support)",
- (WinUSBX[SUB_API_WINUSB].ReadIsochPipeAsap != NULL) ? "with" : "without");
-
-cleanup_winusb:
- if (WinUSBX[SUB_API_WINUSB].hDll == NULL) {
- usbi_err(ctx, "failed to initialize WinUSB");
- memset(&WinUSBX[SUB_API_WINUSB], 0, sizeof(WinUSBX[SUB_API_WINUSB]));
- FreeLibrary(hWinUSB);
- hWinUSB = NULL;
- }
- } else {
- usbi_info(ctx, "WinUSB DLL is not available");
- }
-
- hlibusbK = load_system_library(ctx, "libusbK");
- if (hlibusbK != NULL) {
- LibK_GetVersion_t pLibK_GetVersion;
- LibK_GetProcAddress_t pLibK_GetProcAddress;
- int sub_api = 0;
-
- pLibK_GetVersion = (LibK_GetVersion_t)GetProcAddress(hlibusbK, "LibK_GetVersion");
- if (pLibK_GetVersion != NULL) {
- KLIB_VERSION LibK_Version;
-
- pLibK_GetVersion(&LibK_Version);
- usbi_dbg(ctx, "libusbK DLL found, version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor,
- LibK_Version.Micro, LibK_Version.Nano);
- } else {
- usbi_dbg(ctx, "libusbK DLL found, version unknown");
- }
-
- pLibK_GetProcAddress = (LibK_GetProcAddress_t)GetProcAddress(hlibusbK, "LibK_GetProcAddress");
- if (pLibK_GetProcAddress == NULL) {
- usbi_err(ctx, "LibK_GetProcAddress() not found in libusbK DLL");
- goto cleanup_libusbk;
- }
-
- // NB: The below for loop works because the sub_api value for WinUSB
- // is a higher value than that of libusbK and libusb0
- for (; sub_api < SUB_API_WINUSB; sub_api++) {
- libusbK_Set(sub_api, AbortPipe, true);
- libusbK_Set(sub_api, ControlTransfer, true);
- libusbK_Set(sub_api, FlushPipe, true);
- libusbK_Set(sub_api, Free, true);
- libusbK_Set(sub_api, GetAssociatedInterface, true);
- libusbK_Set(sub_api, Initialize, true);
- libusbK_Set(sub_api, ReadPipe, true);
- libusbK_Set(sub_api, ResetPipe, true);
- libusbK_Set(sub_api, SetCurrentAlternateSetting, true);
- libusbK_Set(sub_api, SetPipePolicy, true);
- libusbK_Set(sub_api, WritePipe, true);
-
- // Optional isochronous support
- libusbK_Set(sub_api, IsoReadPipe, false);
- if (WinUSBX[sub_api].IsoReadPipe != NULL)
- libusbK_Set(sub_api, IsoWritePipe, true);
-
- // Optional device reset support
- libusbK_Set(sub_api, ResetDevice, false);
-
- WinUSBX[sub_api].hDll = hlibusbK;
- }
-
-cleanup_libusbk:
- if (sub_api < SUB_API_WINUSB) {
- usbi_err(ctx, "failed to initialize libusbK");
- while (sub_api >= 0) {
- memset(&WinUSBX[sub_api], 0, sizeof(WinUSBX[sub_api]));
- sub_api--;
- }
- FreeLibrary(hlibusbK);
- hlibusbK = NULL;
- }
- } else {
- usbi_info(ctx, "libusbK DLL is not available");
- }
-
- if ((hWinUSB == NULL) && (hlibusbK == NULL)) {
- usbi_warn(ctx, "neither WinUSB nor libusbK DLLs were found, "
- "you will not be able to access devices outside of enumeration");
- return false;
- }
-
- return true;
-}
-
-static void winusbx_exit(void)
-{
- bool loaded = false;
- HMODULE hDll;
-
- hDll = WinUSBX[SUB_API_LIBUSBK].hDll;
- if (hDll != NULL) {
- FreeLibrary(hDll);
- loaded = true;
- }
-
- hDll = WinUSBX[SUB_API_WINUSB].hDll;
- if (hDll != NULL) {
- FreeLibrary(hDll);
- loaded = true;
- }
-
- // Reset the WinUSBX API structures if something was loaded
- if (loaded)
- memset(&WinUSBX, 0, sizeof(WinUSBX));
-}
-
-// 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 winusbx_open(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- HANDLE file_handle;
- int i;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- // WinUSB requires a separate 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_WINUSBX)) {
- file_handle = windows_open(dev_handle, priv->usb_interface[i].path, GENERIC_READ | GENERIC_WRITE);
- if (file_handle == INVALID_HANDLE_VALUE) {
- usbi_err(HANDLE_CTX(dev_handle), "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0));
- switch (GetLastError()) {
- 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 winusbx_close(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- HANDLE handle;
- int i;
-
- if (sub_api == SUB_API_NOTSET)
- sub_api = priv->sub_api;
-
- if (WinUSBX[sub_api].hDll == NULL)
- return;
-
- if (priv->apib->id == USB_API_COMPOSITE) {
- // If this is a composite device, just free and close all WinUSB-like
- // interfaces directly (each is independent and not associated with another)
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if (priv->usb_interface[i].apib->id == USB_API_WINUSBX) {
- handle = handle_priv->interface_handle[i].api_handle;
- if (HANDLE_VALID(handle))
- WinUSBX[sub_api].Free(handle);
-
- handle = handle_priv->interface_handle[i].dev_handle;
- if (HANDLE_VALID(handle))
- CloseHandle(handle);
- }
- }
- } else {
- // If this is a WinUSB device, free all interfaces above interface 0,
- // then free and close interface 0 last
- for (i = 1; i < USB_MAXINTERFACES; i++) {
- handle = handle_priv->interface_handle[i].api_handle;
- if (HANDLE_VALID(handle))
- WinUSBX[sub_api].Free(handle);
- }
- handle = handle_priv->interface_handle[0].api_handle;
- if (HANDLE_VALID(handle))
- WinUSBX[sub_api].Free(handle);
-
- handle = handle_priv->interface_handle[0].dev_handle;
- if (HANDLE_VALID(handle))
- CloseHandle(handle);
- }
-}
-
-static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface)
-{
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- HANDLE winusb_handle = handle_priv->interface_handle[iface].api_handle;
- UCHAR policy;
- ULONG timeout = 0;
- uint8_t endpoint_address;
- int i;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- // With handle and endpoints 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 (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
- PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout))
- usbi_dbg(HANDLE_CTX(dev_handle), "failed to set PIPE_TRANSFER_TIMEOUT for control endpoint %02X", endpoint_address);
-
- if ((i == -1) || (sub_api == SUB_API_LIBUSB0))
- continue; // Other policies don't apply to control endpoint or libusb0
-
- policy = false;
- handle_priv->interface_handle[iface].zlp[endpoint_address] = WINUSB_ZLP_UNSET;
- if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
- SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy))
- usbi_dbg(HANDLE_CTX(dev_handle), "failed to disable SHORT_PACKET_TERMINATE for endpoint %02X", endpoint_address);
-
- if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
- IGNORE_SHORT_PACKETS, sizeof(UCHAR), &policy))
- usbi_dbg(HANDLE_CTX(dev_handle), "failed to disable IGNORE_SHORT_PACKETS for endpoint %02X", endpoint_address);
-
- policy = true;
- /* ALLOW_PARTIAL_READS must be enabled due to likely libusbK bug. See:
- https://sourceforge.net/mailarchive/message.php?msg_id=29736015 */
- if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
- ALLOW_PARTIAL_READS, sizeof(UCHAR), &policy))
- usbi_dbg(HANDLE_CTX(dev_handle), "failed to enable ALLOW_PARTIAL_READS for endpoint %02X", endpoint_address);
-
- if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
- AUTO_CLEAR_STALL, sizeof(UCHAR), &policy))
- usbi_dbg(HANDLE_CTX(dev_handle), "failed to enable AUTO_CLEAR_STALL for endpoint %02X", endpoint_address);
-
- if (sub_api == SUB_API_LIBUSBK) {
- if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
- ISO_ALWAYS_START_ASAP, sizeof(UCHAR), &policy))
- usbi_dbg(HANDLE_CTX(dev_handle), "failed to enable ISO_ALWAYS_START_ASAP for endpoint %02X", endpoint_address);
- }
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface)
-{
- struct libusb_context *ctx = HANDLE_CTX(dev_handle);
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE);
- HDEVINFO dev_info;
- char *dev_interface_path = NULL;
- char *dev_interface_path_guid_start;
- char filter_path[] = "\\\\.\\libusb0-0000";
- bool found_filter = false;
- HANDLE file_handle, winusb_handle;
- DWORD err, _index;
- int r;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- // If the device is composite, but using the default Windows composite parent driver (usbccgp)
- // or if it's the first WinUSB-like interface, we get a handle through Initialize().
- if ((is_using_usbccgp) || (iface == 0)) {
- // composite device (independent interfaces) or interface 0
- file_handle = handle_priv->interface_handle[iface].dev_handle;
- if (!HANDLE_VALID(file_handle))
- return LIBUSB_ERROR_NOT_FOUND;
-
- if (!WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
- handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
- err = GetLastError();
- switch (err) {
- case ERROR_BAD_COMMAND:
- // The device was disconnected
- usbi_err(ctx, "could not access interface %u: %s", iface, windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- default:
- // it may be that we're using the libusb0 filter driver.
- // TODO: can we move this whole business into the K/0 DLL?
- r = LIBUSB_SUCCESS;
- for (_index = 0; ; _index++) {
- safe_free(dev_interface_path);
-
- if (found_filter)
- break;
-
- r = get_interface_details_filter(ctx, &dev_info, _index, filter_path, &dev_interface_path);
- if ((r != LIBUSB_SUCCESS) || (dev_interface_path == NULL))
- break;
-
- // ignore GUID part
- dev_interface_path_guid_start = strchr(dev_interface_path, '{');
- if (dev_interface_path_guid_start == NULL)
- continue;
- *dev_interface_path_guid_start = '\0';
-
- if (strncmp(dev_interface_path, priv->usb_interface[iface].path, strlen(dev_interface_path)) == 0) {
- file_handle = windows_open(dev_handle, filter_path, GENERIC_READ | GENERIC_WRITE);
- if (file_handle != INVALID_HANDLE_VALUE) {
- if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
- // Replace the existing file handle with the working one
- CloseHandle(handle_priv->interface_handle[iface].dev_handle);
- handle_priv->interface_handle[iface].dev_handle = file_handle;
- found_filter = true;
- } else {
- usbi_err(ctx, "could not initialize filter driver for %s", filter_path);
- CloseHandle(file_handle);
- }
- } else {
- usbi_err(ctx, "could not open device %s: %s", filter_path, windows_error_str(0));
- }
- }
- }
- if (r != LIBUSB_SUCCESS)
- return r;
- if (!found_filter) {
- usbi_err(ctx, "could not access interface %u: %s", iface, windows_error_str(err));
- return LIBUSB_ERROR_ACCESS;
- }
- }
- }
- handle_priv->interface_handle[iface].api_handle = winusb_handle;
- } else {
- // For all other interfaces, use 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 (!HANDLE_VALID(winusb_handle)) {
- file_handle = handle_priv->interface_handle[0].dev_handle;
- if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
- handle_priv->interface_handle[0].api_handle = winusb_handle;
- usbi_warn(ctx, "auto-claimed interface 0 (required to claim %u with WinUSB)", iface);
- } else {
- usbi_warn(ctx, "failed to auto-claim interface 0 (required to claim %u with WinUSB): %s", iface, windows_error_str(0));
- return LIBUSB_ERROR_ACCESS;
- }
- }
- if (!WinUSBX[sub_api].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 %u: %s", iface, windows_error_str(0));
- return LIBUSB_ERROR_ACCESS;
- }
- }
- handle_priv->interface_handle[iface].dev_handle = handle_priv->interface_handle[0].dev_handle;
- }
- usbi_dbg(ctx, "claimed interface %u", iface);
- handle_priv->active_interface = iface;
-
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface)
-{
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- HANDLE winusb_handle;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- winusb_handle = handle_priv->interface_handle[iface].api_handle;
- if (!HANDLE_VALID(winusb_handle))
- return LIBUSB_ERROR_NOT_FOUND;
-
- WinUSBX[sub_api].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 winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- int i;
-
- if ((api_id < USB_API_WINUSBX) || (api_id > USB_API_HID)) {
- usbi_dbg(HANDLE_CTX(dev_handle), "unsupported API ID");
- return -1;
- }
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if (HANDLE_VALID(handle_priv->interface_handle[i].dev_handle)
- && HANDLE_VALID(handle_priv->interface_handle[i].api_handle)
- && (priv->usb_interface[i].apib->id == api_id))
- return i;
- }
-
- return -1;
-}
-
-/*
-* Check a specific interface is valid (of the same API type), for control transfers
-*/
-static int check_valid_interface(struct libusb_device_handle *dev_handle, unsigned short interface, int api_id)
-{
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- if (interface >= USB_MAXINTERFACES)
- return -1;
-
- if ((api_id < USB_API_WINUSBX) || (api_id > USB_API_HID)) {
- usbi_dbg(HANDLE_CTX(dev_handle), "unsupported API ID");
- return -1;
- }
-
- // try the requested interface
- if (HANDLE_VALID(handle_priv->interface_handle[interface].dev_handle)
- && HANDLE_VALID(handle_priv->interface_handle[interface].api_handle)
- && (priv->usb_interface[interface].apib->id == api_id))
- return interface;
-
- return -1;
-}
-
-/*
- * Lookup interface by endpoint address. -1 if not found
- */
-static int interface_by_endpoint(struct winusb_device_priv *priv,
- struct winusb_device_handle_priv *handle_priv, uint8_t endpoint_address)
-{
- int i, j;
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if (!HANDLE_VALID(handle_priv->interface_handle[i].api_handle))
- 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 winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle);
- PWINUSB_SETUP_PACKET setup = (PWINUSB_SETUP_PACKET)transfer->buffer;
- ULONG size, transferred;
- HANDLE winusb_handle;
- OVERLAPPED *overlapped;
- int current_interface;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
-
- // Windows places upper limits on the control transfer size
- // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-bandwidth-allocation#maximum-transfer-size
- if (size > MAX_CTRL_BUFFER_LENGTH)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- if ((setup->RequestType & 0x1F) == LIBUSB_RECIPIENT_INTERFACE)
- current_interface = check_valid_interface(transfer->dev_handle, setup->Index & 0xff, USB_API_WINUSBX);
- else
- current_interface = get_valid_interface(transfer->dev_handle, USB_API_WINUSBX);
- if (current_interface < 0) {
- if (auto_claim(transfer, &current_interface, USB_API_WINUSBX) != LIBUSB_SUCCESS)
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg(ITRANSFER_CTX(itransfer), "will use interface %d", current_interface);
-
- transfer_priv->interface_number = (uint8_t)current_interface;
- winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
- set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle);
- overlapped = get_transfer_priv_overlapped(itransfer);
-
- // Sending of set configuration control requests from WinUSB creates issues, except when using libusb0.sys
- if (sub_api != SUB_API_LIBUSB0
- && (LIBUSB_REQ_TYPE(setup->RequestType) == LIBUSB_REQUEST_TYPE_STANDARD)
- && (setup->Request == LIBUSB_REQUEST_SET_CONFIGURATION)) {
- if (setup->Value != priv->active_config) {
- usbi_warn(TRANSFER_CTX(transfer), "cannot set configuration other than the default one");
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
- windows_force_sync_completion(itransfer, 0);
- } else {
- if (!WinUSBX[sub_api].ControlTransfer(winusb_handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, &transferred, overlapped)) {
- if (GetLastError() != ERROR_IO_PENDING) {
- usbi_warn(TRANSFER_CTX(transfer), "ControlTransfer failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_IO;
- }
- } else {
- windows_force_sync_completion(itransfer, transferred);
- }
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting)
-{
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- HANDLE winusb_handle;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- winusb_handle = handle_priv->interface_handle[iface].api_handle;
- if (!HANDLE_VALID(winusb_handle)) {
- usbi_err(HANDLE_CTX(dev_handle), "interface must be claimed first");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- if (!WinUSBX[sub_api].SetCurrentAlternateSetting(winusb_handle, altsetting)) {
- usbi_err(HANDLE_CTX(dev_handle), "SetCurrentAlternateSetting failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_IO;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-
-static void WINAPI winusbx_native_iso_transfer_continue_stream_callback(struct libusb_transfer *transfer)
-{
- // If this callback is invoked, this means that we attempted to set ContinueStream
- // to TRUE when calling Read/WriteIsochPipeAsap in winusbx_do_iso_transfer.
- // The role of this callback is to fallback to ContinueStream = FALSE if the transfer
- // did not succeed.
-
- struct winusb_transfer_priv *transfer_priv =
- get_winusb_transfer_priv(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer));
- bool fallback = (transfer->status != LIBUSB_TRANSFER_COMPLETED);
- int idx;
-
- // Restore the user callback
- transfer->callback = transfer_priv->iso_user_callback;
-
- for (idx = 0; idx < transfer->num_iso_packets && !fallback; idx++) {
- if (transfer->iso_packet_desc[idx].status != LIBUSB_TRANSFER_COMPLETED)
- fallback = true;
- }
-
- if (!fallback) {
- // If the transfer was successful, we restore the user callback and call it.
- if (transfer->callback)
- transfer->callback(transfer);
- } else {
- // If the transfer wasn't successful we reschedule the transfer while forcing it
- // not to continue the stream. This might results in a 5-ms delay.
- transfer_priv->iso_break_stream = TRUE;
- libusb_submit_transfer(transfer);
- }
-}
-static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- HANDLE winusb_handle;
- OVERLAPPED *overlapped;
- BOOL ret;
- int current_interface;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
- if (current_interface < 0) {
- usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg(TRANSFER_CTX(transfer), "matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
-
- transfer_priv->interface_number = (uint8_t)current_interface;
- winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
- set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle);
- overlapped = get_transfer_priv_overlapped(itransfer);
-
- if ((sub_api == SUB_API_LIBUSBK) || (sub_api == SUB_API_LIBUSB0)) {
- int i;
- UINT offset;
- size_t iso_ctx_size;
- PKISO_CONTEXT iso_context;
-
- if (WinUSBX[sub_api].IsoReadPipe == NULL) {
- usbi_warn(TRANSFER_CTX(transfer), "libusbK DLL does not support isoch transfers");
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-
- iso_ctx_size = sizeof(KISO_CONTEXT) + (transfer->num_iso_packets * sizeof(KISO_PACKET));
- transfer_priv->iso_context = iso_context = calloc(1, iso_ctx_size);
- if (transfer_priv->iso_context == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- // start ASAP
- iso_context->StartFrame = 0;
- iso_context->NumberOfPackets = (SHORT)transfer->num_iso_packets;
-
- // convert the transfer packet lengths to iso_packet offsets
- offset = 0;
- for (i = 0; i < transfer->num_iso_packets; i++) {
- iso_context->IsoPackets[i].offset = offset;
- offset += transfer->iso_packet_desc[i].length;
- }
-
- if (IS_XFERIN(transfer)) {
- usbi_dbg(TRANSFER_CTX(transfer), "reading %d iso packets", transfer->num_iso_packets);
- ret = WinUSBX[sub_api].IsoReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, overlapped, iso_context);
- } else {
- usbi_dbg(TRANSFER_CTX(transfer), "writing %d iso packets", transfer->num_iso_packets);
- ret = WinUSBX[sub_api].IsoWritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, overlapped, iso_context);
- }
-
- if (!ret && GetLastError() != ERROR_IO_PENDING) {
- usbi_err(TRANSFER_CTX(transfer), "IsoReadPipe/IsoWritePipe failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_IO;
- }
-
- return LIBUSB_SUCCESS;
- } else if (sub_api == SUB_API_WINUSB) {
- WINUSB_PIPE_INFORMATION_EX pipe_info_ex = { 0 };
- WINUSB_ISOCH_BUFFER_HANDLE buffer_handle;
- ULONG iso_transfer_size_multiple;
- int out_transfer_length = 0;
- int idx;
-
- // Depending on the version of Microsoft WinUSB, isochronous transfers may not be supported.
- if (WinUSBX[sub_api].ReadIsochPipeAsap == NULL) {
- usbi_warn(TRANSFER_CTX(transfer), "WinUSB DLL does not support isoch transfers");
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-
- if (sizeof(struct libusb_iso_packet_descriptor) != sizeof(USBD_ISO_PACKET_DESCRIPTOR)) {
- usbi_err(TRANSFER_CTX(transfer), "size of WinUsb and libusb isoch packet descriptors don't match");
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-
- // Query the pipe extended information to find the pipe index corresponding to the endpoint.
- for (idx = 0; idx < priv->usb_interface[current_interface].nb_endpoints; ++idx) {
- ret = WinUSBX[sub_api].QueryPipeEx(winusb_handle, (UINT8)priv->usb_interface[current_interface].current_altsetting, (UCHAR)idx, &pipe_info_ex);
- if (!ret) {
- usbi_err(TRANSFER_CTX(transfer), "couldn't query interface settings for USB pipe with index %d. Error: %s", idx, windows_error_str(0));
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- if (pipe_info_ex.PipeId == transfer->endpoint && pipe_info_ex.PipeType == UsbdPipeTypeIsochronous)
- break;
- }
-
- // Make sure we found the index.
- if (idx == priv->usb_interface[current_interface].nb_endpoints) {
- usbi_err(TRANSFER_CTX(transfer), "couldn't find isoch endpoint 0x%02x", transfer->endpoint);
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- if (IS_XFERIN(transfer)) {
- int interval = pipe_info_ex.Interval;
-
- // For high-speed and SuperSpeed device, the interval is 2**(bInterval-1).
- if (transfer->dev_handle->dev->speed >= LIBUSB_SPEED_HIGH)
- interval = (1 << (pipe_info_ex.Interval - 1));
-
- // WinUSB only supports isoch transfers spanning a full USB frames. Later, we might be smarter about this
- // and allocate a temporary buffer. However, this is harder than it seems as its destruction would depend on overlapped
- // IO...
- iso_transfer_size_multiple = (pipe_info_ex.MaximumBytesPerInterval * 8) / interval;
- if (transfer->length % iso_transfer_size_multiple != 0) {
- usbi_err(TRANSFER_CTX(transfer), "length of isoch buffer must be a multiple of the MaximumBytesPerInterval * 8 / Interval");
- return LIBUSB_ERROR_INVALID_PARAM;
- }
- } else {
- // If this is an OUT transfer, we make sure the isoch packets are contiguous as this isn't supported otherwise.
- bool size_should_be_zero = false;
-
- for (idx = 0; idx < transfer->num_iso_packets; ++idx) {
- if ((size_should_be_zero && transfer->iso_packet_desc[idx].length != 0) ||
- (transfer->iso_packet_desc[idx].length != pipe_info_ex.MaximumBytesPerInterval && idx + 1 < transfer->num_iso_packets && transfer->iso_packet_desc[idx + 1].length > 0)) {
- usbi_err(TRANSFER_CTX(transfer), "isoch packets for OUT transfer with WinUSB must be contiguous in memory");
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- size_should_be_zero = (transfer->iso_packet_desc[idx].length == 0);
- out_transfer_length += transfer->iso_packet_desc[idx].length;
- }
- }
-
- if (transfer_priv->isoch_buffer_handle != NULL) {
- if (WinUSBX[sub_api].UnregisterIsochBuffer(transfer_priv->isoch_buffer_handle)) {
- transfer_priv->isoch_buffer_handle = NULL;
- } else {
- usbi_err(TRANSFER_CTX(transfer), "failed to unregister WinUSB isoch buffer: %s", windows_error_str(0));
- return LIBUSB_ERROR_OTHER;
- }
- }
-
- // Register the isoch buffer to the operating system.
- ret = WinUSBX[sub_api].RegisterIsochBuffer(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, &buffer_handle);
- if (!ret) {
- usbi_err(TRANSFER_CTX(transfer), "failed to register WinUSB isoch buffer: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_MEM;
- }
-
- // Important note: the WinUSB_Read/WriteIsochPipeAsap API requires a ContinueStream parameter that tells whether the isochronous
- // stream must be continued or if the WinUSB driver can schedule the transfer at its convenience. Profiling subsequent transfers
- // with ContinueStream = FALSE showed that 5 frames, i.e. about 5 milliseconds, were left empty between each transfer. This
- // is critical as this greatly diminish the achievable isochronous bandwidth. We solved the problem using the following strategy:
- // - Transfers are first scheduled with ContinueStream = TRUE and with winusbx_iso_transfer_continue_stream_callback as user callback.
- // - If the transfer succeeds, winusbx_iso_transfer_continue_stream_callback restore the user callback and calls its.
- // - If the transfer fails, winusbx_iso_transfer_continue_stream_callback reschedule the transfer and force ContinueStream = FALSE.
- if (!transfer_priv->iso_break_stream) {
- transfer_priv->iso_user_callback = transfer->callback;
- transfer->callback = winusbx_native_iso_transfer_continue_stream_callback;
- }
-
- // Initiate the transfers.
- if (IS_XFERIN(transfer))
- ret = WinUSBX[sub_api].ReadIsochPipeAsap(buffer_handle, 0, transfer->length, !transfer_priv->iso_break_stream, transfer->num_iso_packets, (PUSBD_ISO_PACKET_DESCRIPTOR)transfer->iso_packet_desc, overlapped);
- else
- ret = WinUSBX[sub_api].WriteIsochPipeAsap(buffer_handle, 0, out_transfer_length, !transfer_priv->iso_break_stream, overlapped);
-
- if (!ret && GetLastError() != ERROR_IO_PENDING) {
- usbi_err(TRANSFER_CTX(transfer), "ReadIsochPipeAsap/WriteIsochPipeAsap failed: %s", windows_error_str(0));
- if (!WinUSBX[sub_api].UnregisterIsochBuffer(buffer_handle))
- usbi_warn(TRANSFER_CTX(transfer), "failed to unregister WinUSB isoch buffer: %s", windows_error_str(0));
- return LIBUSB_ERROR_IO;
- }
-
- // Restore the ContinueStream parameter to TRUE.
- transfer_priv->iso_break_stream = FALSE;
-
- transfer_priv->isoch_buffer_handle = buffer_handle;
-
- return LIBUSB_SUCCESS;
- } else {
- PRINT_UNSUPPORTED_API(winusbx_submit_iso_transfer);
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-}
-
-static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- HANDLE winusb_handle;
- OVERLAPPED *overlapped;
- BOOL ret;
- int current_interface;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
- if (current_interface < 0) {
- usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg(TRANSFER_CTX(transfer), "matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
-
- transfer_priv->interface_number = (uint8_t)current_interface;
- winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
- set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle);
- overlapped = get_transfer_priv_overlapped(itransfer);
-
- if (IS_XFERIN(transfer)) {
- usbi_dbg(TRANSFER_CTX(transfer), "reading %d bytes", transfer->length);
- ret = WinUSBX[sub_api].ReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped);
- } else {
- // Set SHORT_PACKET_TERMINATE if ZLP requested.
- // Changing this can be a problem with packets in flight, so only allow on the first transfer.
- UCHAR policy = (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) != 0;
- uint8_t* current_zlp = &handle_priv->interface_handle[current_interface].zlp[transfer->endpoint];
- if (*current_zlp == WINUSB_ZLP_UNSET) {
- if (policy &&
- !WinUSBX[sub_api].SetPipePolicy(winusb_handle, transfer->endpoint,
- SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy)) {
- usbi_err(TRANSFER_CTX(transfer), "failed to set SHORT_PACKET_TERMINATE for endpoint %02X", transfer->endpoint);
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
- *current_zlp = policy ? WINUSB_ZLP_ON : WINUSB_ZLP_OFF;
- } else if (policy != (*current_zlp == WINUSB_ZLP_ON)) {
- usbi_err(TRANSFER_CTX(transfer), "cannot change ZERO_PACKET for endpoint %02X on Windows", transfer->endpoint);
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-
- usbi_dbg(TRANSFER_CTX(transfer), "writing %d bytes", transfer->length);
- ret = WinUSBX[sub_api].WritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped);
- }
-
- if (!ret && GetLastError() != ERROR_IO_PENDING) {
- usbi_err(TRANSFER_CTX(transfer), "ReadPipe/WritePipe failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_IO;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
-{
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- HANDLE winusb_handle;
- int current_interface;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
- if (current_interface < 0) {
- usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface - cannot clear");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg(HANDLE_CTX(dev_handle), "matched endpoint %02X with interface %d", endpoint, current_interface);
- winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
-
- if (!WinUSBX[sub_api].ResetPipe(winusb_handle, endpoint)) {
- usbi_err(HANDLE_CTX(dev_handle), "ResetPipe failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_cancel_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle);
- struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- int current_interface = transfer_priv->interface_number;
- HANDLE handle;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- usbi_dbg(TRANSFER_CTX(transfer), "will use interface %d", current_interface);
-
- handle = handle_priv->interface_handle[current_interface].api_handle;
- if (!WinUSBX[sub_api].AbortPipe(handle, transfer->endpoint)) {
- usbi_err(TRANSFER_CTX(transfer), "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 winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- HANDLE winusb_handle;
- int i, j;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- // Reset any available pipe (except control)
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- winusb_handle = handle_priv->interface_handle[i].api_handle;
- if (HANDLE_VALID(winusb_handle)) {
- for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) {
- usbi_dbg(HANDLE_CTX(dev_handle), "resetting ep %02X", priv->usb_interface[i].endpoint[j]);
- if (!WinUSBX[sub_api].AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))
- usbi_err(HANDLE_CTX(dev_handle), "AbortPipe (pipe address %02X) failed: %s",
- priv->usb_interface[i].endpoint[j], windows_error_str(0));
-
- // FlushPipe seems to fail on OUT pipes
- if (IS_EPIN(priv->usb_interface[i].endpoint[j])
- && (!WinUSBX[sub_api].FlushPipe(winusb_handle, priv->usb_interface[i].endpoint[j])))
- usbi_err(HANDLE_CTX(dev_handle), "FlushPipe (pipe address %02X) failed: %s",
- priv->usb_interface[i].endpoint[j], windows_error_str(0));
-
- if (!WinUSBX[sub_api].ResetPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))
- usbi_err(HANDLE_CTX(dev_handle), "ResetPipe (pipe address %02X) failed: %s",
- priv->usb_interface[i].endpoint[j], windows_error_str(0));
- }
- }
- }
-
- // libusbK & libusb0 have the ability to issue an actual device reset
- if ((sub_api != SUB_API_WINUSB) && (WinUSBX[sub_api].ResetDevice != NULL)) {
- winusb_handle = handle_priv->interface_handle[0].api_handle;
- if (HANDLE_VALID(winusb_handle))
- WinUSBX[sub_api].ResetDevice(winusb_handle);
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static enum libusb_transfer_status winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
- int i;
-
- if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
- // for isochronous, need to copy the individual iso packet actual_lengths and statuses
- if ((sub_api == SUB_API_LIBUSBK) || (sub_api == SUB_API_LIBUSB0)) {
- // iso only supported on libusbk-based backends for now
- PKISO_CONTEXT iso_context = transfer_priv->iso_context;
- for (i = 0; i < transfer->num_iso_packets; i++) {
- transfer->iso_packet_desc[i].actual_length = iso_context->IsoPackets[i].actual_length;
- // TODO translate USDB_STATUS codes http://msdn.microsoft.com/en-us/library/ff539136(VS.85).aspx to libusb_transfer_status
- //transfer->iso_packet_desc[i].status = transfer_priv->iso_context->IsoPackets[i].status;
- }
- } else if (sub_api == SUB_API_WINUSB) {
- if (IS_XFERIN(transfer)) {
- /* Convert isochronous packet descriptor between Windows and libusb representation.
- * Both representation are guaranteed to have the same length in bytes.*/
- PUSBD_ISO_PACKET_DESCRIPTOR usbd_iso_packet_desc = (PUSBD_ISO_PACKET_DESCRIPTOR)transfer->iso_packet_desc;
- for (i = 0; i < transfer->num_iso_packets; i++) {
- unsigned int packet_length = (i < transfer->num_iso_packets - 1) ? (usbd_iso_packet_desc[i + 1].Offset - usbd_iso_packet_desc[i].Offset) : usbd_iso_packet_desc[i].Length;
- unsigned int actual_length = usbd_iso_packet_desc[i].Length;
- USBD_STATUS status = usbd_iso_packet_desc[i].Status;
-
- transfer->iso_packet_desc[i].length = packet_length;
- transfer->iso_packet_desc[i].actual_length = actual_length;
- transfer->iso_packet_desc[i].status = usbd_status_to_libusb_transfer_status(status);
- }
- } else {
- for (i = 0; i < transfer->num_iso_packets; i++) {
- transfer->iso_packet_desc[i].status = LIBUSB_TRANSFER_COMPLETED;
- }
- }
- } else {
- // This should only occur if backend is not set correctly or other backend isoc is partially implemented
- PRINT_UNSUPPORTED_API(copy_transfer_data);
- return LIBUSB_TRANSFER_ERROR;
- }
- }
-
- itransfer->transferred += (int)length;
- 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 *hid_priv, 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)hid_priv->vid;
- d.idProduct = (uint16_t)hid_priv->pid;
- d.bcdDevice = 0x0100;
- d.iManufacturer = hid_priv->string_index[0];
- d.iProduct = hid_priv->string_index[1];
- d.iSerialNumber = hid_priv->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 *hid_priv, 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 (hid_priv->input_report_size)
- num_endpoints++;
- if (hid_priv->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(hid_priv, hd, &tmp_size);
-
- if (hid_priv->input_report_size) {
- ed->bLength = LIBUSB_DT_ENDPOINT_SIZE;
- ed->bDescriptorType = LIBUSB_DT_ENDPOINT;
- ed->bEndpointAddress = HID_IN_EP;
- ed->bmAttributes = 3;
- ed->wMaxPacketSize = hid_priv->input_report_size - 1;
- ed->bInterval = 10;
- ed = (struct libusb_endpoint_descriptor *)((char *)ed + LIBUSB_DT_ENDPOINT_SIZE);
- }
-
- if (hid_priv->output_report_size) {
- ed->bLength = LIBUSB_DT_ENDPOINT_SIZE;
- ed->bDescriptorType = LIBUSB_DT_ENDPOINT;
- ed->bEndpointAddress = HID_OUT_EP;
- ed->bmAttributes = 3;
- ed->wMaxPacketSize = hid_priv->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 *hid_priv, int _index,
- void *data, size_t *size, HANDLE hid_handle)
-{
- void *tmp = NULL;
- WCHAR string[MAX_USB_STRING_LENGTH];
- size_t tmp_size = 0;
- int i;
-
- /* language ID, EN-US */
- char string_langid[] = {0x09, 0x04};
-
- if (_index == 0) {
- tmp = string_langid;
- tmp_size = sizeof(string_langid) + 2;
- } else {
- for (i = 0; i < 3; i++) {
- if (_index == (hid_priv->string_index[i])) {
- tmp = hid_priv->string[i];
- tmp_size = (_hid_wcslen(hid_priv->string[i]) + 1) * sizeof(WCHAR);
- break;
- }
- }
-
- if (i == 3) {
- if (!HidD_GetIndexedString(hid_handle, _index, string, sizeof(string)))
- return LIBUSB_ERROR_INVALID_PARAM;
- tmp = string;
- tmp_size = (_hid_wcslen(string) + 1) * sizeof(WCHAR);
- }
- }
-
- 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 *hid_priv, 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(hid_priv, 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 *hid_priv, void *data, size_t *size)
-{
- uint8_t d[MAX_HID_DESCRIPTOR_SIZE];
- size_t i = 0;
-
- /* usage page */
- d[i++] = 0x06; d[i++] = hid_priv->usagePage & 0xFF; d[i++] = hid_priv->usagePage >> 8;
- /* usage */
- d[i++] = 0x09; d[i++] = (uint8_t)hid_priv->usage;
- /* start collection (application) */
- d[i++] = 0xA1; d[i++] = 0x01;
- /* input report */
- if (hid_priv->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)hid_priv->input_report_size - 1;
- /* input (data, variable, absolute) */
- d[i++] = 0x81; d[i++] = 0x00;
- }
- /* output report */
- if (hid_priv->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)hid_priv->output_report_size - 1;
- /* output (data, variable, absolute) */
- d[i++] = 0x91; d[i++] = 0x00;
- }
- /* feature report */
- if (hid_priv->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)hid_priv->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 libusb_device *dev, HANDLE hid_handle, int recipient,
- int type, int _index, void *data, size_t *size)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev);
- UNUSED(recipient);
-
- switch (type) {
- case LIBUSB_DT_DEVICE:
- usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_DEVICE");
- return _hid_get_device_descriptor(priv->hid, data, size);
- case LIBUSB_DT_CONFIG:
- usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_CONFIG");
- if (!_index)
- return _hid_get_config_descriptor(priv->hid, data, size);
- return LIBUSB_ERROR_INVALID_PARAM;
- case LIBUSB_DT_STRING:
- usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_STRING");
- return _hid_get_string_descriptor(priv->hid, _index, data, size, hid_handle);
- case LIBUSB_DT_HID:
- usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_HID");
- if (!_index)
- return _hid_get_hid_descriptor(priv->hid, data, size);
- return LIBUSB_ERROR_INVALID_PARAM;
- case LIBUSB_DT_REPORT:
- usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_REPORT");
- if (!_index)
- return _hid_get_report_descriptor(priv->hid, data, size);
- return LIBUSB_ERROR_INVALID_PARAM;
- case LIBUSB_DT_PHYSICAL:
- usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_PHYSICAL");
- if (HidD_GetPhysicalDescriptor(hid_handle, data, (ULONG)*size))
- return LIBUSB_COMPLETED;
- return LIBUSB_ERROR_OTHER;
- }
-
- usbi_warn(DEVICE_CTX(dev), "unsupported");
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int _hid_get_report(struct libusb_device *dev, HANDLE hid_handle, int id, void *data,
- struct winusb_transfer_priv *tp, size_t size, OVERLAPPED *overlapped, int report_type)
-{
- DWORD ioctl_code, expected_size = (DWORD)size;
- uint8_t *buf;
-
- if (tp->hid_buffer != NULL)
- usbi_err(DEVICE_CTX(dev), "program assertion failed - hid_buffer is not NULL");
-
- if ((size == 0) || (size > MAX_HID_REPORT_SIZE)) {
- usbi_warn(DEVICE_CTX(dev), "invalid size (%"PRIuPTR")", (uintptr_t)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_warn(DEVICE_CTX(dev), "unknown HID report type %d", report_type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- // Add a trailing byte to detect overflows
- buf = calloc(1, expected_size + 1);
- if (buf == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- buf[0] = (uint8_t)id; // Must be set always
- usbi_dbg(DEVICE_CTX(dev), "report ID: 0x%02X", buf[0]);
-
- // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0)
- if (!DeviceIoControl(hid_handle, ioctl_code, buf, expected_size + 1,
- buf, expected_size + 1, NULL, overlapped)) {
- if (GetLastError() != ERROR_IO_PENDING) {
- usbi_err(DEVICE_CTX(dev), "failed to read HID Report: %s", windows_error_str(0));
- 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
- tp->hid_expected_size = expected_size;
-
- return LIBUSB_SUCCESS;
-}
-
-static int _hid_set_report(struct libusb_device *dev, HANDLE hid_handle, int id, void *data,
- struct winusb_transfer_priv *tp, size_t size, OVERLAPPED *overlapped, int report_type)
-{
- DWORD ioctl_code, write_size = (DWORD)size;
- // If an id is reported, we must allow MAX_HID_REPORT_SIZE + 1
- size_t max_report_size = MAX_HID_REPORT_SIZE + (id ? 1 : 0);
- uint8_t *buf;
-
- if (tp->hid_buffer != NULL)
- usbi_err(DEVICE_CTX(dev), "program assertion failed - hid_buffer is not NULL");
-
- if ((size == 0) || (size > max_report_size)) {
- usbi_warn(DEVICE_CTX(dev), "invalid size (%"PRIuPTR")", (uintptr_t)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_warn(DEVICE_CTX(dev), "unknown HID report type %d", report_type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- usbi_dbg(DEVICE_CTX(dev), "report ID: 0x%02X", id);
- // When report IDs are not used (i.e. when id == 0), we must add
- // a null report ID. Otherwise, we just use original data buffer
- if (id == 0)
- 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(DEVICE_CTX(dev), "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, NULL, overlapped)) {
- if (GetLastError() != ERROR_IO_PENDING) {
- usbi_err(DEVICE_CTX(dev), "failed to write HID Output Report: %s", windows_error_str(0));
- free(buf);
- return LIBUSB_ERROR_IO;
- }
- }
-
- tp->hid_buffer = buf;
- tp->hid_dest = NULL;
- return LIBUSB_SUCCESS;
-}
-
-static int _hid_class_request(struct libusb_device *dev, HANDLE hid_handle, int request_type,
- int request, int value, int _index, void *data, struct winusb_transfer_priv *tp,
- size_t size, OVERLAPPED *overlapped)
-{
- int report_type = (value >> 8) & 0xFF;
- int report_id = value & 0xFF;
-
- UNUSED(_index);
-
- 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 bool hid_init(struct libusb_context *ctx)
-{
- DLL_GET_HANDLE(ctx, hid);
-
- DLL_LOAD_FUNC(hid, HidD_GetAttributes, true);
- DLL_LOAD_FUNC(hid, HidD_GetHidGuid, true);
- DLL_LOAD_FUNC(hid, HidD_GetPreparsedData, true);
- DLL_LOAD_FUNC(hid, HidD_FreePreparsedData, true);
- DLL_LOAD_FUNC(hid, HidD_GetManufacturerString, true);
- DLL_LOAD_FUNC(hid, HidD_GetProductString, true);
- DLL_LOAD_FUNC(hid, HidD_GetSerialNumberString, true);
- DLL_LOAD_FUNC(hid, HidD_GetIndexedString, true);
- DLL_LOAD_FUNC(hid, HidP_GetCaps, true);
- DLL_LOAD_FUNC(hid, HidD_SetNumInputBuffers, true);
- DLL_LOAD_FUNC(hid, HidD_GetPhysicalDescriptor, true);
- DLL_LOAD_FUNC(hid, HidD_FlushQueue, true);
- DLL_LOAD_FUNC(hid, HidP_GetValueCaps, true);
-
- return true;
-}
-
-static void hid_exit(void)
-{
- DLL_FREE_HANDLE(hid);
-}
-
-// 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(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct libusb_device *dev = dev_handle->dev;
- struct winusb_device_priv *priv = usbi_get_device_priv(dev);
- struct winusb_device_handle_priv *handle_priv = get_winusb_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];
- int nb_ids[2]; // zero and nonzero report IDs
-#if defined(ENABLE_LOGGING)
- const char * const type[3] = {"input", "output", "feature"};
-#endif
-
- UNUSED(sub_api);
- CHECK_HID_AVAILABLE;
-
- if (priv->hid == NULL) {
- usbi_err(HANDLE_CTX(dev_handle), "program assertion failed - private HID structure is uninitialized");
- 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 = windows_open(dev_handle, priv->usb_interface[i].path, GENERIC_READ | GENERIC_WRITE);
- /*
- * http://www.lvr.com/hidfaq.htm: Why do I receive "Access denied" when attempting to access my HID?
- * "Windows 2000 and later have exclusive read/write access to HIDs that are configured as a system
- * 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(HANDLE_CTX(dev_handle), "could not open HID device in R/W mode (keyboard or mouse?) - trying without");
- hid_handle = windows_open(dev_handle, priv->usb_interface[i].path, 0);
- if (hid_handle == INVALID_HANDLE_VALUE) {
- usbi_err(HANDLE_CTX(dev_handle), "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0));
- switch (GetLastError()) {
- 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(HANDLE_CTX(dev_handle), "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(HANDLE_CTX(dev_handle), "set maximum input buffer size to %d", i / 2);
-
- // Get the maximum input and output report size
- if (!HidD_GetPreparsedData(hid_handle, &preparsed_data) || !preparsed_data) {
- usbi_err(HANDLE_CTX(dev_handle), "could not read HID preparsed data (HidD_GetPreparsedData)");
- break;
- }
- if (HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) {
- usbi_err(HANDLE_CTX(dev_handle), "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 = HidP_Input; j <= HidP_Feature; j++) {
- usbi_dbg(HANDLE_CTX(dev_handle), "%lu HID %s report value(s) found", ULONG_CAST(size[j]), type[j]);
- priv->hid->uses_report_ids[j] = false;
- if (size[j] > 0) {
- value_caps = calloc(size[j], sizeof(HIDP_VALUE_CAPS));
- if ((value_caps != NULL)
- && (HidP_GetValueCaps((HIDP_REPORT_TYPE)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(HANDLE_CTX(dev_handle), " 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(HANDLE_CTX(dev_handle), "program assertion failed - zero and nonzero report IDs used for %s",
- type[j]);
- priv->hid->uses_report_ids[j] = true;
- }
- } else {
- usbi_warn(HANDLE_CTX(dev_handle), " could not process %s report IDs", type[j]);
- }
- 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;
-
- // Store usage and usagePage values
- priv->hid->usage = capabilities.Usage;
- priv->hid->usagePage = capabilities.UsagePage;
-
- // Fetch string descriptors
- priv->hid->string_index[0] = dev->device_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] = dev->device_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] = dev->device_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(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- HANDLE file_handle;
- int i;
-
- UNUSED(sub_api);
-
- if (DLL_HANDLE_NAME(hid) == NULL)
- 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 (HANDLE_VALID(file_handle))
- CloseHandle(file_handle);
- }
- }
-}
-
-static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface)
-{
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- UNUSED(sub_api);
- 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(HANDLE_CTX(dev_handle), "claimed interface %u", iface);
- handle_priv->active_interface = iface;
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface)
-{
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- UNUSED(sub_api);
- 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(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting)
-{
- UNUSED(sub_api);
- UNUSED(iface);
-
- CHECK_HID_AVAILABLE;
-
- if (altsetting != 0) {
- usbi_err(HANDLE_CTX(dev_handle), "set interface altsetting not supported for altsetting >0");
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
- struct libusb_device_handle *dev_handle = transfer->dev_handle;
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer;
- HANDLE hid_handle;
- OVERLAPPED *overlapped;
- int current_interface;
- uint8_t config;
- size_t size;
- int r;
-
- UNUSED(sub_api);
- CHECK_HID_AVAILABLE;
-
- 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(dev_handle, USB_API_HID);
- if (current_interface < 0) {
- if (auto_claim(transfer, &current_interface, USB_API_HID) != LIBUSB_SUCCESS)
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg(ITRANSFER_CTX(itransfer), "will use interface %d", current_interface);
-
- transfer_priv->interface_number = (uint8_t)current_interface;
- hid_handle = handle_priv->interface_handle[current_interface].api_handle;
- set_transfer_priv_handle(itransfer, hid_handle);
- overlapped = get_transfer_priv_overlapped(itransfer);
-
- switch (LIBUSB_REQ_TYPE(setup->RequestType)) {
- case LIBUSB_REQUEST_TYPE_STANDARD:
- switch (setup->Request) {
- case LIBUSB_REQUEST_GET_DESCRIPTOR:
- r = _hid_get_descriptor(dev_handle->dev, hid_handle, LIBUSB_REQ_RECIPIENT(setup->RequestType),
- (setup->Value >> 8) & 0xFF, setup->Value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size);
- break;
- case LIBUSB_REQUEST_GET_CONFIGURATION:
- r = winusb_get_configuration(dev_handle, &config);
- if (r == LIBUSB_SUCCESS) {
- size = 1;
- ((uint8_t *)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = config;
- r = LIBUSB_COMPLETED;
- }
- break;
- case LIBUSB_REQUEST_SET_CONFIGURATION:
- if (setup->Value == priv->active_config) {
- r = LIBUSB_COMPLETED;
- } else {
- usbi_warn(TRANSFER_CTX(transfer), "cannot set configuration other than the default one");
- r = LIBUSB_ERROR_NOT_SUPPORTED;
- }
- 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(0, dev_handle, (uint8_t)setup->Index, (uint8_t)setup->Value);
- if (r == LIBUSB_SUCCESS)
- r = LIBUSB_COMPLETED;
- break;
- default:
- usbi_warn(TRANSFER_CTX(transfer), "unsupported HID control request");
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
- break;
- case LIBUSB_REQUEST_TYPE_CLASS:
- r = _hid_class_request(dev_handle->dev, hid_handle, setup->RequestType, setup->Request, setup->Value,
- setup->Index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer_priv,
- size, overlapped);
- break;
- default:
- usbi_warn(TRANSFER_CTX(transfer), "unsupported HID control request");
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-
- if (r < 0)
- return r;
-
- if (r == LIBUSB_COMPLETED) {
- // Force request to be completed synchronously. Transferred size has been set by previous call
- windows_force_sync_completion(itransfer, (ULONG)size);
- r = LIBUSB_SUCCESS;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- HANDLE hid_handle;
- OVERLAPPED *overlapped;
- bool direction_in;
- BOOL ret;
- int current_interface, length;
-
- UNUSED(sub_api);
- CHECK_HID_AVAILABLE;
-
- if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
- return LIBUSB_ERROR_NOT_SUPPORTED;
-
- transfer_priv->hid_dest = NULL;
- safe_free(transfer_priv->hid_buffer);
-
- current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
- if (current_interface < 0) {
- usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg(TRANSFER_CTX(transfer), "matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
-
- transfer_priv->interface_number = (uint8_t)current_interface;
- hid_handle = handle_priv->interface_handle[current_interface].api_handle;
- set_transfer_priv_handle(itransfer, hid_handle);
- overlapped = get_transfer_priv_overlapped(itransfer);
- direction_in = IS_XFERIN(transfer);
-
- // 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 = calloc(1, length + 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(TRANSFER_CTX(transfer), "reading %d bytes (report ID: 0x00)", length);
- ret = ReadFile(hid_handle, transfer_priv->hid_buffer, length + 1, NULL, overlapped);
- } else {
- if (!priv->hid->uses_report_ids[1])
- 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(TRANSFER_CTX(transfer), "writing %d bytes (report ID: 0x%02X)", length, transfer_priv->hid_buffer[0]);
- ret = WriteFile(hid_handle, transfer_priv->hid_buffer, length, NULL, overlapped);
- }
-
- if (!ret && GetLastError() != ERROR_IO_PENDING) {
- usbi_err(TRANSFER_CTX(transfer), "HID transfer failed: %s", windows_error_str(0));
- safe_free(transfer_priv->hid_buffer);
- return LIBUSB_ERROR_IO;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- HANDLE hid_handle;
- int current_interface;
-
- UNUSED(sub_api);
- 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 (HANDLE_VALID(hid_handle))
- HidD_FlushQueue(hid_handle);
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
-{
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- HANDLE hid_handle;
- int current_interface;
-
- UNUSED(sub_api);
- CHECK_HID_AVAILABLE;
-
- current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
- if (current_interface < 0) {
- usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface - cannot clear");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg(HANDLE_CTX(dev_handle), "matched endpoint %02X with interface %d", endpoint, current_interface);
- hid_handle = handle_priv->interface_handle[current_interface].api_handle;
-
- // No endpoint selection with Microsoft's implementation, so we try to flush the
- // whole interface. Should be OK for most case scenarios
- if (!HidD_FlushQueue(hid_handle)) {
- usbi_err(HANDLE_CTX(dev_handle), "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 enum libusb_transfer_status hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
- enum libusb_transfer_status r = LIBUSB_TRANSFER_COMPLETED;
-
- UNUSED(sub_api);
-
- 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
- if (length > 0) {
- // First, check for overflow
- if ((size_t)length > transfer_priv->hid_expected_size) {
- usbi_err(TRANSFER_CTX(transfer), "OVERFLOW!");
- length = (DWORD)transfer_priv->hid_expected_size;
- r = LIBUSB_TRANSFER_OVERFLOW;
- }
-
- if (transfer_priv->hid_buffer[0] == 0) {
- memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer + 1, length);
- } else {
- memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer, length);
- }
- }
- transfer_priv->hid_dest = NULL;
- }
- // For write, we just need to free the hid buffer
- safe_free(transfer_priv->hid_buffer);
- }
-
- itransfer->transferred += (int)length;
- return r;
-}
-
-
-/*
- * Composite API functions
- */
-static int composite_open(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- int i, r = LIBUSB_ERROR_NOT_FOUND;
- // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID
- bool available[SUB_API_MAX + 1];
-
- UNUSED(sub_api);
-
- for (i = 0; i < SUB_API_MAX + 1; i++)
- available[i] = false;
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- switch (priv->usb_interface[i].apib->id) {
- case USB_API_WINUSBX:
- if (priv->usb_interface[i].sub_api != SUB_API_NOTSET)
- available[priv->usb_interface[i].sub_api] = true;
- break;
- case USB_API_HID:
- available[SUB_API_MAX] = true;
- break;
- default:
- break;
- }
- }
-
- for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers
- if (available[i]) {
- r = usb_api_backend[USB_API_WINUSBX].open(i, dev_handle);
- if (r != LIBUSB_SUCCESS)
- return r;
- }
- }
-
- if (available[SUB_API_MAX]) { // HID driver
- r = hid_open(SUB_API_NOTSET, dev_handle);
-
- // On Windows 10 version 1903 (OS Build 18362) and later Windows blocks attempts to
- // open HID devices with a U2F usage unless running as administrator. We ignore this
- // failure and proceed without the HID device opened.
- if (r == LIBUSB_ERROR_ACCESS) {
- usbi_dbg(HANDLE_CTX(dev_handle), "ignoring access denied error while opening HID interface of composite device");
- r = LIBUSB_SUCCESS;
- }
- }
-
- return r;
-}
-
-static void composite_close(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- int i;
- // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID
- bool available[SUB_API_MAX + 1];
-
- UNUSED(sub_api);
-
- for (i = 0; i < SUB_API_MAX + 1; i++)
- available[i] = false;
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- switch (priv->usb_interface[i].apib->id) {
- case USB_API_WINUSBX:
- if (priv->usb_interface[i].sub_api != SUB_API_NOTSET)
- available[priv->usb_interface[i].sub_api] = true;
- break;
- case USB_API_HID:
- available[SUB_API_MAX] = true;
- break;
- default:
- break;
- }
- }
-
- for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers
- if (available[i])
- usb_api_backend[USB_API_WINUSBX].close(i, dev_handle);
- }
-
- if (available[SUB_API_MAX]) // HID driver
- hid_close(SUB_API_NOTSET, dev_handle);
-}
-
-static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- UNUSED(sub_api);
- CHECK_SUPPORTED_API(priv->usb_interface[iface].apib, claim_interface);
-
- return priv->usb_interface[iface].apib->
- claim_interface(priv->usb_interface[iface].sub_api, dev_handle, iface);
-}
-
-static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- UNUSED(sub_api);
- CHECK_SUPPORTED_API(priv->usb_interface[iface].apib, set_interface_altsetting);
-
- return priv->usb_interface[iface].apib->
- set_interface_altsetting(priv->usb_interface[iface].sub_api, dev_handle, iface, altsetting);
-}
-
-static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
-
- UNUSED(sub_api);
- CHECK_SUPPORTED_API(priv->usb_interface[iface].apib, release_interface);
-
- return priv->usb_interface[iface].apib->
- release_interface(priv->usb_interface[iface].sub_api, dev_handle, iface);
-}
-
-static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- struct libusb_config_descriptor *conf_desc;
- WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer;
- int iface, pass, r;
-
- UNUSED(sub_api);
-
- // Interface shouldn't matter for control, but it does in practice, with Windows'
- // restrictions with regards to accessing HID keyboards and mice. Try to target
- // a specific interface first, if possible.
- switch (LIBUSB_REQ_RECIPIENT(setup->RequestType)) {
- case LIBUSB_RECIPIENT_INTERFACE:
- iface = setup->Index & 0xFF;
- break;
- case LIBUSB_RECIPIENT_ENDPOINT:
- r = libusb_get_active_config_descriptor(transfer->dev_handle->dev, &conf_desc);
- if (r == LIBUSB_SUCCESS) {
- iface = get_interface_by_endpoint(conf_desc, (setup->Index & 0xFF));
- libusb_free_config_descriptor(conf_desc);
- break;
- }
- // No break if not able to determine interface
- // Fall through
- default:
- iface = -1;
- break;
- }
-
- // Try and target a specific interface if the control setup indicates such
- if ((iface >= 0) && (iface < USB_MAXINTERFACES)) {
- usbi_dbg(TRANSFER_CTX(transfer), "attempting control transfer targeted to interface %d", iface);
- if ((priv->usb_interface[iface].path != NULL)
- && (priv->usb_interface[iface].apib->submit_control_transfer != NULL)) {
- r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer);
- if (r == LIBUSB_SUCCESS)
- return r;
- }
- }
-
- // Either not targeted to a specific interface or no luck in doing so.
- // Try a 2 pass approach with all interfaces.
- for (pass = 0; pass < 2; pass++) {
- for (iface = 0; iface < USB_MAXINTERFACES; iface++) {
- if ((priv->usb_interface[iface].path != NULL)
- && (priv->usb_interface[iface].apib->submit_control_transfer != NULL)) {
- if ((pass == 0) && (priv->usb_interface[iface].restricted_functionality)) {
- usbi_dbg(TRANSFER_CTX(transfer), "trying to skip restricted interface #%d (HID keyboard or mouse?)", iface);
- continue;
- }
- usbi_dbg(TRANSFER_CTX(transfer), "using interface %d", iface);
- r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer);
- // If not supported on this API, it may be supported on another, so don't give up yet!!
- if (r == LIBUSB_ERROR_NOT_SUPPORTED)
- continue;
- return r;
- }
- }
- }
-
- usbi_err(TRANSFER_CTX(transfer), "no libusb supported interfaces to complete request");
- return LIBUSB_ERROR_NOT_FOUND;
-}
-
-static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- int current_interface;
-
- UNUSED(sub_api);
-
- current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
- if (current_interface < 0) {
- usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, submit_bulk_transfer);
-
- return priv->usb_interface[current_interface].apib->
- submit_bulk_transfer(priv->usb_interface[current_interface].sub_api, itransfer);
-}
-
-static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- int current_interface;
-
- UNUSED(sub_api);
-
- current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
- if (current_interface < 0) {
- usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, submit_iso_transfer);
-
- return priv->usb_interface[current_interface].apib->
- submit_iso_transfer(priv->usb_interface[current_interface].sub_api, itransfer);
-}
-
-static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
-{
- struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- int current_interface;
-
- UNUSED(sub_api);
-
- current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
- if (current_interface < 0) {
- usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface - cannot clear");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, clear_halt);
-
- return priv->usb_interface[current_interface].apib->
- clear_halt(priv->usb_interface[current_interface].sub_api, dev_handle, endpoint);
-}
-
-static int composite_cancel_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- int current_interface = transfer_priv->interface_number;
-
- UNUSED(sub_api);
-
- if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) {
- usbi_err(TRANSFER_CTX(transfer), "program assertion failed - invalid interface_number");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, cancel_transfer);
-
- return priv->usb_interface[current_interface].apib->
- cancel_transfer(priv->usb_interface[current_interface].sub_api, itransfer);
-}
-
-static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
- int i, r;
- bool available[SUB_API_MAX];
-
- UNUSED(sub_api);
-
- for (i = 0; i < SUB_API_MAX; i++)
- available[i] = false;
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if ((priv->usb_interface[i].apib->id == USB_API_WINUSBX)
- && (priv->usb_interface[i].sub_api != SUB_API_NOTSET))
- available[priv->usb_interface[i].sub_api] = true;
- }
-
- for (i = 0; i < SUB_API_MAX; i++) {
- if (available[i]) {
- r = usb_api_backend[USB_API_WINUSBX].reset_device(i, dev_handle);
- if (r != LIBUSB_SUCCESS)
- return r;
- }
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static enum libusb_transfer_status composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
- struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
- int current_interface = transfer_priv->interface_number;
-
- UNUSED(sub_api);
- if (priv->usb_interface[current_interface].apib->copy_transfer_data == NULL) {
- usbi_err(TRANSFER_CTX(transfer), "program assertion failed - no function to copy transfer data");
- return LIBUSB_TRANSFER_ERROR;
- }
-
- return priv->usb_interface[current_interface].apib->
- copy_transfer_data(priv->usb_interface[current_interface].sub_api, itransfer, length);
-}
diff --git a/src/os/windows_winusb.h b/src/os/windows_winusb.h
deleted file mode 100644
index 6afd5cb..0000000
--- a/src/os/windows_winusb.h
+++ /dev/null
@@ -1,783 +0,0 @@
-/*
- * Windows backend for libusb 1.0
- * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
- * 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
- */
-
-#ifndef LIBUSB_WINDOWS_WINUSB_H
-#define LIBUSB_WINDOWS_WINUSB_H
-
-#include <devioctl.h>
-#include <guiddef.h>
-
-#include "windows_common.h"
-
-#define MAX_CTRL_BUFFER_LENGTH 4096
-#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 256
-#define MAX_KEY_LENGTH 256
-#define LIST_SEPARATOR ';'
-
-// Handle code for HID interface that have been claimed ("dibs")
-#define INTERFACE_CLAIMED ((HANDLE)(intptr_t)0xD1B5)
-// Additional return code for HID operations that completed synchronously
-#define LIBUSB_COMPLETED (LIBUSB_SUCCESS + 1)
-
-// http://msdn.microsoft.com/en-us/library/ff545978.aspx
-// http://msdn.microsoft.com/en-us/library/ff545972.aspx
-// http://msdn.microsoft.com/en-us/library/ff545982.aspx
-static const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = {0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27}};
-static const GUID GUID_DEVINTERFACE_USB_HUB = {0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8}};
-static const GUID GUID_DEVINTERFACE_USB_DEVICE = {0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}};
-static const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = {0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9}};
-
-// The following define MUST be == sizeof(USB_DESCRIPTOR_REQUEST)
-#define USB_DESCRIPTOR_REQUEST_SIZE 12U
-
-/*
- * Multiple USB API backend support
- */
-#define USB_API_UNSUPPORTED 0
-#define USB_API_HUB 1
-#define USB_API_COMPOSITE 2
-#define USB_API_WINUSBX 3
-#define USB_API_HID 4
-#define USB_API_MAX 5
-
-// Sub-APIs for WinUSB-like driver APIs (WinUSB, libusbK, libusb-win32 through the libusbK DLL)
-// Must have the same values as the KUSB_DRVID enum from libusbk.h
-#define SUB_API_NOTSET -1
-#define SUB_API_LIBUSBK 0
-#define SUB_API_LIBUSB0 1
-#define SUB_API_WINUSB 2
-#define SUB_API_MAX 3
-
-struct windows_usb_api_backend {
- const uint8_t id;
- const char * const designation;
- const char * const * const driver_name_list; // Driver name, without .sys, e.g. "usbccgp"
- const uint8_t nb_driver_names;
- bool (*init)(struct libusb_context *ctx);
- void (*exit)(void);
- int (*open)(int sub_api, struct libusb_device_handle *dev_handle);
- void (*close)(int sub_api, struct libusb_device_handle *dev_handle);
- int (*configure_endpoints)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
- int (*claim_interface)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
- int (*set_interface_altsetting)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting);
- int (*release_interface)(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
- int (*clear_halt)(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
- int (*reset_device)(int sub_api, struct libusb_device_handle *dev_handle);
- int (*submit_bulk_transfer)(int sub_api, struct usbi_transfer *itransfer);
- int (*submit_iso_transfer)(int sub_api, struct usbi_transfer *itransfer);
- int (*submit_control_transfer)(int sub_api, struct usbi_transfer *itransfer);
- int (*cancel_transfer)(int sub_api, struct usbi_transfer *itransfer);
- enum libusb_transfer_status (*copy_transfer_data)(int sub_api, struct usbi_transfer *itransfer, DWORD length);
-};
-
-extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX];
-
-#define PRINT_UNSUPPORTED_API(fname) \
- usbi_dbg(NULL, "unsupported API call for '%s' " \
- "(unrecognized device driver)", #fname)
-
-#define CHECK_SUPPORTED_API(apip, fname) \
- do { \
- if ((apip)->fname == NULL) { \
- PRINT_UNSUPPORTED_API(fname); \
- return LIBUSB_ERROR_NOT_SUPPORTED; \
- } \
- } while (0)
-
-/*
- * 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_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;
- uint16_t usage;
- uint16_t usagePage;
- WCHAR string[3][MAX_USB_STRING_LENGTH];
- uint8_t string_index[3]; // man, prod, ser
-};
-
-static inline struct winusb_device_priv *winusb_device_priv_init(struct libusb_device *dev)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev);
- int i;
-
- priv->apib = &usb_api_backend[USB_API_UNSUPPORTED];
- priv->sub_api = SUB_API_NOTSET;
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- priv->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED];
- priv->usb_interface[i].sub_api = SUB_API_NOTSET;
- }
-
- return priv;
-}
-
-static inline void winusb_device_priv_release(struct libusb_device *dev)
-{
- struct winusb_device_priv *priv = usbi_get_device_priv(dev);
- int i;
-
- free(priv->dev_id);
- free(priv->path);
- if ((dev->device_descriptor.bNumConfigurations > 0) && (priv->config_descriptor != NULL)) {
- for (i = 0; i < dev->device_descriptor.bNumConfigurations; i++) {
- if (priv->config_descriptor[i] == NULL)
- continue;
- free((UCHAR *)priv->config_descriptor[i] - USB_DESCRIPTOR_REQUEST_SIZE);
- }
- }
- free(priv->config_descriptor);
- free(priv->hid);
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- free(priv->usb_interface[i].path);
- free(priv->usb_interface[i].endpoint);
- }
-}
-
-// 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 retrieve list
- const char *designation; // internal designation (for debug output)
-};
-
-/*
- * 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
-
-/* Cfgmgr32 dependencies */
-DLL_DECLARE_HANDLE(Cfgmgr32);
-DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG));
-DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG));
-
-/* AdvAPI32 dependencies */
-DLL_DECLARE_HANDLE(AdvAPI32);
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegQueryValueExA, (HKEY, LPCSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY));
-
-/* SetupAPI dependencies */
-DLL_DECLARE_HANDLE(SetupAPI);
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (LPCGUID, PCSTR, HWND, DWORD));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA,
- LPCGUID, DWORD, PSP_DEVICE_INTERFACE_DATA));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInstanceIdA, (HDEVINFO, PSP_DEVINFO_DATA,
- PCSTR, DWORD, PDWORD));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA,
- PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO,
- PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD, DWORD));
-
-#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN
-
-#define USB_GET_NODE_INFORMATION 258
-#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260
-#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274
-#define USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 279
-
-#define USB_CTL_CODE(id) \
- CTL_CODE(FILE_DEVICE_USB, (id), METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-#define IOCTL_USB_GET_NODE_INFORMATION \
- USB_CTL_CODE(USB_GET_NODE_INFORMATION)
-
-#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \
- USB_CTL_CODE(USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION)
-
-#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \
- USB_CTL_CODE(USB_GET_NODE_CONNECTION_INFORMATION_EX)
-
-#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 \
- USB_CTL_CODE(USB_GET_NODE_CONNECTION_INFORMATION_EX_V2)
-
-typedef enum _USB_CONNECTION_STATUS {
- NoDeviceConnected,
- DeviceConnected,
- DeviceFailedEnumeration,
- DeviceGeneralFailure,
- DeviceCausedOvercurrent,
- DeviceNotEnoughPower,
- DeviceNotEnoughBandwidth,
- DeviceHubNestedTooDeeply,
- DeviceInLegacyHub,
- DeviceEnumerating,
- DeviceReset
-} USB_CONNECTION_STATUS;
-
-typedef enum _USB_DEVICE_SPEED {
- UsbLowSpeed = 0,
- UsbFullSpeed,
- UsbHighSpeed,
- UsbSuperSpeed,
- UsbSuperSpeedPlus // Not in Microsoft headers
-} USB_DEVICE_SPEED;
-
-typedef enum _USB_HUB_NODE {
- UsbHub,
- UsbMIParent
-} USB_HUB_NODE;
-
-#if defined(_MSC_VER)
-// disable /W4 MSVC warnings that are benign
-#pragma warning(push)
-#pragma warning(disable:4214) // bit field types other than int
-#endif
-
-// Most of the structures below need to be packed
-#include <pshpack1.h>
-
-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_HUB_INFORMATION {
- USB_HUB_DESCRIPTOR HubDescriptor;
- BOOLEAN HubIsBusPowered;
-} USB_HUB_INFORMATION, *PUSB_HUB_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_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_CONFIGURATION_DESCRIPTOR_SHORT {
- USB_DESCRIPTOR_REQUEST req;
- USB_CONFIGURATION_DESCRIPTOR desc;
-} USB_CONFIGURATION_DESCRIPTOR_SHORT;
-
-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_NODE_CONNECTION_INFORMATION_EX {
- ULONG ConnectionIndex;
- USB_DEVICE_DESCRIPTOR DeviceDescriptor;
- UCHAR CurrentConfigurationValue;
- UCHAR Speed;
- BOOLEAN DeviceIsHub;
- USHORT DeviceAddress;
- ULONG NumberOfOpenPipes;
- USB_CONNECTION_STATUS ConnectionStatus;
-// USB_PIPE_INFO PipeList[0];
-} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX;
-
-typedef union _USB_PROTOCOLS {
- ULONG ul;
- struct {
- ULONG Usb110:1;
- ULONG Usb200:1;
- ULONG Usb300:1;
- ULONG ReservedMBZ:29;
- };
-} USB_PROTOCOLS, *PUSB_PROTOCOLS;
-
-typedef union _USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS {
- ULONG ul;
- struct {
- ULONG DeviceIsOperatingAtSuperSpeedOrHigher:1;
- ULONG DeviceIsSuperSpeedCapableOrHigher:1;
- ULONG DeviceIsOperatingAtSuperSpeedPlusOrHigher:1;
- ULONG DeviceIsSuperSpeedPlusCapableOrHigher:1;
- ULONG ReservedMBZ:28;
- };
-} USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS, *PUSB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS;
-
-typedef struct _USB_NODE_CONNECTION_INFORMATION_EX_V2 {
- ULONG ConnectionIndex;
- ULONG Length;
- USB_PROTOCOLS SupportedUsbProtocols;
- USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS Flags;
-} USB_NODE_CONNECTION_INFORMATION_EX_V2, *PUSB_NODE_CONNECTION_INFORMATION_EX_V2;
-
-#include <poppack.h>
-
-#if defined(_MSC_VER)
-// Restore original warnings
-#pragma warning(pop)
-#endif
-
-/* winusb.dll interface */
-
-/* pipe policies */
-#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
-/* libusbK */
-#define ISO_ALWAYS_START_ASAP 0x21
-
-typedef struct _USBD_ISO_PACKET_DESCRIPTOR {
- ULONG Offset;
- ULONG Length;
- USBD_STATUS Status;
-} USBD_ISO_PACKET_DESCRIPTOR, *PUSBD_ISO_PACKET_DESCRIPTOR;
-
-typedef enum _USBD_PIPE_TYPE {
- UsbdPipeTypeControl,
- UsbdPipeTypeIsochronous,
- UsbdPipeTypeBulk,
- UsbdPipeTypeInterrupt
-} USBD_PIPE_TYPE;
-
-typedef struct {
- USBD_PIPE_TYPE PipeType;
- UCHAR PipeId;
- USHORT MaximumPacketSize;
- UCHAR Interval;
- ULONG MaximumBytesPerInterval;
-} WINUSB_PIPE_INFORMATION_EX, *PWINUSB_PIPE_INFORMATION_EX;
-
-#include <pshpack1.h>
-
-typedef struct _WINUSB_SETUP_PACKET {
- UCHAR RequestType;
- UCHAR Request;
- USHORT Value;
- USHORT Index;
- USHORT Length;
-} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET;
-
-#include <poppack.h>
-
-typedef PVOID WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
-typedef PVOID WINUSB_ISOCH_BUFFER_HANDLE, *PWINUSB_ISOCH_BUFFER_HANDLE;
-
-typedef BOOL (WINAPI *WinUsb_AbortPipe_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID
-);
-typedef BOOL (WINAPI *WinUsb_ControlTransfer_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- WINUSB_SETUP_PACKET SetupPacket,
- PUCHAR Buffer,
- ULONG BufferLength,
- PULONG LengthTransferred,
- LPOVERLAPPED Overlapped
-);
-typedef BOOL (WINAPI *WinUsb_FlushPipe_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID
-);
-typedef BOOL (WINAPI *WinUsb_Free_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle
-);
-typedef BOOL (WINAPI *WinUsb_GetAssociatedInterface_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR AssociatedInterfaceIndex,
- PWINUSB_INTERFACE_HANDLE AssociatedInterfaceHandle
-);
-typedef BOOL (WINAPI *WinUsb_Initialize_t)(
- HANDLE DeviceHandle,
- PWINUSB_INTERFACE_HANDLE InterfaceHandle
-);
-typedef BOOL (WINAPI *WinUsb_QueryPipeEx_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR AlternateInterfaceHandle,
- UCHAR PipeIndex,
- PWINUSB_PIPE_INFORMATION_EX PipeInformationEx
-);
-typedef BOOL (WINAPI *WinUsb_ReadIsochPipeAsap_t)(
- PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
- ULONG Offset,
- ULONG Length,
- BOOL ContinueStream,
- ULONG NumberOfPackets,
- PUSBD_ISO_PACKET_DESCRIPTOR IsoPacketDescriptors,
- LPOVERLAPPED Overlapped
-);
-typedef BOOL (WINAPI *WinUsb_ReadPipe_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID,
- PUCHAR Buffer,
- ULONG BufferLength,
- PULONG LengthTransferred,
- LPOVERLAPPED Overlapped
-);
-typedef BOOL (WINAPI *WinUsb_RegisterIsochBuffer_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID,
- PVOID Buffer,
- ULONG BufferLength,
- PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle
-);
-typedef BOOL (WINAPI *WinUsb_ResetPipe_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID
-);
-typedef BOOL (WINAPI *WinUsb_SetCurrentAlternateSetting_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR AlternateSetting
-);
-typedef BOOL (WINAPI *WinUsb_SetPipePolicy_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID,
- ULONG PolicyType,
- ULONG ValueLength,
- PVOID Value
-);
-typedef BOOL (WINAPI *WinUsb_UnregisterIsochBuffer_t)(
- WINUSB_ISOCH_BUFFER_HANDLE BufferHandle
-);
-typedef BOOL (WINAPI *WinUsb_WriteIsochPipeAsap_t)(
- WINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
- ULONG Offset,
- ULONG Length,
- BOOL ContinueStream,
- LPOVERLAPPED Overlapped
-);
-typedef BOOL (WINAPI *WinUsb_WritePipe_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID,
- PUCHAR Buffer,
- ULONG BufferLength,
- PULONG LengthTransferred,
- LPOVERLAPPED Overlapped
-);
-
-/* /!\ These must match the ones from the official libusbk.h */
-typedef enum _KUSB_FNID {
- KUSB_FNID_Init,
- KUSB_FNID_Free,
- KUSB_FNID_ClaimInterface,
- KUSB_FNID_ReleaseInterface,
- KUSB_FNID_SetAltInterface,
- KUSB_FNID_GetAltInterface,
- KUSB_FNID_GetDescriptor,
- KUSB_FNID_ControlTransfer,
- KUSB_FNID_SetPowerPolicy,
- KUSB_FNID_GetPowerPolicy,
- KUSB_FNID_SetConfiguration,
- KUSB_FNID_GetConfiguration,
- KUSB_FNID_ResetDevice,
- KUSB_FNID_Initialize,
- KUSB_FNID_SelectInterface,
- KUSB_FNID_GetAssociatedInterface,
- KUSB_FNID_Clone,
- KUSB_FNID_QueryInterfaceSettings,
- KUSB_FNID_QueryDeviceInformation,
- KUSB_FNID_SetCurrentAlternateSetting,
- KUSB_FNID_GetCurrentAlternateSetting,
- KUSB_FNID_QueryPipe,
- KUSB_FNID_SetPipePolicy,
- KUSB_FNID_GetPipePolicy,
- KUSB_FNID_ReadPipe,
- KUSB_FNID_WritePipe,
- KUSB_FNID_ResetPipe,
- KUSB_FNID_AbortPipe,
- KUSB_FNID_FlushPipe,
- KUSB_FNID_IsoReadPipe,
- KUSB_FNID_IsoWritePipe,
- KUSB_FNID_GetCurrentFrameNumber,
- KUSB_FNID_GetOverlappedResult,
- KUSB_FNID_GetProperty,
- KUSB_FNID_COUNT,
-} KUSB_FNID;
-
-typedef struct _KLIB_VERSION {
- INT Major;
- INT Minor;
- INT Micro;
- INT Nano;
-} KLIB_VERSION, *PKLIB_VERSION;
-
-typedef BOOL (WINAPI *LibK_GetProcAddress_t)(
- PVOID ProcAddress,
- INT DriverID,
- INT FunctionID
-);
-
-typedef VOID (WINAPI *LibK_GetVersion_t)(
- PKLIB_VERSION Version
-);
-
-typedef BOOL (WINAPI *LibK_ResetDevice_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle
-);
-
-//KISO_PACKET is equivalent of libusb_iso_packet_descriptor except uses absolute "offset" field instead of sequential Lengths
-typedef struct _KISO_PACKET {
- UINT offset;
- USHORT actual_length; //changed from libusbk_shared.h "Length" for clarity
- USHORT status;
-} KISO_PACKET, *PKISO_PACKET;
-
-typedef enum _KISO_FLAG {
- KISO_FLAG_NONE = 0,
- KISO_FLAG_SET_START_FRAME = 0x00000001,
-} KISO_FLAG;
-
-//KISO_CONTEXT is the conceptual equivalent of libusb_transfer except is isochronous-specific and must match libusbk's version
-typedef struct _KISO_CONTEXT {
- KISO_FLAG Flags;
- UINT StartFrame;
- SHORT ErrorCount;
- SHORT NumberOfPackets;
- UINT UrbHdrStatus;
- KISO_PACKET IsoPackets[0];
-} KISO_CONTEXT, *PKISO_CONTEXT;
-
-typedef BOOL(WINAPI *LibK_IsoReadPipe_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID,
- PUCHAR Buffer,
- ULONG BufferLength,
- LPOVERLAPPED Overlapped,
- PKISO_CONTEXT IsoContext
-);
-
-typedef BOOL(WINAPI *LibK_IsoWritePipe_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID,
- PUCHAR Buffer,
- ULONG BufferLength,
- LPOVERLAPPED Overlapped,
- PKISO_CONTEXT IsoContext
-);
-
-struct winusb_interface {
- HMODULE hDll;
- WinUsb_AbortPipe_t AbortPipe;
- WinUsb_ControlTransfer_t ControlTransfer;
- WinUsb_FlushPipe_t FlushPipe;
- WinUsb_Free_t Free;
- WinUsb_GetAssociatedInterface_t GetAssociatedInterface;
- WinUsb_Initialize_t Initialize;
- WinUsb_ReadPipe_t ReadPipe;
- WinUsb_ResetPipe_t ResetPipe;
- WinUsb_SetCurrentAlternateSetting_t SetCurrentAlternateSetting;
- WinUsb_SetPipePolicy_t SetPipePolicy;
- WinUsb_WritePipe_t WritePipe;
- union {
- struct {
- // Isochoronous functions for libusbK sub api:
- LibK_IsoReadPipe_t IsoReadPipe;
- LibK_IsoWritePipe_t IsoWritePipe;
- // Reset device function for libusbK sub api:
- LibK_ResetDevice_t ResetDevice;
- };
- struct {
- // Isochronous functions for WinUSB sub api:
- WinUsb_QueryPipeEx_t QueryPipeEx;
- WinUsb_ReadIsochPipeAsap_t ReadIsochPipeAsap;
- WinUsb_RegisterIsochBuffer_t RegisterIsochBuffer;
- WinUsb_UnregisterIsochBuffer_t UnregisterIsochBuffer;
- WinUsb_WriteIsochPipeAsap_t WriteIsochPipeAsap;
- };
- };
-};
-
-/* hid.dll interface */
-
-#define HIDP_STATUS_SUCCESS 0x110000
-typedef void * PHIDP_PREPARSED_DATA;
-
-#include <pshpack1.h>
-
-typedef struct _HIDD_ATTIRBUTES {
- ULONG Size;
- USHORT VendorID;
- USHORT ProductID;
- USHORT VersionNumber;
-} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
-
-#include <poppack.h>
-
-typedef USHORT USAGE;
-typedef struct _HIDP_CAPS {
- 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_HANDLE(hid);
-DLL_DECLARE_FUNC(WINAPI, VOID, HidD_GetHidGuid, (LPGUID));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetAttributes, (HANDLE, PHIDD_ATTRIBUTES));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPreparsedData, (HANDLE, PHIDP_PREPARSED_DATA *));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FreePreparsedData, (PHIDP_PREPARSED_DATA));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetManufacturerString, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetProductString, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetSerialNumberString, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetIndexedString, (HANDLE, ULONG, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, LONG, HidP_GetCaps, (PHIDP_PREPARSED_DATA, PHIDP_CAPS));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetNumInputBuffers, (HANDLE, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPhysicalDescriptor, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FlushQueue, (HANDLE));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA));
-
-#endif