1bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev/* 2bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * darwin backend for libusb 1.0 3bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Copyright (C) 2008-2010 Nathan Hjelm <hjelmn@users.sourceforge.net> 4bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 5bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * This library is free software; you can redistribute it and/or 6bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * modify it under the terms of the GNU Lesser General Public 7bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * License as published by the Free Software Foundation; either 8bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * version 2.1 of the License, or (at your option) any later version. 9bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 10bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * This library is distributed in the hope that it will be useful, 11bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * but WITHOUT ANY WARRANTY; without even the implied warranty of 12bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Lesser General Public License for more details. 14bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * 15bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * You should have received a copy of the GNU Lesser General Public 16bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * License along with this library; if not, write to the Free Software 17bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev */ 19bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 20bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <config.h> 21bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <ctype.h> 22bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <dirent.h> 23bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <errno.h> 24bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <fcntl.h> 25bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <pthread.h> 26bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <stdio.h> 27bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <stdlib.h> 28bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <string.h> 29bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <sys/ioctl.h> 30bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <sys/stat.h> 31bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <sys/types.h> 32bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <unistd.h> 33bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 34bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <mach/clock.h> 35bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <mach/clock_types.h> 36bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <mach/mach_host.h> 37bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 38bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <mach/mach_port.h> 39bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <IOKit/IOCFBundle.h> 40bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <IOKit/usb/IOUSBLib.h> 41bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include <IOKit/IOCFPlugIn.h> 42bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 43bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#include "darwin_usb.h" 44bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 45bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic mach_port_t libusb_darwin_mp = 0; /* master port */ 46bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic CFRunLoopRef libusb_darwin_acfl = NULL; /* async cf loop */ 47bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int initCount = 0; 48bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 49bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev/* async event thread */ 50bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic pthread_t libusb_darwin_at; 51bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 52bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian); 53bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface); 54bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface); 55bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_reset_device(struct libusb_device_handle *dev_handle); 56bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0); 57bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 58bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic const char *darwin_error_str (int result) { 59bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev switch (result) { 60bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnSuccess: 61bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return "no error"; 62bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnNotOpen: 63bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return "device not opened for exclusive access"; 64bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnNoDevice: 65bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return "no connection to an IOService"; 66bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOUSBNoAsyncPortErr: 67bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return "no async port has been opened for interface"; 68bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnExclusiveAccess: 69bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return "another process has device opened for exclusive access"; 70bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOUSBPipeStalled: 71bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return "pipe is stalled"; 72bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnError: 73bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return "could not establish a connection to the Darwin kernel"; 74bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOUSBTransactionTimeout: 75bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return "transaction timed out"; 76bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnBadArgument: 77bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return "invalid argument"; 78bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnAborted: 79bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return "transaction aborted"; 80bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnNotResponding: 81bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return "device not responding"; 82bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnOverrun: 83bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return "data overrun"; 84bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnCannotWire: 85bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return "physical memory can not be wired down"; 86bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev default: 87bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return "unknown error"; 88bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 89bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 90bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 91bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_to_libusb (int result) { 92bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev switch (result) { 93bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnSuccess: 94bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_SUCCESS; 95bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnNotOpen: 96bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnNoDevice: 97bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NO_DEVICE; 98bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnExclusiveAccess: 99bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_ACCESS; 100bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOUSBPipeStalled: 101bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_PIPE; 102bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnBadArgument: 103bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_INVALID_PARAM; 104bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOUSBTransactionTimeout: 105bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_TIMEOUT; 106bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnNotResponding: 107bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnAborted: 108bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnError: 109bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOUSBNoAsyncPortErr: 110bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev default: 111bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_OTHER; 112bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 113bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 114bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 115bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 116bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, uint8_t *pipep, uint8_t *ifcp) { 117bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; 118bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 119bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* current interface */ 120bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct __darwin_interface *cInterface; 121bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 122bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int8_t i, iface; 123bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 124bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (HANDLE_CTX(dev_handle), "converting ep address 0x%02x to pipeRef and interface", ep); 125bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 126bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (iface = 0 ; iface < USB_MAXINTERFACES ; iface++) { 127bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev cInterface = &priv->interfaces[iface]; 128bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 129bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (dev_handle->claimed_interfaces & (1 << iface)) { 130bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 0 ; i < cInterface->num_endpoints ; i++) { 131bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (cInterface->endpoint_addrs[i] == ep) { 132bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev *pipep = i + 1; 133bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev *ifcp = iface; 134bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (HANDLE_CTX(dev_handle), "pipe %d on interface %d matches", *pipep, *ifcp); 135bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 136bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 137bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 138bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 139bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 140bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 141bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* No pipe found with the correct endpoint address */ 142bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_warn (HANDLE_CTX(dev_handle), "no pipeRef found with endpoint address 0x%02x.", ep); 143bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 144bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return -1; 145bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 146bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 147bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int usb_setup_device_iterator (io_iterator_t *deviceIterator) { 148bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return IOServiceGetMatchingServices(libusb_darwin_mp, IOServiceMatching(kIOUSBDeviceClassName), deviceIterator); 149bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 150bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 151bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic usb_device_t **usb_get_next_device (io_iterator_t deviceIterator, UInt32 *locationp) { 152bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev io_cf_plugin_ref_t *plugInInterface = NULL; 153bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usb_device_t **device; 154bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev io_service_t usbDevice; 155bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev long result; 156bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev SInt32 score; 157bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 158bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!IOIteratorIsValid (deviceIterator)) 159bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return NULL; 160bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 161bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 162bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while ((usbDevice = IOIteratorNext(deviceIterator))) { 163bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev result = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, 164bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kIOCFPlugInInterfaceID, &plugInInterface, 165bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev &score); 166bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kIOReturnSuccess == result && plugInInterface) 167bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 168bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 169bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_dbg ("libusb/darwin.c usb_get_next_device: could not set up plugin for service: %s\n", darwin_error_str (result)); 170bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 171bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 172bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!usbDevice) 173bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return NULL; 174bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 175bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (void)IOObjectRelease(usbDevice); 176bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (void)(*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID), 177bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (LPVOID)&device); 178bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 179bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*plugInInterface)->Stop(plugInInterface); 180bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IODestroyPlugInInterface (plugInInterface); 181bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 182bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*(device))->GetLocationID(device, locationp); 183bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 184bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return device; 185bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 186bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 187bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic kern_return_t darwin_get_device (uint32_t dev_location, usb_device_t ***darwin_device) { 188bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kern_return_t kresult; 189bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev UInt32 location; 190bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev io_iterator_t deviceIterator; 191bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 192bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = usb_setup_device_iterator (&deviceIterator); 193bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) 194bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return kresult; 195bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 196bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* This port of libusb uses locations to keep track of devices. */ 197bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while ((*darwin_device = usb_get_next_device (deviceIterator, &location)) != NULL) { 198bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (location == dev_location) 199bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 200bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 201bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (**darwin_device)->Release(*darwin_device); 202bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 203bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 204bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOObjectRelease (deviceIterator); 205bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 206bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!(*darwin_device)) 207bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return kIOReturnNoDevice; 208bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 209bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return kIOReturnSuccess; 210bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 211bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 212bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 213bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 214bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) { 215bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_context *ctx = (struct libusb_context *)ptr; 216bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_device_handle *handle; 217bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *dpriv; 218bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_handle_priv *priv; 219bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 220bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev io_service_t device; 221bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev long location; 222bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFTypeRef locationCF; 223bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev UInt32 message; 224bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 225bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (ctx, "a device has been detached"); 226bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 227bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while ((device = IOIteratorNext (rem_devices)) != 0) { 228bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* get the location from the i/o registry */ 229bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev locationCF = IORegistryEntryCreateCFProperty (device, CFSTR(kUSBDevicePropertyLocationID), kCFAllocatorDefault, 0); 230bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 231bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFNumberGetValue(locationCF, kCFNumberLongType, &location); 232bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRelease (locationCF); 233bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOObjectRelease (device); 234bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 235bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_mutex_lock(&ctx->open_devs_lock); 236bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev list_for_each_entry(handle, &ctx->open_devs, list) { 237bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev dpriv = (struct darwin_device_priv *)handle->dev->os_priv; 238bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 239bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* the device may have been opened several times. write to each handle's event descriptor */ 240bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (dpriv->location == location && handle->os_priv) { 241bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev priv = (struct darwin_device_handle_priv *)handle->os_priv; 242bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 243bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev message = MESSAGE_DEVICE_GONE; 244bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev write (priv->fds[1], &message, sizeof (message)); 245bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 246bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 247bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 248bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_mutex_unlock(&ctx->open_devs_lock); 249bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 250bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 251bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 252bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void darwin_clear_iterator (io_iterator_t iter) { 253bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev io_service_t device; 254bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 255bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while ((device = IOIteratorNext (iter)) != 0) 256bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOObjectRelease (device); 257bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 258bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 259bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void *event_thread_main (void *arg0) { 260bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 261bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_context *ctx = (struct libusb_context *)arg0; 262bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 263bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* hotplug (device removal) source */ 264bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRunLoopSourceRef libusb_notification_cfsource; 265bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev io_notification_port_t libusb_notification_port; 266bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev io_iterator_t libusb_rem_device_iterator; 267bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 268bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (ctx, "creating hotplug event source"); 269bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 270bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRetain (CFRunLoopGetCurrent ()); 271bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 272bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* add the notification port to the run loop */ 273bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_notification_port = IONotificationPortCreate (libusb_darwin_mp); 274bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_notification_cfsource = IONotificationPortGetRunLoopSource (libusb_notification_port); 275bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRunLoopAddSource(CFRunLoopGetCurrent (), libusb_notification_cfsource, kCFRunLoopDefaultMode); 276bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 277bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* create notifications for removed devices */ 278bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = IOServiceAddMatchingNotification (libusb_notification_port, kIOTerminatedNotification, 279bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOServiceMatching(kIOUSBDeviceClassName), 280bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (IOServiceMatchingCallback)darwin_devices_detached, 281bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (void *)ctx, &libusb_rem_device_iterator); 282bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 283bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) { 284bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult)); 285bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 286bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_exit ((void *)kresult); 287bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 288bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 289bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* arm notifiers */ 290bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev darwin_clear_iterator (libusb_rem_device_iterator); 291bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 292bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* let the main thread know about the async runloop */ 293bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_darwin_acfl = CFRunLoopGetCurrent (); 294bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 295bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (ctx, "libopenusb/darwin.c event_thread_main: thread ready to receive events"); 296bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 297bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* run the runloop */ 298bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRunLoopRun(); 299bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 300bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (ctx, "libopenusb/darwin.c event_thread_main: thread exiting"); 301bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 302bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* delete notification port */ 303bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRunLoopSourceInvalidate (libusb_notification_cfsource); 304bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IONotificationPortDestroy (libusb_notification_port); 305bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 306bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRelease (CFRunLoopGetCurrent ()); 307bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 308bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_darwin_acfl = NULL; 309bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 310bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_exit (0); 311bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 312bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 313bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_init(struct libusb_context *ctx) { 314bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 315bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 316bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!(initCount++)) { 317bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Create the master port for talking to IOKit */ 318bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!libusb_darwin_mp) { 319bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = IOMasterPort (MACH_PORT_NULL, &libusb_darwin_mp); 320bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 321bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess || !libusb_darwin_mp) 322bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 323bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 324bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 325bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_create (&libusb_darwin_at, NULL, event_thread_main, (void *)ctx); 326bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 327bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while (!libusb_darwin_acfl) 328bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usleep (10); 329bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 330bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 331bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 332bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 333bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 334bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void darwin_exit (void) { 335bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!(--initCount)) { 336bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev void *ret; 337bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 338bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* stop the async runloop */ 339bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRunLoopStop (libusb_darwin_acfl); 340bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_join (libusb_darwin_at, &ret); 341bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 342bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (libusb_darwin_mp) 343bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev mach_port_deallocate(mach_task_self(), libusb_darwin_mp); 344bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 345bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_darwin_mp = 0; 346bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 347bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 348bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 349bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian) { 350bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv; 351bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 352bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* return cached copy */ 353bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev memmove (buffer, &(priv->dev_descriptor), DEVICE_DESC_LENGTH); 354bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 355bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev *host_endian = 0; 356bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 357bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 358bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 359bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 360bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int get_configuration_index (struct libusb_device *dev, int config_value) { 361bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv; 362bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev UInt8 i, numConfig; 363bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOUSBConfigurationDescriptorPtr desc; 364bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 365bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 366bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* is there a simpler way to determine the index? */ 367bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(priv->device))->GetNumberOfConfigurations (priv->device, &numConfig); 368bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) 369bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 370bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 371bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 0 ; i < numConfig ; i++) { 372bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*(priv->device))->GetConfigurationDescriptorPtr (priv->device, i, &desc); 373bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 374bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (libusb_le16_to_cpu (desc->bConfigurationValue) == config_value) 375bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return i; 376bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 377bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 378bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* configuration not found */ 379bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_OTHER; 380bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 381bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 382bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) { 383bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv; 384bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev UInt8 config_value; 385bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int config_index; 386bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 387bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 388bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(priv->device))->GetConfiguration (priv->device, &config_value); 389bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) 390bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 391bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 392bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev config_index = get_configuration_index (dev, config_value); 393bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (config_index < 0) 394bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return config_index; 395bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 396bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_get_config_descriptor (dev, config_index, buffer, len, host_endian); 397bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 398bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 399bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) { 400bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv; 401bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOUSBConfigurationDescriptorPtr desc; 402bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 403bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usb_device_t **device = NULL; 404bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 405bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!priv) 406bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_OTHER; 407bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 408bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!priv->device) { 409bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = darwin_get_device (priv->location, &device); 410bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult || !device) { 411bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (DEVICE_CTX (dev), "could not find device: %s", darwin_error_str (kresult)); 412bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 413bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 414bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 415bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 416bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* don't have to open the device to get a config descriptor */ 417bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } else 418bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev device = priv->device; 419bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 420bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*device)->GetConfigurationDescriptorPtr (device, config_index, &desc); 421bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult == kIOReturnSuccess) { 422bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* copy descriptor */ 423bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (libusb_le16_to_cpu(desc->wTotalLength) < len) 424bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev len = libusb_le16_to_cpu(desc->wTotalLength); 425bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 426bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev memmove (buffer, desc, len); 427bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 428bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* GetConfigurationDescriptorPtr returns the descriptor in USB bus order */ 429bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev *host_endian = 0; 430bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 431bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 432bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!priv->device) 433bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*device)->Release (device); 434bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 435bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 436bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 437bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 438bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int process_new_device (struct libusb_context *ctx, usb_device_t **device, UInt32 locationID, struct discovered_devs **_discdevs) { 439bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *priv; 440bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_device *dev; 441bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct discovered_devs *discdevs; 442bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev UInt16 address, idVendor, idProduct; 443bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev UInt8 bDeviceClass, bDeviceSubClass; 444bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOUSBDevRequest req; 445bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int ret = 0, need_unref = 0; 446bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 447bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev do { 448bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev dev = usbi_get_device_by_session_id(ctx, locationID); 449bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!dev) { 450bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (ctx, "allocating new device for location 0x%08x", locationID); 451bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev dev = usbi_alloc_device(ctx, locationID); 452bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev need_unref = 1; 453bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } else 454bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (ctx, "using existing device for location 0x%08x", locationID); 455bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 456bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!dev) { 457bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ret = LIBUSB_ERROR_NO_MEM; 458bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 459bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 460bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 461bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev priv = (struct darwin_device_priv *)dev->os_priv; 462bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 463bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Set up request for device descriptor */ 464bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); 465bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev req.bRequest = kUSBRqGetDescriptor; 466bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev req.wValue = kUSBDeviceDesc << 8; 467bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev req.wIndex = 0; 468bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev req.wLength = sizeof(IOUSBDeviceDescriptor); 469bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev req.pData = &(priv->dev_descriptor); 470bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 471bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*(device))->GetDeviceAddress (device, (USBDeviceAddress *)&address); 472bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*(device))->GetDeviceProduct (device, &idProduct); 473bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*(device))->GetDeviceVendor (device, &idVendor); 474bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*(device))->GetDeviceClass (device, &bDeviceClass); 475bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*(device))->GetDeviceSubClass (device, &bDeviceSubClass); 476bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 477bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /**** retrieve device descriptors ****/ 478bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* device must be open for DeviceRequest */ 479bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*device)->USBDeviceOpen(device); 480bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 481bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ret = (*(device))->DeviceRequest (device, &req); 482bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (ret != kIOReturnSuccess) { 483bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int try_unsuspend = 1; 484bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#if DeviceVersion >= 320 485bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev UInt32 info; 486bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 487bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* device may be suspended. unsuspend it and try again */ 488bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* IOUSBFamily 320+ provides a way to detect device suspension but earlier versions do not */ 489bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (void)(*device)->GetUSBDeviceInformation (device, &info); 490bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 491bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev try_unsuspend = info & (1 << kUSBInformationDeviceIsSuspendedBit); 492bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#endif 493bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 494bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (try_unsuspend) { 495bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* resume the device */ 496bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (void)(*device)->USBDeviceSuspend (device, 0); 497bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 498bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ret = (*(device))->DeviceRequest (device, &req); 499bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 500bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* resuspend the device */ 501bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (void)(*device)->USBDeviceSuspend (device, 1); 502bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 503bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 504bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 505bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*device)->USBDeviceClose (device); 506bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 507bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (ret != kIOReturnSuccess) { 508bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_warn (ctx, "could not retrieve device descriptor: %s. skipping device", darwin_error_str (ret)); 509bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ret = -1; 510bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 511bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 512bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 513bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /**** end: retrieve device descriptors ****/ 514bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 515bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices. */ 516bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (libusb_le16_to_cpu (priv->dev_descriptor.idProduct) != idProduct) { 517bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* not a valid device */ 518bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_warn (ctx, "idProduct from iokit (%04x) does not match idProduct in descriptor (%04x). skipping device", 519bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev idProduct, libusb_le16_to_cpu (priv->dev_descriptor.idProduct)); 520bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ret = -1; 521bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 522bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 523bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 524bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev dev->bus_number = locationID >> 24; 525bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev dev->device_address = address; 526bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 527bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* save our location, we'll need this later */ 528bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev priv->location = locationID; 529bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev snprintf(priv->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", address, idVendor, idProduct, bDeviceClass, bDeviceSubClass); 530bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 531bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ret = usbi_sanitize_device (dev); 532bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (ret < 0) 533bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 534bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 535bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* append the device to the list of discovered devices */ 536bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev discdevs = discovered_devs_append(*_discdevs, dev); 537bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!discdevs) { 538bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ret = LIBUSB_ERROR_NO_MEM; 539bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 540bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 541bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 542bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev *_discdevs = discdevs; 543bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 544bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (ctx, "found device with address %d at %s", dev->device_address, priv->sys_path); 545bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } while (0); 546bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 547bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (need_unref) 548bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_unref_device(dev); 549bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 550bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return ret; 551bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 552bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 553bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs) { 554bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev io_iterator_t deviceIterator; 555bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usb_device_t **device; 556bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kern_return_t kresult; 557bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev UInt32 location; 558bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 559bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!libusb_darwin_mp) 560bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_INVALID_PARAM; 561bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 562bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = usb_setup_device_iterator (&deviceIterator); 563bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) 564bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 565bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 566bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) { 567bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (void) process_new_device (ctx, device, location, _discdevs); 568bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 569bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*(device))->Release(device); 570bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 571bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 572bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOObjectRelease(deviceIterator); 573bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 574bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 575bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 576bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 577bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_open (struct libusb_device_handle *dev_handle) { 578bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; 579bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; 580bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usb_device_t **darwin_device; 581bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 582bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 583bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (0 == dpriv->open_count) { 584bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = darwin_get_device (dpriv->location, &darwin_device); 585bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) { 586bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "could not find device: %s", darwin_error_str (kresult)); 587bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 588bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 589bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 590bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev dpriv->device = darwin_device; 591bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 592bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* try to open the device */ 593bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(dpriv->device))->USBDeviceOpenSeize (dpriv->device); 594bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 595bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) { 596bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "USBDeviceOpen: %s", darwin_error_str(kresult)); 597bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 598bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev switch (kresult) { 599bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnExclusiveAccess: 600bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* it is possible to perform some actions on a device that is not open so do not return an error */ 601bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev priv->is_open = 0; 602bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 603bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 604bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev default: 605bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*(dpriv->device))->Release (dpriv->device); 606bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev dpriv->device = NULL; 607bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 608bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 609bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } else { 610bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev priv->is_open = 1; 611bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 612bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* create async event source */ 613bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(dpriv->device))->CreateDeviceAsyncEventSource (dpriv->device, &priv->cfSource); 614bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 615bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRetain (libusb_darwin_acfl); 616bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 617bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* add the cfSource to the aync run loop */ 618bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRunLoopAddSource(libusb_darwin_acfl, priv->cfSource, kCFRunLoopCommonModes); 619bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 620bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 621bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 622bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* device opened successfully */ 623bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev dpriv->open_count++; 624bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 625bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* create a file descriptor for notifications */ 626bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pipe (priv->fds); 627bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 628bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* set the pipe to be non-blocking */ 629bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev fcntl (priv->fds[1], F_SETFD, O_NONBLOCK); 630bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 631bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_add_pollfd(HANDLE_CTX(dev_handle), priv->fds[0], POLLIN); 632bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 633bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (HANDLE_CTX (dev_handle), "device open for access"); 634bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 635bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 636bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 637bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 638bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void darwin_close (struct libusb_device_handle *dev_handle) { 639bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; 640bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; 641bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 642bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int i; 643bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 644bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (dpriv->open_count == 0) { 645bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* something is probably very wrong if this is the case */ 646bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "Close called on a device that was not open!\n"); 647bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return; 648bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 649bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 650bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev dpriv->open_count--; 651bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 652bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* make sure all interfaces are released */ 653bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 0 ; i < USB_MAXINTERFACES ; i++) 654bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (dev_handle->claimed_interfaces & (1 << i)) 655bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev libusb_release_interface (dev_handle, i); 656bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 657bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (0 == dpriv->open_count) { 658bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (priv->is_open) { 659bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* delete the device's async event source */ 660bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (priv->cfSource) { 661bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRunLoopRemoveSource (libusb_darwin_acfl, priv->cfSource, kCFRunLoopDefaultMode); 662bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRelease (priv->cfSource); 663bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 664bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 665bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* close the device */ 666bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(dpriv->device))->USBDeviceClose(dpriv->device); 667bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) { 668bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Log the fact that we had a problem closing the file, however failing a 669bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * close isn't really an error, so return success anyway */ 670bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "USBDeviceClose: %s", darwin_error_str(kresult)); 671bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 672bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 673bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 674bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(dpriv->device))->Release(dpriv->device); 675bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) { 676bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Log the fact that we had a problem closing the file, however failing a 677bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev * close isn't really an error, so return success anyway */ 678bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult)); 679bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 680bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 681bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev dpriv->device = NULL; 682bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 683bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 684bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* file descriptors are maintained per-instance */ 685bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_remove_pollfd (HANDLE_CTX (dev_handle), priv->fds[0]); 686bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev close (priv->fds[1]); 687bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev close (priv->fds[0]); 688bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 689bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev priv->fds[0] = priv->fds[1] = -1; 690bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 691bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 692bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_get_configuration(struct libusb_device_handle *dev_handle, int *config) { 693bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; 694bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev UInt8 configNum; 695bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 696bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 697bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(dpriv->device))->GetConfiguration (dpriv->device, &configNum); 698bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) 699bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 700bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 701bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev *config = (int) configNum; 702bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 703bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 704bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 705bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 706bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_set_configuration(struct libusb_device_handle *dev_handle, int config) { 707bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; 708bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 709bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int i; 710bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 711bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Setting configuration will invalidate the interface, so we need 712bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev to reclaim it. First, dispose of existing interfaces, if any. */ 713bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 0 ; i < USB_MAXINTERFACES ; i++) 714bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (dev_handle->claimed_interfaces & (1 << i)) 715bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev darwin_release_interface (dev_handle, i); 716bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 717bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(dpriv->device))->SetConfiguration (dpriv->device, config); 718bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) 719bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 720bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 721bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Reclaim any interfaces. */ 722bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 0 ; i < USB_MAXINTERFACES ; i++) 723bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (dev_handle->claimed_interfaces & (1 << i)) 724bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev darwin_claim_interface (dev_handle, i); 725bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 726bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 727bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 728bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 729bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_get_interface (usb_device_t **darwin_device, uint8_t ifc, io_service_t *usbInterfacep) { 730bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOUSBFindInterfaceRequest request; 731bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint8_t current_interface; 732bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kern_return_t kresult; 733bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev io_iterator_t interface_iterator; 734bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 735bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev *usbInterfacep = IO_OBJECT_NULL; 736bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 737bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Setup the Interface Request */ 738bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request.bInterfaceClass = kIOUSBFindInterfaceDontCare; 739bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; 740bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; 741bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev request.bAlternateSetting = kIOUSBFindInterfaceDontCare; 742bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 743bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator); 744bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) 745bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return kresult; 746bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 747bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for ( current_interface = 0 ; current_interface <= ifc ; current_interface++ ) 748bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev *usbInterfacep = IOIteratorNext(interface_iterator); 749bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 750bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* done with the interface iterator */ 751bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOObjectRelease(interface_iterator); 752bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 753bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 754bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 755bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 756bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int get_endpoints (struct libusb_device_handle *dev_handle, int iface) { 757bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; 758bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 759bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* current interface */ 760bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct __darwin_interface *cInterface = &priv->interfaces[iface]; 761bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 762bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kern_return_t kresult; 763bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 764bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev u_int8_t numep, direction, number; 765bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev u_int8_t dont_care1, dont_care3; 766bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev u_int16_t dont_care2; 767bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int i; 768bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 769bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (HANDLE_CTX (dev_handle), "building table of endpoints."); 770bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 771bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* retrieve the total number of endpoints on this interface */ 772bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(cInterface->interface))->GetNumEndpoints(cInterface->interface, &numep); 773bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) { 774bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "can't get number of endpoints for interface: %s", darwin_error_str(kresult)); 775bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 776bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 777bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 778bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* iterate through pipe references */ 779bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 1 ; i <= numep ; i++) { 780bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(cInterface->interface))->GetPipeProperties(cInterface->interface, i, &direction, &number, &dont_care1, 781bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev &dont_care2, &dont_care3); 782bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 783bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) { 784bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "error getting pipe information for pipe %d: %s", i, darwin_error_str(kresult)); 785bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 786bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 787bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 788bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 789bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (HANDLE_CTX (dev_handle), "interface: %i pipe %i: dir: %i number: %i", iface, i, direction, number); 790bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 791bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev cInterface->endpoint_addrs[i - 1] = ((direction << 7 & LIBUSB_ENDPOINT_DIR_MASK) | (number & LIBUSB_ENDPOINT_ADDRESS_MASK)); 792bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 793bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 794bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev cInterface->num_endpoints = numep; 795bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 796bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 797bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 798bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 799bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface) { 800bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; 801bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; 802bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev io_service_t usbInterface = IO_OBJECT_NULL; 803bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 804bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOCFPlugInInterface **plugInInterface = NULL; 805bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev SInt32 score; 806bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint8_t new_config; 807bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 808bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* current interface */ 809bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct __darwin_interface *cInterface = &priv->interfaces[iface]; 810bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 811bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = darwin_get_interface (dpriv->device, iface, &usbInterface); 812bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) 813bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 814bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 815bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* make sure we have an interface */ 816bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!usbInterface) { 817bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev u_int8_t nConfig; /* Index of configuration to use */ 818bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOUSBConfigurationDescriptorPtr configDesc; /* to describe which configuration to select */ 819bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Only a composite class device with no vendor-specific driver will 820bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev be configured. Otherwise, we need to do it ourselves, or there 821bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev will be no interfaces for the device. */ 822bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 823bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (HANDLE_CTX (dev_handle), "no interface found; selecting configuration" ); 824bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 825bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(dpriv->device))->GetNumberOfConfigurations (dpriv->device, &nConfig); 826bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) { 827bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "GetNumberOfConfigurations: %s", darwin_error_str(kresult)); 828bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb(kresult); 829bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 830bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 831bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (nConfig < 1) { 832bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "GetNumberOfConfigurations: no configurations"); 833bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_OTHER; 834bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 835bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 836bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (HANDLE_CTX (dev_handle), "device has %d configuration%s. using the first", 837bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (int)nConfig, (nConfig > 1 ? "s" : "") ); 838bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 839bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Always use the first configuration */ 840bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(dpriv->device))->GetConfigurationDescriptorPtr (dpriv->device, 0, &configDesc); 841bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) { 842bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "GetConfigurationDescriptorPtr: %s", 843bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev darwin_error_str(kresult)); 844bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 845bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev new_config = 1; 846bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } else 847bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev new_config = configDesc->bConfigurationValue; 848bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 849bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (HANDLE_CTX (dev_handle), "new configuration value is %d", new_config); 850bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 851bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* set the configuration */ 852bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = darwin_set_configuration (dev_handle, new_config); 853bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != LIBUSB_SUCCESS) { 854bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "could not set configuration"); 855bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return kresult; 856bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 857bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 858bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = darwin_get_interface (dpriv->device, iface, &usbInterface); 859bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) { 860bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult)); 861bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 862bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 863bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 864bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 865bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!usbInterface) { 866bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "interface not found"); 867bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NOT_FOUND; 868bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 869bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 870bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* get an interface to the device's interface */ 871bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = IOCreatePlugInInterfaceForService (usbInterface, kIOUSBInterfaceUserClientTypeID, 872bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kIOCFPlugInInterfaceID, &plugInInterface, &score); 873bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) { 874bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "IOCreatePlugInInterfaceForService: %s", darwin_error_str(kresult)); 875bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 876bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 877bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 878bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!plugInInterface) { 879bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "plugin interface not found"); 880bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NOT_FOUND; 881bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 882bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 883bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* ignore release error */ 884bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (void)IOObjectRelease (usbInterface); 885bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 886bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Do the actual claim */ 887bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*plugInInterface)->QueryInterface(plugInInterface, 888bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), 889bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (LPVOID)&cInterface->interface); 890bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult || !cInterface->interface) { 891bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "QueryInterface: %s", darwin_error_str(kresult)); 892bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 893bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 894bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 895bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* We no longer need the intermediate plug-in */ 896bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*plugInInterface)->Release(plugInInterface); 897bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 898bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* claim the interface */ 899bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(cInterface->interface))->USBInterfaceOpen(cInterface->interface); 900bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) { 901bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "USBInterfaceOpen: %s", darwin_error_str(kresult)); 902bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 903bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 904bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 905bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* update list of endpoints */ 906bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = get_endpoints (dev_handle, iface); 907bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) { 908bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* this should not happen */ 909bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev darwin_release_interface (dev_handle, iface); 910bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table"); 911bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return kresult; 912bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 913bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 914bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev cInterface->cfSource = NULL; 915bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 916bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* create async event source */ 917bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(cInterface->interface))->CreateInterfaceAsyncEventSource (cInterface->interface, &cInterface->cfSource); 918bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) { 919bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "could not create async event source"); 920bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 921bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* can't continue without an async event source */ 922bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (void)darwin_release_interface (dev_handle, iface); 923bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 924bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 925bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 926bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 927bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* add the cfSource to the async thread's run loop */ 928bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRunLoopAddSource(libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode); 929bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 930bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (HANDLE_CTX (dev_handle), "interface opened"); 931bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 932bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 933bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 934bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 935bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface) { 936bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; 937bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 938bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 939bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* current interface */ 940bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct __darwin_interface *cInterface = &priv->interfaces[iface]; 941bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 942bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Check to see if an interface is open */ 943bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!cInterface->interface) 944bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_SUCCESS; 945bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 946bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* clean up endpoint data */ 947bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev cInterface->num_endpoints = 0; 948bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 949bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* delete the interface's async event source */ 950bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (cInterface->cfSource) { 951bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRunLoopRemoveSource (libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode); 952bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRelease (cInterface->cfSource); 953bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 954bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 955bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(cInterface->interface))->USBInterfaceClose(cInterface->interface); 956bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) 957bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "USBInterfaceClose: %s", darwin_error_str(kresult)); 958bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 959bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(cInterface->interface))->Release(cInterface->interface); 960bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) 961bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult)); 962bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 963bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev cInterface->interface = IO_OBJECT_NULL; 964bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 965bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 966bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 967bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 968bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) { 969bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; 970bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 971bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 972bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* current interface */ 973bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct __darwin_interface *cInterface = &priv->interfaces[iface]; 974bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 975bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!cInterface->interface) 976bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NO_DEVICE; 977bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 978bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(cInterface->interface))->SetAlternateInterface (cInterface->interface, altsetting); 979bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) 980bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev darwin_reset_device (dev_handle); 981bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 982bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* update list of endpoints */ 983bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = get_endpoints (dev_handle, iface); 984bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) { 985bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* this should not happen */ 986bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev darwin_release_interface (dev_handle, iface); 987bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table"); 988bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return kresult; 989bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 990bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 991bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 992bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 993bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 994bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) { 995bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; 996bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 997bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* current interface */ 998bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct __darwin_interface *cInterface; 999bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint8_t pipeRef, iface; 1000bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 1001bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1002bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* determine the interface/endpoint to use */ 1003bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (ep_to_pipeRef (dev_handle, endpoint, &pipeRef, &iface) != 0) { 1004bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "endpoint not found on any open interface"); 1005bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1006bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NOT_FOUND; 1007bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1008bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1009bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev cInterface = &priv->interfaces[iface]; 1010bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1011bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#if (InterfaceVersion < 190) 1012bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(cInterface->interface))->ClearPipeStall(cInterface->interface, pipeRef); 1013bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#else 1014bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* newer versions of darwin support clearing additional bits on the device's endpoint */ 1015bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef); 1016bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#endif 1017bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) 1018bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "ClearPipeStall: %s", darwin_error_str (kresult)); 1019bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1020bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 1021bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1022bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1023bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_reset_device(struct libusb_device_handle *dev_handle) { 1024bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; 1025bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 1026bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1027bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(dpriv->device))->ResetDevice (dpriv->device); 1028bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) 1029bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "ResetDevice: %s", darwin_error_str (kresult)); 1030bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1031bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 1032bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1033bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1034bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle, int interface) { 1035bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; 1036bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev io_service_t usbInterface; 1037bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFTypeRef driver; 1038bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 1039bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1040bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = darwin_get_interface (dpriv->device, interface, &usbInterface); 1041bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) { 1042bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult)); 1043bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1044bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 1045bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1046bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1047bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev driver = IORegistryEntryCreateCFProperty (usbInterface, kIOBundleIdentifierKey, kCFAllocatorDefault, 0); 1048bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOObjectRelease (usbInterface); 1049bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1050bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (driver) { 1051bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRelease (driver); 1052bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1053bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 1; 1054bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1055bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1056bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* no driver */ 1057bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 1058bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1059bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1060bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev/* attaching/detaching kernel drivers is not currently supported (maybe in the future?) */ 1061bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_attach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) { 1062bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NOT_SUPPORTED; 1063bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1064bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1065bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_detach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) { 1066bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NOT_SUPPORTED; 1067bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1068bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1069bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void darwin_destroy_device(struct libusb_device *dev) { 1070bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1071bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1072bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int submit_bulk_transfer(struct usbi_transfer *itransfer) { 1073bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); 1074bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; 1075bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1076bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn ret; 1077bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint8_t is_read; /* 0 = we're reading, 1 = we're writing */ 1078bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint8_t transferType; 1079bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* None of the values below are used in libusb for bulk transfers */ 1080bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint8_t direction, number, interval, pipeRef, iface; 1081bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint16_t maxPacketSize; 1082bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1083bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct __darwin_interface *cInterface; 1084bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1085bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* are we reading or writing? */ 1086bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev is_read = transfer->endpoint & LIBUSB_ENDPOINT_IN; 1087bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1088bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) { 1089bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); 1090bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1091bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NOT_FOUND; 1092bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1093bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1094bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev cInterface = &priv->interfaces[iface]; 1095bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1096bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number, 1097bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev &transferType, &maxPacketSize, &interval); 1098bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1099bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* submit the request */ 1100bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* timeouts are unavailable on interrupt endpoints */ 1101bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (transferType == kUSBInterrupt) { 1102bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (is_read) 1103bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ret = (*(cInterface->interface))->ReadPipeAsync(cInterface->interface, pipeRef, transfer->buffer, 1104bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev transfer->length, darwin_async_io_callback, itransfer); 1105bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev else 1106bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ret = (*(cInterface->interface))->WritePipeAsync(cInterface->interface, pipeRef, transfer->buffer, 1107bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev transfer->length, darwin_async_io_callback, itransfer); 1108bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } else { 1109bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (is_read) 1110bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ret = (*(cInterface->interface))->ReadPipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer, 1111bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev transfer->length, transfer->timeout, transfer->timeout, 1112bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev darwin_async_io_callback, (void *)itransfer); 1113bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev else 1114bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ret = (*(cInterface->interface))->WritePipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer, 1115bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev transfer->length, transfer->timeout, transfer->timeout, 1116bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev darwin_async_io_callback, (void *)itransfer); 1117bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1118bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1119bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (ret) 1120bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (TRANSFER_CTX (transfer), "bulk transfer failed (dir = %s): %s (code = 0x%08x)", is_read ? "In" : "Out", 1121bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev darwin_error_str(ret), ret); 1122bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1123bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (ret); 1124bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1125bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1126bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int submit_iso_transfer(struct usbi_transfer *itransfer) { 1127bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); 1128bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); 1129bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; 1130bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1131bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 1132bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint8_t is_read; /* 0 = we're writing, 1 = we're reading */ 1133bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint8_t pipeRef, iface; 1134bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev UInt64 frame; 1135bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev AbsoluteTime atTime; 1136bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int i; 1137bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1138bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct __darwin_interface *cInterface; 1139bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1140bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* are we reading or writing? */ 1141bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev is_read = transfer->endpoint & LIBUSB_ENDPOINT_IN; 1142bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1143bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* construct an array of IOUSBIsocFrames */ 1144bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tpriv->isoc_framelist = (IOUSBIsocFrame*) calloc (transfer->num_iso_packets, sizeof(IOUSBIsocFrame)); 1145bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!tpriv->isoc_framelist) 1146bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NO_MEM; 1147bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1148bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* copy the frame list from the libusb descriptor (the structures differ only is member order) */ 1149bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 0 ; i < transfer->num_iso_packets ; i++) 1150bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tpriv->isoc_framelist[i].frReqCount = transfer->iso_packet_desc[i].length; 1151bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1152bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* determine the interface/endpoint to use */ 1153bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) { 1154bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); 1155bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1156bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NOT_FOUND; 1157bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1158bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1159bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev cInterface = &priv->interfaces[iface]; 1160bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1161bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* Last but not least we need the bus frame number */ 1162bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(cInterface->interface))->GetBusFrameNumber(cInterface->interface, &frame, &atTime); 1163bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult) { 1164bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (TRANSFER_CTX (transfer), "failed to get bus frame number: %d", kresult); 1165bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free(tpriv->isoc_framelist); 1166bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tpriv->isoc_framelist = NULL; 1167bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1168bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 1169bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1170bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1171bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* schedule for a frame a little in the future */ 1172bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev frame += 2; 1173bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1174bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* submit the request */ 1175bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (is_read) 1176bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(cInterface->interface))->ReadIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame, 1177bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback, 1178bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev itransfer); 1179bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev else 1180bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(cInterface->interface))->WriteIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame, 1181bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback, 1182bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev itransfer); 1183bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1184bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) { 1185bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (TRANSFER_CTX (transfer), "isochronous transfer failed (dir: %s): %s", is_read ? "In" : "Out", 1186bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev darwin_error_str(kresult)); 1187bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free (tpriv->isoc_framelist); 1188bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tpriv->isoc_framelist = NULL; 1189bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1190bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1191bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 1192bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1193bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1194bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int submit_control_transfer(struct usbi_transfer *itransfer) { 1195bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); 1196bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_control_setup *setup = (struct libusb_control_setup *) transfer->buffer; 1197bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *dpriv = (struct darwin_device_priv *)transfer->dev_handle->dev->os_priv; 1198bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); 1199bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1200bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 1201bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1202bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev bzero(&tpriv->req, sizeof(tpriv->req)); 1203bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1204bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* IOUSBDeviceInterface expects the request in cpu endianess */ 1205bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tpriv->req.bmRequestType = setup->bmRequestType; 1206bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tpriv->req.bRequest = setup->bRequest; 1207bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* these values should be in bus order from libusb_fill_control_setup */ 1208bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tpriv->req.wValue = OSSwapLittleToHostInt16 (setup->wValue); 1209bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tpriv->req.wIndex = OSSwapLittleToHostInt16 (setup->wIndex); 1210bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tpriv->req.wLength = OSSwapLittleToHostInt16 (setup->wLength); 1211bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* data is stored after the libusb control block */ 1212bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tpriv->req.pData = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; 1213bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tpriv->req.completionTimeout = transfer->timeout; 1214bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tpriv->req.noDataTimeout = transfer->timeout; 1215bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1216bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* all transfers in libusb-1.0 are async */ 1217bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(dpriv->device))->DeviceRequestAsyncTO(dpriv->device, &(tpriv->req), darwin_async_io_callback, itransfer); 1218bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1219bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kresult != kIOReturnSuccess) 1220bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (TRANSFER_CTX (transfer), "control request failed: %s", darwin_error_str(kresult)); 1221bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1222bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 1223bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1224bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1225bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_submit_transfer(struct usbi_transfer *itransfer) { 1226bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); 1227bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1228bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev switch (transfer->type) { 1229bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case LIBUSB_TRANSFER_TYPE_CONTROL: 1230bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return submit_control_transfer(itransfer); 1231bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case LIBUSB_TRANSFER_TYPE_BULK: 1232bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1233bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return submit_bulk_transfer(itransfer); 1234bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1235bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return submit_iso_transfer(itransfer); 1236bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev default: 1237bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); 1238bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_INVALID_PARAM; 1239bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1240bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1241bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1242bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int cancel_control_transfer(struct usbi_transfer *itransfer) { 1243bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); 1244bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_priv *dpriv = (struct darwin_device_priv *)transfer->dev_handle->dev->os_priv; 1245bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 1246bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1247bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (ITRANSFER_CTX (itransfer), "WARNING: aborting all transactions control pipe"); 1248bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1249bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(dpriv->device))->USBDeviceAbortPipeZero (dpriv->device); 1250bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1251bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 1252bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1253bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1254bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_abort_transfers (struct usbi_transfer *itransfer) { 1255bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); 1256bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; 1257bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct __darwin_interface *cInterface; 1258bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev uint8_t pipeRef, iface; 1259bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 1260bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1261bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) { 1262bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); 1263bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1264bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_NOT_FOUND; 1265bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1266bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1267bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev cInterface = &priv->interfaces[iface]; 1268bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1269bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (ITRANSFER_CTX (itransfer), "WARNING: aborting all transactions on interface %d pipe %d", iface, pipeRef); 1270bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1271bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* abort transactions */ 1272bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev (*(cInterface->interface))->AbortPipe (cInterface->interface, pipeRef); 1273bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1274bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (ITRANSFER_CTX (itransfer), "calling clear pipe stall to clear the data toggle bit"); 1275bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1276bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* clear the data toggle bit */ 1277bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#if (InterfaceVersion < 190) 1278bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(cInterface->interface))->ClearPipeStall(cInterface->interface, pipeRef); 1279bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#else 1280bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* newer versions of darwin support clearing additional bits on the device's endpoint */ 1281bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef); 1282bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev#endif 1283bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1284bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_to_libusb (kresult); 1285bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1286bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1287bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_cancel_transfer(struct usbi_transfer *itransfer) { 1288bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); 1289bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1290bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev switch (transfer->type) { 1291bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case LIBUSB_TRANSFER_TYPE_CONTROL: 1292bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return cancel_control_transfer(itransfer); 1293bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case LIBUSB_TRANSFER_TYPE_BULK: 1294bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1295bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1296bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return darwin_abort_transfers (itransfer); 1297bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev default: 1298bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); 1299bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_INVALID_PARAM; 1300bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1301bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1302bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1303bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void darwin_clear_transfer_priv (struct usbi_transfer *itransfer) { 1304bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); 1305bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); 1306bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1307bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS && tpriv->isoc_framelist) { 1308bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev free (tpriv->isoc_framelist); 1309bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tpriv->isoc_framelist = NULL; 1310bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1311bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1312bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1313bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0) { 1314bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct usbi_transfer *itransfer = (struct usbi_transfer *)refcon; 1315bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); 1316bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; 1317bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev UInt32 message; 1318bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1319bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (ITRANSFER_CTX (itransfer), "an async io operation has completed"); 1320bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1321bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* send a completion message to the device's file descriptor */ 1322bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev message = MESSAGE_ASYNC_IO_COMPLETE; 1323bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev write (priv->fds[1], &message, sizeof (message)); 1324bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev write (priv->fds[1], &itransfer, sizeof (itransfer)); 1325bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev write (priv->fds[1], &result, sizeof (IOReturn)); 1326bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev write (priv->fds[1], &arg0, sizeof (UInt32)); 1327bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1328bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1329bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_transfer_status (struct usbi_transfer *itransfer, kern_return_t result) { 1330bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev switch (result) { 1331bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnSuccess: 1332bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_TRANSFER_COMPLETED; 1333bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnAborted: 1334bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_TRANSFER_CANCELLED; 1335bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOUSBPipeStalled: 1336bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: pipe is stalled"); 1337bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_TRANSFER_STALL; 1338bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOReturnOverrun: 1339bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (ITRANSFER_CTX (itransfer), "transfer error: data overrun", darwin_error_str (result)); 1340bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_TRANSFER_OVERFLOW; 1341bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case kIOUSBTransactionTimeout: 1342bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (ITRANSFER_CTX (itransfer), "transfer error: timed out"); 1343bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_TRANSFER_TIMED_OUT; 1344bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev default: 1345bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (ITRANSFER_CTX (itransfer), "transfer error: %s (value = 0x%08x)", darwin_error_str (result), result); 1346bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_TRANSFER_ERROR; 1347bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1348bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1349bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1350bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic void darwin_handle_callback (struct usbi_transfer *itransfer, kern_return_t result, UInt32 io_size) { 1351bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); 1352bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); 1353bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int isIsoc = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type; 1354bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int isBulk = LIBUSB_TRANSFER_TYPE_BULK == transfer->type; 1355bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int isControl = LIBUSB_TRANSFER_TYPE_CONTROL == transfer->type; 1356bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int isInterrupt = LIBUSB_TRANSFER_TYPE_INTERRUPT == transfer->type; 1357bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int i; 1358bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1359bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!isIsoc && !isBulk && !isControl && !isInterrupt) { 1360bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); 1361bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return; 1362bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1363bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1364bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (ITRANSFER_CTX (itransfer), "handling %s completion with kernel status %d", 1365bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev isControl ? "control" : isBulk ? "bulk" : isIsoc ? "isoc" : "interrupt", result); 1366bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1367bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (kIOReturnSuccess == result) { 1368bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (isIsoc && tpriv->isoc_framelist) { 1369bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* copy isochronous results back */ 1370bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1371bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 0; i < transfer->num_iso_packets ; i++) { 1372bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_iso_packet_descriptor *lib_desc = transfer->iso_packet_desc; 1373bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev lib_desc->status = darwin_to_libusb (tpriv->isoc_framelist[i].frStatus); 1374bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev lib_desc->actual_length = tpriv->isoc_framelist[i].frActCount; 1375bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1376bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } else if (!isIsoc) 1377bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev itransfer->transferred += io_size; 1378bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1379bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1380bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* it is ok to handle cancelled transfers without calling usbi_handle_transfer_cancellation (we catch timeout transfers) */ 1381bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_handle_transfer_completion (itransfer, darwin_transfer_status (itransfer, result)); 1382bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1383bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1384bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int op_handle_events(struct libusb_context *ctx, struct pollfd *fds, nfds_t nfds, int num_ready) { 1385bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct usbi_transfer *itransfer; 1386bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev UInt32 io_size; 1387bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev IOReturn kresult; 1388bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev int i = 0, ret; 1389bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev UInt32 message; 1390bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1391bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_mutex_lock(&ctx->open_devs_lock); 1392bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev for (i = 0; i < nfds && num_ready > 0; i++) { 1393bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct pollfd *pollfd = &fds[i]; 1394bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct libusb_device_handle *handle; 1395bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev struct darwin_device_handle_priv *hpriv = NULL; 1396bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1397bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_info (ctx, "checking fd %i with revents = %x", fds[i], pollfd->revents); 1398bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1399bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!pollfd->revents) 1400bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev continue; 1401bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1402bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev num_ready--; 1403bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev list_for_each_entry(handle, &ctx->open_devs, list) { 1404bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev hpriv = (struct darwin_device_handle_priv *)handle->os_priv; 1405bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (hpriv->fds[0] == pollfd->fd) 1406bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 1407bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1408bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1409bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (!(pollfd->revents & POLLERR)) { 1410bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev ret = read (hpriv->fds[0], &message, sizeof (message)); 1411bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (ret < sizeof (message)) 1412bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev continue; 1413bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } else 1414bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* could not poll the device-- response is to delete the device (this seems a little heavy-handed) */ 1415bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev message = MESSAGE_DEVICE_GONE; 1416bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1417bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev switch (message) { 1418bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case MESSAGE_DEVICE_GONE: 1419bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* remove the device's async port from the runloop */ 1420bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (hpriv->cfSource) { 1421bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev if (libusb_darwin_acfl) 1422bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRunLoopRemoveSource (libusb_darwin_acfl, hpriv->cfSource, kCFRunLoopDefaultMode); 1423bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev CFRelease (hpriv->cfSource); 1424bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev hpriv->cfSource = NULL; 1425bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1426bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1427bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fds[0]); 1428bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_handle_disconnect(handle); 1429bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1430bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* done with this device */ 1431bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev continue; 1432bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case MESSAGE_ASYNC_IO_COMPLETE: 1433bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev read (hpriv->fds[0], &itransfer, sizeof (itransfer)); 1434bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev read (hpriv->fds[0], &kresult, sizeof (IOReturn)); 1435bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev read (hpriv->fds[0], &io_size, sizeof (UInt32)); 1436bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1437bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev darwin_handle_callback (itransfer, kresult, io_size); 1438bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 1439bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev default: 1440bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev usbi_err (ctx, "unknown message received from device pipe"); 1441bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1442bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1443bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1444bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev pthread_mutex_unlock(&ctx->open_devs_lock); 1445bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1446bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 1447bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1448bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1449bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevstatic int darwin_clock_gettime(int clk_id, struct timespec *tp) { 1450bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev mach_timespec_t sys_time; 1451bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev clock_serv_t clock_ref; 1452bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1453bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev switch (clk_id) { 1454bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case USBI_CLOCK_REALTIME: 1455bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* CLOCK_REALTIME represents time since the epoch */ 1456bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clock_ref); 1457bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 1458bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev case USBI_CLOCK_MONOTONIC: 1459bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev /* use system boot time as reference for the monotonic clock */ 1460bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &clock_ref); 1461bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev break; 1462bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev default: 1463bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return LIBUSB_ERROR_INVALID_PARAM; 1464bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev } 1465bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1466bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev clock_get_time (clock_ref, &sys_time); 1467bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1468bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tp->tv_sec = sys_time.tv_sec; 1469bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev tp->tv_nsec = sys_time.tv_nsec; 1470bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1471bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev return 0; 1472bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev} 1473bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1474bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishevconst struct usbi_os_backend darwin_backend = { 1475bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .name = "Darwin", 1476bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .init = darwin_init, 1477bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .exit = darwin_exit, 1478bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .get_device_list = darwin_get_device_list, 1479bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .get_device_descriptor = darwin_get_device_descriptor, 1480bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .get_active_config_descriptor = darwin_get_active_config_descriptor, 1481bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .get_config_descriptor = darwin_get_config_descriptor, 1482bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1483bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .open = darwin_open, 1484bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .close = darwin_close, 1485bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .get_configuration = darwin_get_configuration, 1486bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .set_configuration = darwin_set_configuration, 1487bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .claim_interface = darwin_claim_interface, 1488bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .release_interface = darwin_release_interface, 1489bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1490bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .set_interface_altsetting = darwin_set_interface_altsetting, 1491bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .clear_halt = darwin_clear_halt, 1492bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .reset_device = darwin_reset_device, 1493bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1494bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .kernel_driver_active = darwin_kernel_driver_active, 1495bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .detach_kernel_driver = darwin_detach_kernel_driver, 1496bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .attach_kernel_driver = darwin_attach_kernel_driver, 1497bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1498bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .destroy_device = darwin_destroy_device, 1499bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1500bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .submit_transfer = darwin_submit_transfer, 1501bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .cancel_transfer = darwin_cancel_transfer, 1502bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .clear_transfer_priv = darwin_clear_transfer_priv, 1503bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1504bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .handle_events = op_handle_events, 1505bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1506bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .clock_gettime = darwin_clock_gettime, 1507bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1508bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .device_priv_size = sizeof(struct darwin_device_priv), 1509bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .device_handle_priv_size = sizeof(struct darwin_device_handle_priv), 1510bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .transfer_priv_size = sizeof(struct darwin_transfer_priv), 1511bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev .add_iso_packet_size = 0, 1512bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev}; 1513bda86ae8203fd360c4e87c310498da1e1e4c53a7Yavor Goulishev 1514