summaryrefslogtreecommitdiffstats
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);
-