1ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/* -*- Mode: C; indent-tabs-mode:nil -*- */
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * darwin backend for libusbx 1.0
4ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Copyright © 2008-2013 Nathan Hjelm <hjelmn@users.sourceforge.net>
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This library is free software; you can redistribute it and/or
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * modify it under the terms of the GNU Lesser General Public
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * License as published by the Free Software Foundation; either
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * version 2.1 of the License, or (at your option) any later version.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This library is distributed in the hope that it will be useful,
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * but WITHOUT ANY WARRANTY; without even the implied warranty of
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Lesser General Public License for more details.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * You should have received a copy of the GNU Lesser General Public
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * License along with this library; if not, write to the Free Software
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "config.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ctype.h>
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pthread.h>
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h>
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>
30ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include <fcntl.h>
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <libkern/OSAtomic.h>
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <mach/clock.h>
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <mach/clock_types.h>
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <mach/mach_host.h>
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <mach/mach_port.h>
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <AvailabilityMacros.h>
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #include <objc/objc-auto.h>
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "darwin_usb.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* async event thread */
46ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic pthread_mutex_t libusb_darwin_at_mutex = PTHREAD_MUTEX_INITIALIZER;
47ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic pthread_cond_t  libusb_darwin_at_cond = PTHREAD_COND_INITIALIZER;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static clock_serv_t clock_realtime;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static clock_serv_t clock_monotonic;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic CFRunLoopRef libusb_darwin_acfl = NULL; /* event cf loop */
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic volatile int32_t initCount = 0;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic usbi_mutex_t darwin_cached_devices_lock = PTHREAD_MUTEX_INITIALIZER;
56ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic struct list_head darwin_cached_devices = {&darwin_cached_devices, &darwin_cached_devices};
57ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
58ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#define DARWIN_CACHED_DEVICE(a) ((struct darwin_cached_device *) (((struct darwin_device_priv *)((a)->os_priv))->dev))
59ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* async event thread */
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static pthread_t libusb_darwin_at;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_reset_device(struct libusb_device_handle *dev_handle);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
69ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int darwin_scan_devices(struct libusb_context *ctx);
70ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int process_new_device (struct libusb_context *ctx, io_service_t service);
71ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
72ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if defined(ENABLE_LOGGING)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char *darwin_error_str (int result) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (result) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnSuccess:
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "no error";
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnNotOpen:
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "device not opened for exclusive access";
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnNoDevice:
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "no connection to an IOService";
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOUSBNoAsyncPortErr:
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "no async port has been opened for interface";
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnExclusiveAccess:
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "another process has device opened for exclusive access";
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOUSBPipeStalled:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "pipe is stalled";
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnError:
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "could not establish a connection to the Darwin kernel";
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOUSBTransactionTimeout:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "transaction timed out";
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnBadArgument:
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "invalid argument";
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnAborted:
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "transaction aborted";
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnNotResponding:
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "device not responding";
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnOverrun:
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "data overrun";
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnCannotWire:
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "physical memory can not be wired down";
101ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  case kIOReturnNoResources:
102ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return "out of resources";
103ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  case kIOUSBHighSpeedSplitError:
104ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return "high speed split error";
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  default:
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "unknown error";
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
109ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_to_libusb (int result) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (result) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnUnderrun:
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnSuccess:
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_SUCCESS;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnNotOpen:
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnNoDevice:
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_NO_DEVICE;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnExclusiveAccess:
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_ACCESS;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOUSBPipeStalled:
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_PIPE;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnBadArgument:
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_INVALID_PARAM;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOUSBTransactionTimeout:
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_TIMEOUT;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnNotResponding:
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnAborted:
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnError:
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOUSBNoAsyncPortErr:
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  default:
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_OTHER;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
136ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch/* this function must be called with the darwin_cached_devices_lock held */
137ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic void darwin_deref_cached_device(struct darwin_cached_device *cached_dev) {
138ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  cached_dev->refcount--;
139ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* free the device and remove it from the cache */
140ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (0 == cached_dev->refcount) {
141ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    list_del(&cached_dev->list);
142ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
143ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    (*(cached_dev->device))->Release(cached_dev->device);
144ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    free (cached_dev);
145ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
146ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
147ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
148ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic void darwin_ref_cached_device(struct darwin_cached_device *cached_dev) {
149ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  cached_dev->refcount++;
150ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, uint8_t *pipep, uint8_t *ifcp) {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* current interface */
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_interface *cInterface;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int8_t i, iface;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
160ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("converting ep address 0x%02x to pipeRef and interface", ep);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iface = 0 ; iface < USB_MAXINTERFACES ; iface++) {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cInterface = &priv->interfaces[iface];
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (dev_handle->claimed_interfaces & (1 << iface)) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (i = 0 ; i < cInterface->num_endpoints ; i++) {
167ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        if (cInterface->endpoint_addrs[i] == ep) {
168ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          *pipep = i + 1;
169ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          *ifcp = iface;
170ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          usbi_dbg ("pipe %d on interface %d matches", *pipep, *ifcp);
171ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          return 0;
172ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* No pipe found with the correct endpoint address */
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usbi_warn (HANDLE_CTX(dev_handle), "no pipeRef found with endpoint address 0x%02x.", ep);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return -1;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
183ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int usb_setup_device_iterator (io_iterator_t *deviceIterator, UInt32 location) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!matchingDict)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kIOReturnError;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (location) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CFMutableDictionaryRef propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                         &kCFTypeDictionaryKeyCallBacks,
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                         &kCFTypeDictionaryValueCallBacks);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (propertyMatchDict) {
195ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      /* there are no unsigned CFNumber types so treat the value as signed. the os seems to do this
196ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch         internally (CFNumberType of locationID is 3) */
197ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      CFTypeRef locationCF = CFNumberCreate (NULL, kCFNumberSInt32Type, &location);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CFDictionarySetValue (propertyMatchDict, CFSTR(kUSBDevicePropertyLocationID), locationCF);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* release our reference to the CFNumber (CFDictionarySetValue retains it) */
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CFRelease (locationCF);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CFDictionarySetValue (matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* release out reference to the CFMutableDictionaryRef (CFDictionarySetValue retains it) */
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CFRelease (propertyMatchDict);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* else we can still proceed as long as the caller accounts for the possibility of other devices in the iterator */
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, deviceIterator);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)/* Returns 1 on success, 0 on failure. */
214ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int get_ioregistry_value_number (io_service_t service, CFStringRef property, CFNumberType type, void *p) {
215ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CFTypeRef cfNumber = IORegistryEntryCreateCFProperty (service, property, kCFAllocatorDefault, 0);
216ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int ret = 0;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
218ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (cfNumber) {
219ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (CFGetTypeID(cfNumber) == CFNumberGetTypeID()) {
220ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      ret = CFNumberGetValue(cfNumber, type, p);
221ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
223ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    CFRelease (cfNumber);
224ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
226ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return ret;
227ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
229ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic usb_device_t **darwin_device_from_service (io_service_t service)
230ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch{
231ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  io_cf_plugin_ref_t *plugInInterface = NULL;
232ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usb_device_t **device;
233ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  kern_return_t result;
234ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  SInt32 score;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
236ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  result = IOCreatePlugInInterfaceForService(service, kIOUSBDeviceUserClientTypeID,
237ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                             kIOCFPlugInInterfaceID, &plugInInterface,
238ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                             &score);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
240ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (kIOReturnSuccess != result || !plugInInterface) {
241ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_dbg ("could not set up plugin for service: %s\n", darwin_error_str (result));
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
243ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (void)(*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID),
246ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                           (LPVOID)&device);
247ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* Use release instead of IODestroyPlugInInterface to avoid stopping IOServices associated with this device */
248ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  (*plugInInterface)->Release (plugInInterface);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return device;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
253ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic void darwin_devices_attached (void *ptr, io_iterator_t add_devices) {
254ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct libusb_context *ctx;
255ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  io_service_t service;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
257ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_mutex_lock(&active_contexts_lock);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
259ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  while ((service = IOIteratorNext(add_devices))) {
260ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* add this device to each active context's device list */
261ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
262ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      process_new_device (ctx, service);;
263ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    IOObjectRelease(service);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
268ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_mutex_unlock(&active_contexts_lock);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
272ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct libusb_device *dev = NULL;
273ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct libusb_context *ctx;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_service_t device;
276ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  UInt64 session;
277ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int ret;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while ((device = IOIteratorNext (rem_devices)) != 0) {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* get the location from the i/o registry */
281ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ret = get_ioregistry_value_number (device, CFSTR("sessionID"), kCFNumberSInt64Type, &session);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IOObjectRelease (device);
283ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (!ret)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
286ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_mutex_lock(&active_contexts_lock);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
288ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
289ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      usbi_dbg ("notifying context %p of device disconnect", ctx);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      dev = usbi_get_device_by_session_id(ctx, (unsigned long) session);
292ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      if (dev) {
293ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        /* signal the core that this device has been disconnected. the core will tear down this device
294ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch           when the reference count reaches 0 */
295ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        usbi_disconnect_device(dev);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
299ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_mutex_unlock(&active_contexts_lock);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void darwin_clear_iterator (io_iterator_t iter) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_service_t device;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while ((device = IOIteratorNext (iter)) != 0)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IOObjectRelease (device);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
310ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic void *darwin_event_thread_main (void *arg0) {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn kresult;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct libusb_context *ctx = (struct libusb_context *)arg0;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CFRunLoopRef runloop;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  /* Set this thread's name, so it can be seen in the debugger
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch     and crash reports. */
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
318ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  pthread_setname_np ("org.libusb.device-hotplug");
319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Tell the Objective-C garbage collector about this thread.
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     This is required because, unlike NSThreads, pthreads are
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     not automatically registered. Although we don't use
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     Objective-C, we use CoreFoundation, which does. */
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  objc_registerThreadWithCollector();
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
327ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* hotplug (device arrival/removal) sources */
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CFRunLoopSourceRef     libusb_notification_cfsource;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_notification_port_t libusb_notification_port;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_iterator_t          libusb_rem_device_iterator;
331ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  io_iterator_t          libusb_add_device_iterator;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
333ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("creating hotplug event source");
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  runloop = CFRunLoopGetCurrent ();
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CFRetain (runloop);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* add the notification port to the run loop */
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  libusb_notification_port     = IONotificationPortCreate (kIOMasterPortDefault);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  libusb_notification_cfsource = IONotificationPortGetRunLoopSource (libusb_notification_port);
341eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CFRunLoopAddSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* create notifications for removed devices */
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = IOServiceAddMatchingNotification (libusb_notification_port, kIOTerminatedNotification,
345ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                              IOServiceMatching(kIOUSBDeviceClassName),
346ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                              (IOServiceMatchingCallback)darwin_devices_detached,
347ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                              (void *)ctx, &libusb_rem_device_iterator);
348ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
349ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (kresult != kIOReturnSuccess) {
350ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult));
351ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
352ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    pthread_exit (NULL);
353ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
354ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
355ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* create notifications for attached devices */
356ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  kresult = IOServiceAddMatchingNotification(libusb_notification_port, kIOFirstMatchNotification,
357ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                              IOServiceMatching(kIOUSBDeviceClassName),
358ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                              (IOServiceMatchingCallback)darwin_devices_attached,
359ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                              (void *)ctx, &libusb_add_device_iterator);
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult != kIOReturnSuccess) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult));
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pthread_exit (NULL);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* arm notifiers */
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  darwin_clear_iterator (libusb_rem_device_iterator);
369ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  darwin_clear_iterator (libusb_add_device_iterator);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
371ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("darwin event thread ready to receive events");
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
373ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* signal the main thread that the hotplug runloop has been created. */
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_mutex_lock (&libusb_darwin_at_mutex);
375eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  libusb_darwin_acfl = runloop;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_cond_signal (&libusb_darwin_at_cond);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_mutex_unlock (&libusb_darwin_at_mutex);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* run the runloop */
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CFRunLoopRun();
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
382ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("darwin event thread exiting");
383ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
384ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* remove the notification cfsource */
385ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CFRunLoopRemoveSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode);
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* delete notification port */
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IONotificationPortDestroy (libusb_notification_port);
389ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
390ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* delete iterators */
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOObjectRelease (libusb_rem_device_iterator);
392ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  IOObjectRelease (libusb_add_device_iterator);
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CFRelease (runloop);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  libusb_darwin_acfl = NULL;
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_exit (NULL);
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
401ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic void _darwin_finalize(void) {
402ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *dev, *next;
403ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
404ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_mutex_lock(&darwin_cached_devices_lock);
405ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  list_for_each_entry_safe(dev, next, &darwin_cached_devices, list, struct darwin_cached_device) {
406ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    darwin_deref_cached_device(dev);
407ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
408ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_mutex_unlock(&darwin_cached_devices_lock);
409ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
410ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_init(struct libusb_context *ctx) {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  host_name_port_t host_self;
413ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  static int initted = 0;
414ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int rc;
415ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
416ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  rc = darwin_scan_devices (ctx);
417ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (LIBUSB_SUCCESS != rc) {
418ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return rc;
419ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
421eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (OSAtomicIncrement32Barrier(&initCount) == 1) {
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* create the clocks that will be used */
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
424ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (!initted) {
425ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      initted = 1;
426ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      atexit(_darwin_finalize);
427ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
428ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_self = mach_host_self();
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_get_clock_service(host_self, CALENDAR_CLOCK, &clock_realtime);
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_get_clock_service(host_self, SYSTEM_CLOCK, &clock_monotonic);
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mach_port_deallocate(mach_task_self(), host_self);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
434ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    pthread_create (&libusb_darwin_at, NULL, darwin_event_thread_main, (void *)ctx);
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pthread_mutex_lock (&libusb_darwin_at_mutex);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (!libusb_darwin_acfl)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pthread_cond_wait (&libusb_darwin_at_cond, &libusb_darwin_at_mutex);
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pthread_mutex_unlock (&libusb_darwin_at_mutex);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
442ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return rc;
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void darwin_exit (void) {
446eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (OSAtomicDecrement32Barrier(&initCount) == 0) {
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mach_port_deallocate(mach_task_self(), clock_realtime);
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mach_port_deallocate(mach_task_self(), clock_monotonic);
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
450ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* stop the event runloop and wait for the thread to terminate. */
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CFRunLoopStop (libusb_darwin_acfl);
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pthread_join (libusb_darwin_at, NULL);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian) {
457ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* return cached copy */
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memmove (buffer, &(priv->dev_descriptor), DEVICE_DESC_LENGTH);
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *host_endian = 0;
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int get_configuration_index (struct libusb_device *dev, int config_value) {
468ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt8 i, numConfig;
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOUSBConfigurationDescriptorPtr desc;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn kresult;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* is there a simpler way to determine the index? */
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(priv->device))->GetNumberOfConfigurations (priv->device, &numConfig);
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult != kIOReturnSuccess)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return darwin_to_libusb (kresult);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = 0 ; i < numConfig ; i++) {
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*(priv->device))->GetConfigurationDescriptorPtr (priv->device, i, &desc);
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (desc->bConfigurationValue == config_value)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i;
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* configuration not found */
486ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return LIBUSB_ERROR_NOT_FOUND;
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) {
490ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int config_index;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (0 == priv->active_config)
494ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return LIBUSB_ERROR_NOT_FOUND;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  config_index = get_configuration_index (dev, priv->active_config);
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (config_index < 0)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return config_index;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return darwin_get_config_descriptor (dev, config_index, buffer, len, host_endian);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) {
504ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOUSBConfigurationDescriptorPtr desc;
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn kresult;
507ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int ret;
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
509ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!priv || !priv->device)
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_OTHER;
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
512ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  kresult = (*priv->device)->GetConfigurationDescriptorPtr (priv->device, config_index, &desc);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult == kIOReturnSuccess) {
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* copy descriptor */
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (libusb_le16_to_cpu(desc->wTotalLength) < len)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      len = libusb_le16_to_cpu(desc->wTotalLength);
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memmove (buffer, desc, len);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* GetConfigurationDescriptorPtr returns the descriptor in USB bus order */
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *host_endian = 0;
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
524ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  ret = darwin_to_libusb (kresult);
525ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (ret != LIBUSB_SUCCESS)
526ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return ret;
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
528ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return len;
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* check whether the os has configured the device */
532ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int darwin_check_configuration (struct libusb_context *ctx, struct darwin_cached_device *dev) {
533ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usb_device_t **darwin_device = dev->device;
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOUSBConfigurationDescriptorPtr configDesc;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOUSBFindInterfaceRequest request;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kern_return_t             kresult;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_iterator_t             interface_iterator;
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_service_t              firstInterface;
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
541ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (dev->dev_descriptor.bNumConfigurations < 1) {
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (ctx, "device has no configurations");
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_OTHER; /* no configurations at this speed so we can't use it */
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* find the first configuration */
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*darwin_device)->GetConfigurationDescriptorPtr (darwin_device, 0, &configDesc);
548ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  dev->first_config = (kIOReturnSuccess == kresult) ? configDesc->bConfigurationValue : 1;
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* check if the device is already configured. there is probably a better way than iterating over the
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     to accomplish this (the trick is we need to avoid a call to GetConfigurations since buggy devices
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     might lock up on the device request) */
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Setup the Interface Request */
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request.bInterfaceClass    = kIOUSBFindInterfaceDontCare;
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request.bAlternateSetting  = kIOUSBFindInterfaceDontCare;
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator);
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult)
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return darwin_to_libusb (kresult);
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* iterate once */
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  firstInterface = IOIteratorNext(interface_iterator);
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* done with the interface iterator */
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOObjectRelease(interface_iterator);
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (firstInterface) {
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IOObjectRelease (firstInterface);
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* device is configured */
574ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (dev->dev_descriptor.bNumConfigurations == 1)
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* to avoid problems with some devices get the configurations value from the configuration descriptor */
576ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      dev->active_config = dev->first_config;
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* devices with more than one configuration should work with GetConfiguration */
579ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      (*darwin_device)->GetConfiguration (darwin_device, &dev->active_config);
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* not configured */
582ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    dev->active_config = 0;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
584ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("active config: %u, first config: %u", dev->active_config, dev->first_config);
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
589ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int darwin_request_descriptor (usb_device_t **device, UInt8 desc, UInt8 desc_index, void *buffer, size_t buffer_size) {
590ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  IOUSBDevRequestTO req;
591ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
592ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  memset (buffer, 0, buffer_size);
593ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
594ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* Set up request for descriptor/ */
595ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
596ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  req.bRequest      = kUSBRqGetDescriptor;
597ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  req.wValue        = desc << 8;
598ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  req.wIndex        = desc_index;
599ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  req.wLength       = buffer_size;
600ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  req.pData         = buffer;
601ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  req.noDataTimeout = 20;
602ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  req.completionTimeout = 100;
603ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
604ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return (*device)->DeviceRequestTO (device, &req);
605ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
606ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
607ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int darwin_cache_device_descriptor (struct libusb_context *ctx, struct darwin_cached_device *dev) {
608ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usb_device_t **device = dev->device;
609ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int retries = 1, delay = 30000;
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int unsuspended = 0, try_unsuspend = 1, try_reconfigure = 1;
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int is_open = 0;
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int ret = 0, ret2;
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt8 bDeviceClass;
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UInt16 idProduct, idVendor;
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
616ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  dev->can_enumerate = 0;
617ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (*device)->GetDeviceClass (device, &bDeviceClass);
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (*device)->GetDeviceProduct (device, &idProduct);
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (*device)->GetDeviceVendor (device, &idVendor);
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
622ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* According to Apple's documentation the device must be open for DeviceRequest but we may not be able to open some
623ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * devices and Apple's USB Prober doesn't bother to open the device before issuing a descriptor request.  Still,
624ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch   * to follow the spec as closely as possible, try opening the device */
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_open = ((*device)->USBDeviceOpenSeize(device) == kIOReturnSuccess);
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
628ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /**** retrieve device descriptor ****/
629ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ret = darwin_request_descriptor (device, kUSBDeviceDesc, 0, &dev->dev_descriptor, sizeof(dev->dev_descriptor));
630ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
631ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (kIOReturnOverrun == ret && kUSBDeviceDesc == dev->dev_descriptor.bDescriptorType)
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* received an overrun error but we still received a device descriptor */
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = kIOReturnSuccess;
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (kIOUSBVendorIDAppleComputer == idVendor) {
636ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      /* NTH: don't bother retrying or unsuspending Apple devices */
637ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
638ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
639ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
640ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (kIOReturnSuccess == ret && (0 == dev->dev_descriptor.bNumConfigurations ||
641ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                    0 == dev->dev_descriptor.bcdUSB)) {
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* work around for incorrectly configured devices */
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (try_reconfigure && is_open) {
644ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        usbi_dbg("descriptor appears to be invalid. resetting configuration before trying again...");
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
646ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        /* set the first configuration */
647ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        (*device)->SetConfiguration(device, 1);
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
649ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        /* don't try to reconfigure again */
650ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        try_reconfigure = 0;
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = kIOUSBPipeStalled;
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (kIOReturnSuccess != ret && is_open && try_unsuspend) {
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* device may be suspended. unsuspend it and try again */
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if DeviceVersion >= 320
659ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      UInt32 info = 0;
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* IOUSBFamily 320+ provides a way to detect device suspension but earlier versions do not */
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (void)(*device)->GetUSBDeviceInformation (device, &info);
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
664ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      /* note that the device was suspended */
665ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      if (info & (1 << kUSBInformationDeviceIsSuspendedBit) || 0 == info)
666ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        try_unsuspend = 1;
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (try_unsuspend) {
670ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        /* try to unsuspend the device */
671ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        ret2 = (*device)->USBDeviceSuspend (device, 0);
672ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        if (kIOReturnSuccess != ret2) {
673ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          /* prevent log spew from poorly behaving devices.  this indicates the
674ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch             os actually had trouble communicating with the device */
675ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          usbi_dbg("could not retrieve device descriptor. failed to unsuspend: %s",darwin_error_str(ret2));
676ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        } else
677ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          unsuspended = 1;
678ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
679ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        try_unsuspend = 0;
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (kIOReturnSuccess != ret) {
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      usbi_dbg("kernel responded with code: 0x%08x. sleeping for %d ms before trying again", ret, delay/1000);
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* sleep for a little while before trying again */
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      usleep (delay);
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while (kIOReturnSuccess != ret && retries--);
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (unsuspended)
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* resuspend the device */
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (void)(*device)->USBDeviceSuspend (device, 1);
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_open)
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (void) (*device)->USBDeviceClose (device);
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ret != kIOReturnSuccess) {
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* a debug message was already printed out for this error */
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (LIBUSB_CLASS_HUB == bDeviceClass)
700ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      usbi_dbg ("could not retrieve device descriptor %.4x:%.4x: %s (%x). skipping device",
701ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                idVendor, idProduct, darwin_error_str (ret), ret);
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
703ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      usbi_warn (ctx, "could not retrieve device descriptor %.4x:%.4x: %s (%x). skipping device",
704ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                 idVendor, idProduct, darwin_error_str (ret), ret);
70568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return darwin_to_libusb (ret);
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices. */
709ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (libusb_le16_to_cpu (dev->dev_descriptor.idProduct) != idProduct) {
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* not a valid device */
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_warn (ctx, "idProduct from iokit (%04x) does not match idProduct in descriptor (%04x). skipping device",
712ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch               idProduct, libusb_le16_to_cpu (dev->dev_descriptor.idProduct));
71368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return LIBUSB_ERROR_NO_DEVICE;
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
716ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("cached device descriptor:");
717ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("  bDescriptorType:    0x%02x", dev->dev_descriptor.bDescriptorType);
718ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("  bcdUSB:             0x%04x", dev->dev_descriptor.bcdUSB);
719ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("  bDeviceClass:       0x%02x", dev->dev_descriptor.bDeviceClass);
720ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("  bDeviceSubClass:    0x%02x", dev->dev_descriptor.bDeviceSubClass);
721ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("  bDeviceProtocol:    0x%02x", dev->dev_descriptor.bDeviceProtocol);
722ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("  bMaxPacketSize0:    0x%02x", dev->dev_descriptor.bMaxPacketSize0);
723ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("  idVendor:           0x%04x", dev->dev_descriptor.idVendor);
724ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("  idProduct:          0x%04x", dev->dev_descriptor.idProduct);
725ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("  bcdDevice:          0x%04x", dev->dev_descriptor.bcdDevice);
726ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("  iManufacturer:      0x%02x", dev->dev_descriptor.iManufacturer);
727ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("  iProduct:           0x%02x", dev->dev_descriptor.iProduct);
728ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("  iSerialNumber:      0x%02x", dev->dev_descriptor.iSerialNumber);
729ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("  bNumConfigurations: 0x%02x", dev->dev_descriptor.bNumConfigurations);
730ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
731ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  dev->can_enumerate = 1;
732ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
73368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return LIBUSB_SUCCESS;
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
736ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int darwin_get_cached_device(struct libusb_context *ctx, io_service_t service,
737ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                    struct darwin_cached_device **cached_out) {
738ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *new_device;
73968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  UInt64 sessionID = 0, parent_sessionID = 0;
740ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int ret = LIBUSB_SUCCESS;
741ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usb_device_t **device;
742ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  io_service_t parent;
743ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  kern_return_t result;
744ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  UInt8 port = 0;
745ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
746ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* get some info from the io registry */
747ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  (void) get_ioregistry_value_number (service, CFSTR("sessionID"), kCFNumberSInt64Type, &sessionID);
748ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  (void) get_ioregistry_value_number (service, CFSTR("PortNum"), kCFNumberSInt8Type, &port);
749ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
750ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg("finding cached device for sessionID 0x\n" PRIx64, sessionID);
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
752ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  result = IORegistryEntryGetParentEntry (service, kIOUSBPlane, &parent);
753ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
754ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (kIOReturnSuccess == result) {
755ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    (void) get_ioregistry_value_number (parent, CFSTR("sessionID"), kCFNumberSInt64Type, &parent_sessionID);
756ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    IOObjectRelease(parent);
757ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
758ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
759ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_mutex_lock(&darwin_cached_devices_lock);
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
76168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    *cached_out = NULL;
76268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
763ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    list_for_each_entry(new_device, &darwin_cached_devices, list, struct darwin_cached_device) {
764ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      usbi_dbg("matching sessionID 0x%x against cached device with sessionID 0x%x", sessionID, new_device->session);
765ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      if (new_device->session == sessionID) {
766ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        usbi_dbg("using cached device for device");
767ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        *cached_out = new_device;
768ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        break;
769ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      }
770ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
772ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (*cached_out)
773ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
774ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
775ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_dbg("caching new device with sessionID 0x%x\n", sessionID);
776ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
777ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    device = darwin_device_from_service (service);
778ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (!device) {
779ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      ret = LIBUSB_ERROR_NO_DEVICE;
78068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      break;
78168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
78268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
78368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    new_device = calloc (1, sizeof (*new_device));
78468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (!new_device) {
78568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ret = LIBUSB_ERROR_NO_MEM;
786ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
787ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
789ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* add this device to the cached device list */
790ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    list_add(&new_device->list, &darwin_cached_devices);
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
792ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    (*device)->GetDeviceAddress (device, (USBDeviceAddress *)&new_device->address);
793ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
794ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* keep a reference to this device */
795ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    darwin_ref_cached_device(new_device);
796ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
797ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    new_device->device = device;
798ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    new_device->session = sessionID;
799ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    (*device)->GetLocationID (device, &new_device->location);
800ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    new_device->port = port;
801ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    new_device->parent_session = parent_sessionID;
802ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
803ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* cache the device descriptor */
804ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ret = darwin_cache_device_descriptor(ctx, new_device);
805ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (ret)
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
808ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (new_device->can_enumerate) {
809ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      snprintf(new_device->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", new_device->address,
810ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch               new_device->dev_descriptor.idVendor, new_device->dev_descriptor.idProduct,
811ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch               new_device->dev_descriptor.bDeviceClass, new_device->dev_descriptor.bDeviceSubClass);
812ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
813ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  } while (0);
814ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
815ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_mutex_unlock(&darwin_cached_devices_lock);
816ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
817ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* keep track of devices regardless of if we successfully enumerate them to
818ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch     prevent them from being enumerated multiple times */
819ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
820ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  *cached_out = new_device;
821ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
822ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return ret;
823ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
824ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
825ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int process_new_device (struct libusb_context *ctx, io_service_t service) {
826ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_device_priv *priv;
827ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct libusb_device *dev = NULL;
828ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *cached_device;
829ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  UInt8 devSpeed;
830ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int ret = 0;
831ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
832ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  do {
833ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ret = darwin_get_cached_device (ctx, service, &cached_device);
834ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
83568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (ret < 0 || !cached_device->can_enumerate) {
836ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return ret;
837ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
838ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
839ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* check current active configuration (and cache the first configuration value--
840ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch       which may be used by claim_interface) */
841ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ret = darwin_check_configuration (ctx, cached_device);
842ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (ret)
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_dbg ("allocating new device in context %p for with session 0x%08x",
846ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch              ctx, cached_device->session);
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
84868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    dev = usbi_alloc_device(ctx, (unsigned long) cached_device->session);
849ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (!dev) {
850ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return LIBUSB_ERROR_NO_MEM;
851ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
852ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
853ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    priv = (struct darwin_device_priv *)dev->os_priv;
854ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
855ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    priv->dev = cached_device;
856ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    darwin_ref_cached_device (priv->dev);
857ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
858ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (cached_device->parent_session > 0) {
85968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      dev->parent_dev = usbi_get_device_by_session_id (ctx, (unsigned long) cached_device->parent_session);
860ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    } else {
861ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      dev->parent_dev = NULL;
862ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
863ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    dev->port_number    = cached_device->port;
864ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    dev->bus_number     = cached_device->location >> 24;
865ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    dev->device_address = cached_device->address;
866ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
867ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* need to add a reference to the parent device */
868ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (dev->parent_dev) {
869ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      libusb_ref_device(dev->parent_dev);
870ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
871ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
872ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    (*(priv->dev->device))->GetDeviceSpeed (priv->dev->device, &devSpeed);
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (devSpeed) {
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kUSBDeviceSpeedLow: dev->speed = LIBUSB_SPEED_LOW; break;
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kUSBDeviceSpeedFull: dev->speed = LIBUSB_SPEED_FULL; break;
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kUSBDeviceSpeedHigh: dev->speed = LIBUSB_SPEED_HIGH; break;
878ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if DeviceVersion >= 500
879ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    case kUSBDeviceSpeedSuper: dev->speed = LIBUSB_SPEED_SUPER; break;
880ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      usbi_warn (ctx, "Got unknown device speed %d", devSpeed);
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = usbi_sanitize_device (dev);
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ret < 0)
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
889ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_dbg ("found device with address %d port = %d parent = %p at %p", dev->device_address,
890ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch              dev->port_number, (void *) dev->parent_dev, priv->dev->sys_path);
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while (0);
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
893ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (0 == ret) {
894ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_connect_device (dev);
895ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  } else {
896ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    libusb_unref_device (dev);
897ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
902ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstatic int darwin_scan_devices(struct libusb_context *ctx) {
903ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  io_iterator_t deviceIterator;
904ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  io_service_t service;
905ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  kern_return_t kresult;
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = usb_setup_device_iterator (&deviceIterator, 0);
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult != kIOReturnSuccess)
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return darwin_to_libusb (kresult);
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
911ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  while ((service = IOIteratorNext (deviceIterator))) {
912ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    (void) process_new_device (ctx, service);
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
914ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    IOObjectRelease(service);
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOObjectRelease(deviceIterator);
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_open (struct libusb_device_handle *dev_handle) {
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
924ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn kresult;
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (0 == dpriv->open_count) {
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* try to open the device */
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kresult = (*(dpriv->device))->USBDeviceOpenSeize (dpriv->device);
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (kresult != kIOReturnSuccess) {
931ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      usbi_warn (HANDLE_CTX (dev_handle), "USBDeviceOpen: %s", darwin_error_str(kresult));
932ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
933ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      if (kIOReturnExclusiveAccess != kresult) {
934ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        return darwin_to_libusb (kresult);
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
936ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
937ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      /* it is possible to perform some actions on a device that is not open so do not return an error */
938ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      priv->is_open = 0;
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
940ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      priv->is_open = 1;
941ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
943ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* create async event source */
944ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    kresult = (*(dpriv->device))->CreateDeviceAsyncEventSource (dpriv->device, &priv->cfSource);
945ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (kresult != kIOReturnSuccess) {
946ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      usbi_err (HANDLE_CTX (dev_handle), "CreateDeviceAsyncEventSource: %s", darwin_error_str(kresult));
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
948ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      if (priv->is_open) {
949ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        (*(dpriv->device))->USBDeviceClose (dpriv->device);
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
952ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      priv->is_open = 0;
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
954ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return darwin_to_libusb (kresult);
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
956ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
957ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    CFRetain (libusb_darwin_acfl);
958ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
959ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* add the cfSource to the aync run loop */
960ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    CFRunLoopAddSource(libusb_darwin_acfl, priv->cfSource, kCFRunLoopCommonModes);
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* device opened successfully */
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dpriv->open_count++;
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* create a file descriptor for notifications */
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pipe (priv->fds);
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* set the pipe to be non-blocking */
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fcntl (priv->fds[1], F_SETFD, O_NONBLOCK);
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usbi_add_pollfd(HANDLE_CTX(dev_handle), priv->fds[0], POLLIN);
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
974ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("device open for access");
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void darwin_close (struct libusb_device_handle *dev_handle) {
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
981ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn kresult;
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dpriv->open_count == 0) {
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* something is probably very wrong if this is the case */
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (HANDLE_CTX (dev_handle), "Close called on a device that was not open!\n");
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dpriv->open_count--;
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* make sure all interfaces are released */
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = 0 ; i < USB_MAXINTERFACES ; i++)
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (dev_handle->claimed_interfaces & (1 << i))
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      libusb_release_interface (dev_handle, i);
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (0 == dpriv->open_count) {
999ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* delete the device's async event source */
1000ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (priv->cfSource) {
1001ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      CFRunLoopRemoveSource (libusb_darwin_acfl, priv->cfSource, kCFRunLoopDefaultMode);
1002ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      CFRelease (priv->cfSource);
1003ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      priv->cfSource = NULL;
1004ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      CFRelease (libusb_darwin_acfl);
1005ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1007ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (priv->is_open) {
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* close the device */
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kresult = (*(dpriv->device))->USBDeviceClose(dpriv->device);
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (kresult) {
1011ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        /* Log the fact that we had a problem closing the file, however failing a
1012ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch         * close isn't really an error, so return success anyway */
1013ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        usbi_warn (HANDLE_CTX (dev_handle), "USBDeviceClose: %s", darwin_error_str(kresult));
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* file descriptors are maintained per-instance */
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usbi_remove_pollfd (HANDLE_CTX (dev_handle), priv->fds[0]);
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  close (priv->fds[1]);
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  close (priv->fds[0]);
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  priv->fds[0] = priv->fds[1] = -1;
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_get_configuration(struct libusb_device_handle *dev_handle, int *config) {
1027ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *config = (int) dpriv->active_config;
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_set_configuration(struct libusb_device_handle *dev_handle, int config) {
1035ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn kresult;
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Setting configuration will invalidate the interface, so we need
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     to reclaim it. First, dispose of existing interfaces, if any. */
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = 0 ; i < USB_MAXINTERFACES ; i++)
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (dev_handle->claimed_interfaces & (1 << i))
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      darwin_release_interface (dev_handle, i);
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(dpriv->device))->SetConfiguration (dpriv->device, config);
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult != kIOReturnSuccess)
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return darwin_to_libusb (kresult);
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Reclaim any interfaces. */
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = 0 ; i < USB_MAXINTERFACES ; i++)
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (dev_handle->claimed_interfaces & (1 << i))
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      darwin_claim_interface (dev_handle, i);
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dpriv->active_config = config;
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_get_interface (usb_device_t **darwin_device, uint8_t ifc, io_service_t *usbInterfacep) {
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOUSBFindInterfaceRequest request;
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kern_return_t             kresult;
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_iterator_t             interface_iterator;
1063ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  UInt8                     bInterfaceNumber;
1064ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int                       ret;
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *usbInterfacep = IO_OBJECT_NULL;
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Setup the Interface Request */
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request.bInterfaceClass    = kIOUSBFindInterfaceDontCare;
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request.bAlternateSetting  = kIOUSBFindInterfaceDontCare;
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator);
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult)
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kresult;
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1078ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  while ((*usbInterfacep = IOIteratorNext(interface_iterator))) {
1079ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* find the interface number */
1080ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ret = get_ioregistry_value_number (*usbInterfacep, CFSTR("bInterfaceNumber"), kCFNumberSInt8Type,
1081ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                       &bInterfaceNumber);
1082ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1083ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (ret && bInterfaceNumber == ifc) {
1084ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1085ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1086ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1087ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    (void) IOObjectRelease (*usbInterfacep);
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* done with the interface iterator */
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOObjectRelease(interface_iterator);
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int get_endpoints (struct libusb_device_handle *dev_handle, int iface) {
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* current interface */
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_interface *cInterface = &priv->interfaces[iface];
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kern_return_t kresult;
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  u_int8_t numep, direction, number;
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  u_int8_t dont_care1, dont_care3;
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  u_int16_t dont_care2;
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1109ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("building table of endpoints.");
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* retrieve the total number of endpoints on this interface */
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(cInterface->interface))->GetNumEndpoints(cInterface->interface, &numep);
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult) {
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (HANDLE_CTX (dev_handle), "can't get number of endpoints for interface: %s", darwin_error_str(kresult));
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return darwin_to_libusb (kresult);
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* iterate through pipe references */
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = 1 ; i <= numep ; i++) {
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kresult = (*(cInterface->interface))->GetPipeProperties(cInterface->interface, i, &direction, &number, &dont_care1,
1121ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                            &dont_care2, &dont_care3);
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (kresult != kIOReturnSuccess) {
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      usbi_err (HANDLE_CTX (dev_handle), "error getting pipe information for pipe %d: %s", i, darwin_error_str(kresult));
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return darwin_to_libusb (kresult);
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1129ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_dbg ("interface: %i pipe %i: dir: %i number: %i", iface, i, direction, number);
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cInterface->endpoint_addrs[i - 1] = ((direction << 7 & LIBUSB_ENDPOINT_DIR_MASK) | (number & LIBUSB_ENDPOINT_ADDRESS_MASK));
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cInterface->num_endpoints = numep;
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface) {
1140ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_service_t          usbInterface = IO_OBJECT_NULL;
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn kresult;
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOCFPlugInInterface **plugInInterface = NULL;
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SInt32                score;
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* current interface */
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_interface *cInterface = &priv->interfaces[iface];
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = darwin_get_interface (dpriv->device, iface, &usbInterface);
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult != kIOReturnSuccess)
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return darwin_to_libusb (kresult);
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* make sure we have an interface */
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usbInterface && dpriv->first_config != 0) {
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_info (HANDLE_CTX (dev_handle), "no interface found; setting configuration: %d", dpriv->first_config);
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* set the configuration */
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kresult = darwin_set_configuration (dev_handle, dpriv->first_config);
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (kresult != LIBUSB_SUCCESS) {
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      usbi_err (HANDLE_CTX (dev_handle), "could not set configuration");
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return kresult;
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kresult = darwin_get_interface (dpriv->device, iface, &usbInterface);
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (kresult) {
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult));
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return darwin_to_libusb (kresult);
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!usbInterface) {
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (HANDLE_CTX (dev_handle), "interface not found");
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_NOT_FOUND;
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* get an interface to the device's interface */
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = IOCreatePlugInInterfaceForService (usbInterface, kIOUSBInterfaceUserClientTypeID,
1179ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                               kIOCFPlugInInterfaceID, &plugInInterface, &score);
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* ignore release error */
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (void)IOObjectRelease (usbInterface);
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult) {
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (HANDLE_CTX (dev_handle), "IOCreatePlugInInterfaceForService: %s", darwin_error_str(kresult));
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return darwin_to_libusb (kresult);
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!plugInInterface) {
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (HANDLE_CTX (dev_handle), "plugin interface not found");
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_NOT_FOUND;
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Do the actual claim */
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*plugInInterface)->QueryInterface(plugInInterface,
1196ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                               CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
1197ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                               (LPVOID)&cInterface->interface);
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* We no longer need the intermediate plug-in */
1199ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* Use release instead of IODestroyPlugInInterface to avoid stopping IOServices associated with this device */
1200ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  (*plugInInterface)->Release (plugInInterface);
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult || !cInterface->interface) {
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (HANDLE_CTX (dev_handle), "QueryInterface: %s", darwin_error_str(kresult));
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return darwin_to_libusb (kresult);
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* claim the interface */
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(cInterface->interface))->USBInterfaceOpen(cInterface->interface);
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult) {
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (HANDLE_CTX (dev_handle), "USBInterfaceOpen: %s", darwin_error_str(kresult));
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return darwin_to_libusb (kresult);
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* update list of endpoints */
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = get_endpoints (dev_handle, iface);
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult) {
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* this should not happen */
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    darwin_release_interface (dev_handle, iface);
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table");
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kresult;
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cInterface->cfSource = NULL;
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* create async event source */
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(cInterface->interface))->CreateInterfaceAsyncEventSource (cInterface->interface, &cInterface->cfSource);
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult != kIOReturnSuccess) {
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (HANDLE_CTX (dev_handle), "could not create async event source");
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* can't continue without an async event source */
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (void)darwin_release_interface (dev_handle, iface);
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return darwin_to_libusb (kresult);
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* add the cfSource to the async thread's run loop */
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CFRunLoopAddSource(libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode);
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1238ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("interface opened");
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface) {
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn kresult;
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* current interface */
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_interface *cInterface = &priv->interfaces[iface];
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Check to see if an interface is open */
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cInterface->interface)
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_SUCCESS;
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* clean up endpoint data */
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cInterface->num_endpoints = 0;
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* delete the interface's async event source */
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cInterface->cfSource) {
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CFRunLoopRemoveSource (libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode);
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CFRelease (cInterface->cfSource);
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(cInterface->interface))->USBInterfaceClose(cInterface->interface);
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult)
1265ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_warn (HANDLE_CTX (dev_handle), "USBInterfaceClose: %s", darwin_error_str(kresult));
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(cInterface->interface))->Release(cInterface->interface);
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult != kIOReturnSuccess)
1269ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_warn (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult));
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  cInterface->interface = NULL;
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return darwin_to_libusb (kresult);
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) {
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn kresult;
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* current interface */
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_interface *cInterface = &priv->interfaces[iface];
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cInterface->interface)
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_NO_DEVICE;
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(cInterface->interface))->SetAlternateInterface (cInterface->interface, altsetting);
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult != kIOReturnSuccess)
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    darwin_reset_device (dev_handle);
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* update list of endpoints */
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = get_endpoints (dev_handle, iface);
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult) {
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* this should not happen */
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    darwin_release_interface (dev_handle, iface);
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table");
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kresult;
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return darwin_to_libusb (kresult);
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) {
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* current interface */
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_interface *cInterface;
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8_t pipeRef, iface;
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn kresult;
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* determine the interface/endpoint to use */
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ep_to_pipeRef (dev_handle, endpoint, &pipeRef, &iface) != 0) {
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (HANDLE_CTX (dev_handle), "endpoint not found on any open interface");
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_NOT_FOUND;
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cInterface = &priv->interfaces[iface];
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* newer versions of darwin support clearing additional bits on the device's endpoint */
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef);
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult)
1322ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_warn (HANDLE_CTX (dev_handle), "ClearPipeStall: %s", darwin_error_str (kresult));
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return darwin_to_libusb (kresult);
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_reset_device(struct libusb_device_handle *dev_handle) {
1328ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
1329ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  IOUSBDeviceDescriptor descriptor;
1330ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  IOUSBConfigurationDescriptorPtr cached_configuration;
1331ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  IOUSBConfigurationDescriptor configuration;
1332ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  bool reenumerate = false;
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn kresult;
1334ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int i;
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(dpriv->device))->ResetDevice (dpriv->device);
1337ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (kresult) {
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (HANDLE_CTX (dev_handle), "ResetDevice: %s", darwin_error_str (kresult));
1339ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return darwin_to_libusb (kresult);
1340ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1342ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  do {
1343ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_dbg ("darwin/reset_device: checking if device descriptor changed");
1344ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1345ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* ignore return code. if we can't get a descriptor it might be worthwhile re-enumerating anway */
1346ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    (void) darwin_request_descriptor (dpriv->device, kUSBDeviceDesc, 0, &descriptor, sizeof (descriptor));
1347ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1348ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* check if the device descriptor has changed */
1349ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (0 != memcmp (&dpriv->dev_descriptor, &descriptor, sizeof (descriptor))) {
1350ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      reenumerate = true;
1351ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      break;
1352ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1353ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1354ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* check if any configuration descriptor has changed */
1355ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    for (i = 0 ; i < descriptor.bNumConfigurations ; ++i) {
1356ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      usbi_dbg ("darwin/reset_device: checking if configuration descriptor %d changed", i);
1357ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1358ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      (void) darwin_request_descriptor (dpriv->device, kUSBConfDesc, i, &configuration, sizeof (configuration));
1359ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      (*(dpriv->device))->GetConfigurationDescriptorPtr (dpriv->device, i, &cached_configuration);
1360ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1361ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      if (!cached_configuration || 0 != memcmp (cached_configuration, &configuration, sizeof (configuration))) {
1362ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        reenumerate = true;
1363ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        break;
1364ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      }
1365ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1366ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  } while (0);
1367ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1368ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (reenumerate) {
1369ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_dbg ("darwin/reset_device: device requires reenumeration");
1370ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    (void) (*(dpriv->device))->USBDeviceReEnumerate (dpriv->device, 0);
1371ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return LIBUSB_ERROR_NOT_FOUND;
1372ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1373ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1374ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("darwin/reset_device: device reset complete");
1375ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1376ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return LIBUSB_SUCCESS;
13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle, int interface) {
1380ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  io_service_t usbInterface;
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CFTypeRef driver;
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn kresult;
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = darwin_get_interface (dpriv->device, interface, &usbInterface);
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult) {
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult));
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return darwin_to_libusb (kresult);
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  driver = IORegistryEntryCreateCFProperty (usbInterface, kIOBundleIdentifierKey, kCFAllocatorDefault, 0);
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOObjectRelease (usbInterface);
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (driver) {
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CFRelease (driver);
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* no driver */
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* attaching/detaching kernel drivers is not currently supported (maybe in the future?) */
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_attach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) {
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (void)dev_handle;
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (void)interface;
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return LIBUSB_ERROR_NOT_SUPPORTED;
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_detach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) {
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (void)dev_handle;
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (void)interface;
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return LIBUSB_ERROR_NOT_SUPPORTED;
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void darwin_destroy_device(struct libusb_device *dev) {
1419ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_device_priv *dpriv = (struct darwin_device_priv *) dev->os_priv;
1420ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1421ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (dpriv->dev) {
1422ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* need to hold the lock in case this is the last reference to the device */
1423ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_mutex_lock(&darwin_cached_devices_lock);
1424ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    darwin_deref_cached_device (dpriv->dev);
1425ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    dpriv->dev = NULL;
1426ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_mutex_unlock(&darwin_cached_devices_lock);
1427ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int submit_bulk_transfer(struct usbi_transfer *itransfer) {
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn               ret;
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8_t                transferType;
1436ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* None of the values below are used in libusbx for bulk transfers */
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8_t                direction, number, interval, pipeRef, iface;
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16_t               maxPacketSize;
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_interface *cInterface;
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) {
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_NOT_FOUND;
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cInterface = &priv->interfaces[iface];
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1450424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  ret = (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number,
1451424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                                       &transferType, &maxPacketSize, &interval);
1452424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1453424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (ret) {
1454424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    usbi_err (TRANSFER_CTX (transfer), "bulk transfer failed (dir = %s): %s (code = 0x%08x)", IS_XFERIN(transfer) ? "In" : "Out",
1455424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)              darwin_error_str(ret), ret);
1456424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return darwin_to_libusb (ret);
1457424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1458ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1459ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (0 != (transfer->length % maxPacketSize)) {
1460ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* do not need a zero packet */
1461ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    transfer->flags &= ~LIBUSB_TRANSFER_ADD_ZERO_PACKET;
1462ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* submit the request */
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* timeouts are unavailable on interrupt endpoints */
14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (transferType == kUSBInterrupt) {
1467eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (IS_XFERIN(transfer))
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = (*(cInterface->interface))->ReadPipeAsync(cInterface->interface, pipeRef, transfer->buffer,
1469ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                      transfer->length, darwin_async_io_callback, itransfer);
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = (*(cInterface->interface))->WritePipeAsync(cInterface->interface, pipeRef, transfer->buffer,
1472ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                       transfer->length, darwin_async_io_callback, itransfer);
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1476eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (IS_XFERIN(transfer))
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = (*(cInterface->interface))->ReadPipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer,
1478ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                        transfer->length, transfer->timeout, transfer->timeout,
1479ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                        darwin_async_io_callback, (void *)itransfer);
14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = (*(cInterface->interface))->WritePipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer,
1482ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                         transfer->length, transfer->timeout, transfer->timeout,
1483ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                         darwin_async_io_callback, (void *)itransfer);
14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ret)
1487eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    usbi_err (TRANSFER_CTX (transfer), "bulk transfer failed (dir = %s): %s (code = 0x%08x)", IS_XFERIN(transfer) ? "In" : "Out",
1488ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch               darwin_error_str(ret), ret);
14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return darwin_to_libusb (ret);
14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int submit_iso_transfer(struct usbi_transfer *itransfer) {
14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1498ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  IOReturn kresult;
1499ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  uint8_t direction, number, interval, pipeRef, iface, transferType;
1500ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  uint16_t maxPacketSize;
1501ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  UInt64 frame;
1502ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  AbsoluteTime atTime;
1503ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int i;
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_interface *cInterface;
15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* construct an array of IOUSBIsocFrames, reuse the old one if possible */
15085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tpriv->isoc_framelist && tpriv->num_iso_packets != transfer->num_iso_packets) {
15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(tpriv->isoc_framelist);
15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tpriv->isoc_framelist = NULL;
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!tpriv->isoc_framelist) {
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tpriv->num_iso_packets = transfer->num_iso_packets;
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tpriv->isoc_framelist = (IOUSBIsocFrame*) calloc (transfer->num_iso_packets, sizeof(IOUSBIsocFrame));
15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!tpriv->isoc_framelist)
15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return LIBUSB_ERROR_NO_MEM;
15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1520ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* copy the frame list from the libusbx descriptor (the structures differ only is member order) */
15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = 0 ; i < transfer->num_iso_packets ; i++)
15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tpriv->isoc_framelist[i].frReqCount = transfer->iso_packet_desc[i].length;
15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* determine the interface/endpoint to use */
15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) {
15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_NOT_FOUND;
15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cInterface = &priv->interfaces[iface];
15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1533ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* determine the properties of this endpoint and the speed of the device */
1534ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number,
1535ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                 &transferType, &maxPacketSize, &interval);
1536ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
15375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Last but not least we need the bus frame number */
15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(cInterface->interface))->GetBusFrameNumber(cInterface->interface, &frame, &atTime);
15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult) {
15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (TRANSFER_CTX (transfer), "failed to get bus frame number: %d", kresult);
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(tpriv->isoc_framelist);
15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tpriv->isoc_framelist = NULL;
15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return darwin_to_libusb (kresult);
15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1547ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number,
1548ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                 &transferType, &maxPacketSize, &interval);
1549ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
15505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* schedule for a frame a little in the future */
15515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  frame += 4;
15525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cInterface->frames[transfer->endpoint] && frame < cInterface->frames[transfer->endpoint])
15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    frame = cInterface->frames[transfer->endpoint];
15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* submit the request */
1557eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (IS_XFERIN(transfer))
15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kresult = (*(cInterface->interface))->ReadIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame,
1559ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                             transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback,
1560ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                             itransfer);
15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kresult = (*(cInterface->interface))->WriteIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame,
1563ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                              transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback,
1564ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                              itransfer);
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1566ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (LIBUSB_SPEED_FULL == transfer->dev_handle->dev->speed)
1567ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* Full speed */
1568ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    cInterface->frames[transfer->endpoint] = frame + transfer->num_iso_packets * (1 << (interval - 1));
1569ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  else
1570ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* High/super speed */
1571ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    cInterface->frames[transfer->endpoint] = frame + transfer->num_iso_packets * (1 << (interval - 1)) / 8;
15725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult != kIOReturnSuccess) {
1574eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    usbi_err (TRANSFER_CTX (transfer), "isochronous transfer failed (dir: %s): %s", IS_XFERIN(transfer) ? "In" : "Out",
1575ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch               darwin_error_str(kresult));
15765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free (tpriv->isoc_framelist);
15775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tpriv->isoc_framelist = NULL;
15785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return darwin_to_libusb (kresult);
15815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int submit_control_transfer(struct usbi_transfer *itransfer) {
15845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct libusb_control_setup *setup = (struct libusb_control_setup *) transfer->buffer;
1586ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(transfer->dev_handle->dev);
15875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
15885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn               kresult;
15915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bzero(&tpriv->req, sizeof(tpriv->req));
15935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* IOUSBDeviceInterface expects the request in cpu endianess */
15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tpriv->req.bmRequestType     = setup->bmRequestType;
15965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tpriv->req.bRequest          = setup->bRequest;
15975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* these values should be in bus order from libusb_fill_control_setup */
15985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tpriv->req.wValue            = OSSwapLittleToHostInt16 (setup->wValue);
15995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tpriv->req.wIndex            = OSSwapLittleToHostInt16 (setup->wIndex);
16005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tpriv->req.wLength           = OSSwapLittleToHostInt16 (setup->wLength);
1601ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* data is stored after the libusbx control block */
16025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tpriv->req.pData             = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
16035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tpriv->req.completionTimeout = transfer->timeout;
16045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tpriv->req.noDataTimeout     = transfer->timeout;
16055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* all transfers in libusb-1.0 are async */
16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (transfer->endpoint) {
16115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct darwin_interface *cInterface;
16125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint8_t                 pipeRef, iface;
16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) {
16155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
16165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return LIBUSB_ERROR_NOT_FOUND;
16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cInterface = &priv->interfaces[iface];
16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kresult = (*(cInterface->interface))->ControlRequestAsyncTO (cInterface->interface, pipeRef, &(tpriv->req), darwin_async_io_callback, itransfer);
16235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else
16245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* control request on endpoint 0 */
16255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kresult = (*(dpriv->device))->DeviceRequestAsyncTO(dpriv->device, &(tpriv->req), darwin_async_io_callback, itransfer);
16265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kresult != kIOReturnSuccess)
16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (TRANSFER_CTX (transfer), "control request failed: %s", darwin_error_str(kresult));
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return darwin_to_libusb (kresult);
16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_submit_transfer(struct usbi_transfer *itransfer) {
16345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
16355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (transfer->type) {
16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case LIBUSB_TRANSFER_TYPE_CONTROL:
16385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return submit_control_transfer(itransfer);
16395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case LIBUSB_TRANSFER_TYPE_BULK:
16405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case LIBUSB_TRANSFER_TYPE_INTERRUPT:
16415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return submit_bulk_transfer(itransfer);
16425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
16435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return submit_iso_transfer(itransfer);
16445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  default:
16455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
16465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_INVALID_PARAM;
16475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int cancel_control_transfer(struct usbi_transfer *itransfer) {
16515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
1652ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(transfer->dev_handle->dev);
16535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn kresult;
16545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_warn (ITRANSFER_CTX (itransfer), "aborting all transactions control pipe");
16565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dpriv->device)
16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_NO_DEVICE;
16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(dpriv->device))->USBDeviceAbortPipeZero (dpriv->device);
16615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return darwin_to_libusb (kresult);
16635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_abort_transfers (struct usbi_transfer *itransfer) {
16665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
1667ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(transfer->dev_handle->dev);
16685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
16695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_interface *cInterface;
16705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8_t pipeRef, iface;
16715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOReturn kresult;
16725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) {
16745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
16755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_NOT_FOUND;
16775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cInterface = &priv->interfaces[iface];
16805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dpriv->device)
16825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_NO_DEVICE;
16835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1684ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_warn (ITRANSFER_CTX (itransfer), "aborting all transactions on interface %d pipe %d", iface, pipeRef);
16855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* abort transactions */
16875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (*(cInterface->interface))->AbortPipe (cInterface->interface, pipeRef);
16885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1689ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("calling clear pipe stall to clear the data toggle bit");
16905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* newer versions of darwin support clearing additional bits on the device's endpoint */
16925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef);
16935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return darwin_to_libusb (kresult);
16955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_cancel_transfer(struct usbi_transfer *itransfer) {
16985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (transfer->type) {
17015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case LIBUSB_TRANSFER_TYPE_CONTROL:
17025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return cancel_control_transfer(itransfer);
17035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case LIBUSB_TRANSFER_TYPE_BULK:
17045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case LIBUSB_TRANSFER_TYPE_INTERRUPT:
17055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
17065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return darwin_abort_transfers (itransfer);
17075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  default:
17085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
17095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_INVALID_PARAM;
17105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void darwin_clear_transfer_priv (struct usbi_transfer *itransfer) {
17145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
17155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
17165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS && tpriv->isoc_framelist) {
17185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free (tpriv->isoc_framelist);
17195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tpriv->isoc_framelist = NULL;
17205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0) {
17245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct usbi_transfer *itransfer = (struct usbi_transfer *)refcon;
17255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
17265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
1727ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_msg_async_io_complete message = {.itransfer = itransfer, .result = result,
1728ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                                 .size = (UInt32) (uintptr_t) arg0};
1729ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1730ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("an async io operation has completed");
1731ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1732ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  /* if requested write a zero packet */
1733ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (kIOReturnSuccess == result && IS_XFEROUT(transfer) && transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
1734ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    struct darwin_interface *cInterface;
1735ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    uint8_t iface, pipeRef;
17365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1737ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    (void) ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface);
1738ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    cInterface = &priv->interfaces[iface];
17395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1740ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    (*(cInterface->interface))->WritePipe (cInterface->interface, pipeRef, transfer->buffer, 0);
1741ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
17425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* send a completion message to the device's file descriptor */
17445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  write (priv->fds[1], &message, sizeof (message));
17455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_transfer_status (struct usbi_transfer *itransfer, kern_return_t result) {
17485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (itransfer->flags & USBI_TRANSFER_TIMED_OUT)
17495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = kIOUSBTransactionTimeout;
17505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (result) {
17525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnUnderrun:
17535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnSuccess:
17545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_TRANSFER_COMPLETED;
17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnAborted:
17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_TRANSFER_CANCELLED;
17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOUSBPipeStalled:
1758ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_dbg ("transfer error: pipe is stalled");
17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_TRANSFER_STALL;
17605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOReturnOverrun:
1761ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: data overrun");
17625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_TRANSFER_OVERFLOW;
17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case kIOUSBTransactionTimeout:
1764ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: timed out");
17655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    itransfer->flags |= USBI_TRANSFER_TIMED_OUT;
17665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_TRANSFER_TIMED_OUT;
17675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  default:
1768ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: %s (value = 0x%08x)", darwin_error_str (result), result);
17695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_TRANSFER_ERROR;
17705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void darwin_handle_callback (struct usbi_transfer *itransfer, kern_return_t result, UInt32 io_size) {
17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
17755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int isIsoc      = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type;
17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int isBulk      = LIBUSB_TRANSFER_TYPE_BULK == transfer->type;
17785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int isControl   = LIBUSB_TRANSFER_TYPE_CONTROL == transfer->type;
17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int isInterrupt = LIBUSB_TRANSFER_TYPE_INTERRUPT == transfer->type;
17805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
17815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!isIsoc && !isBulk && !isControl && !isInterrupt) {
17835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
17845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1787ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  usbi_dbg ("handling %s completion with kernel status %d",
1788ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch             isControl ? "control" : isBulk ? "bulk" : isIsoc ? "isoc" : "interrupt", result);
17895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kIOReturnSuccess == result || kIOReturnUnderrun == result) {
17915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (isIsoc && tpriv->isoc_framelist) {
17925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* copy isochronous results back */
17935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (i = 0; i < transfer->num_iso_packets ; i++) {
1795ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
1796ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        lib_desc->status = darwin_to_libusb (tpriv->isoc_framelist[i].frStatus);
1797ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        lib_desc->actual_length = tpriv->isoc_framelist[i].frActCount;
17985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
17995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (!isIsoc)
18005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      itransfer->transferred += io_size;
18015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* it is ok to handle cancelled transfers without calling usbi_handle_transfer_cancellation (we catch timeout transfers) */
18045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usbi_handle_transfer_completion (itransfer, darwin_transfer_status (itransfer, result));
18055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int op_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready) {
1808ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  struct darwin_msg_async_io_complete message;
18095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  POLL_NFDS_TYPE i = 0;
18105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ssize_t ret;
18115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usbi_mutex_lock(&ctx->open_devs_lock);
1813ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
18145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = 0; i < nfds && num_ready > 0; i++) {
18155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct pollfd *pollfd = &fds[i];
18165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1817ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    usbi_dbg ("checking fd %i with revents = %x", pollfd->fd, pollfd->revents);
18185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!pollfd->revents)
18205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
18215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_ready--;
18235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1824ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (pollfd->revents & POLLERR) {
1825ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      /* this probably will never happen so ignore the error an move on. */
18265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1827ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
18285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1829ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    /* there is only one type of message */
1830ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ret = read (pollfd->fd, &message, sizeof (message));
1831ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (ret < (ssize_t) sizeof (message)) {
1832ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      usbi_dbg ("WARNING: short read on async io completion pipe\n");
1833ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      continue;
18345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1835ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1836ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    darwin_handle_callback (message.itransfer, message.result, message.size);
18375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usbi_mutex_unlock(&ctx->open_devs_lock);
18405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
18425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int darwin_clock_gettime(int clk_id, struct timespec *tp) {
18455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mach_timespec_t sys_time;
18465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  clock_serv_t clock_ref;
18475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (clk_id) {
18495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case USBI_CLOCK_REALTIME:
18505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* CLOCK_REALTIME represents time since the epoch */
18515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clock_ref = clock_realtime;
18525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    break;
18535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case USBI_CLOCK_MONOTONIC:
18545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* use system boot time as reference for the monotonic clock */
18555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clock_ref = clock_monotonic;
18565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    break;
18575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  default:
18585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LIBUSB_ERROR_INVALID_PARAM;
18595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
18605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  clock_get_time (clock_ref, &sys_time);
18625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp->tv_sec  = sys_time.tv_sec;
18645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tp->tv_nsec = sys_time.tv_nsec;
18655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
18675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const struct usbi_os_backend darwin_backend = {
1870ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .name = "Darwin",
1871ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .caps = 0,
1872ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .init = darwin_init,
1873ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .exit = darwin_exit,
1874ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .get_device_list = NULL, /* not needed */
1875ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .get_device_descriptor = darwin_get_device_descriptor,
1876ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .get_active_config_descriptor = darwin_get_active_config_descriptor,
1877ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .get_config_descriptor = darwin_get_config_descriptor,
1878ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1879ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .open = darwin_open,
1880ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .close = darwin_close,
1881ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .get_configuration = darwin_get_configuration,
1882ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .set_configuration = darwin_set_configuration,
1883ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .claim_interface = darwin_claim_interface,
1884ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .release_interface = darwin_release_interface,
1885ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1886ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .set_interface_altsetting = darwin_set_interface_altsetting,
1887ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .clear_halt = darwin_clear_halt,
1888ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .reset_device = darwin_reset_device,
1889ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1890ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .kernel_driver_active = darwin_kernel_driver_active,
1891ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .detach_kernel_driver = darwin_detach_kernel_driver,
1892ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .attach_kernel_driver = darwin_attach_kernel_driver,
1893ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1894ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .destroy_device = darwin_destroy_device,
1895ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1896ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .submit_transfer = darwin_submit_transfer,
1897ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .cancel_transfer = darwin_cancel_transfer,
1898ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .clear_transfer_priv = darwin_clear_transfer_priv,
1899ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1900ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .handle_events = op_handle_events,
1901ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1902ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .clock_gettime = darwin_clock_gettime,
1903ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1904ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .device_priv_size = sizeof(struct darwin_device_priv),
1905ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .device_handle_priv_size = sizeof(struct darwin_device_handle_priv),
1906ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .transfer_priv_size = sizeof(struct darwin_transfer_priv),
1907ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        .add_iso_packet_size = 0,
19085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1909