#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <mach/mach_port.h>
#include <IOKit/IOCFBundle.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/IOCFPlugIn.h>
#include "usbi.h"
#if defined (kIOUSBInterfaceInterfaceID220)
#define usb_interface_t IOUSBInterfaceInterface220
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
#define InterfaceVersion 220
#elif defined (kIOUSBInterfaceInterfaceID197)
#define usb_interface_t IOUSBInterfaceInterface197
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197
#define InterfaceVersion 197
#elif defined (kIOUSBInterfaceInterfaceID190)
#define usb_interface_t IOUSBInterfaceInterface190
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190
#define InterfaceVersion 190
#elif defined (kIOUSBInterfaceInterfaceID182)
#define usb_interface_t IOUSBInterfaceInterface182
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182
#define InterfaceVersion 182
#else
#warning "libusb being compiled without support for timeout bulk functions! 10.0 and up"
#define usb_interface_t IOUSBInterfaceInterface
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID
#define LIBUSB_NO_TIMEOUT_INTERFACE
#define InterfaceVersion 180
#endif
#if defined (kIOUSBDeviceInterfaceID197)
#define usb_device_t IOUSBDeviceInterface197
#define DeviceInterfaceID kIOUSBDeviceInterfaceID197
#define DeviceVersion 197
#elif defined (kIOUSBDeviceInterfaceID187)
#define usb_device_t IOUSBDeviceInterface187
#define DeviceInterfaceID kIOUSBDeviceInterfaceID187
#define DeviceVersion 187
#elif defined (kIOUSBDeviceInterfaceID182)
#define usb_device_t IOUSBDeviceInterface182
#define DeviceInterfaceID kIOUSBDeviceInterfaceID182
#define DeviceVersion 182
#else
#define usb_device_t IOUSBDeviceInterface
#define DeviceInterfaceID kIOUSBDeviceInterfaceID
#define LIBUSB_NO_TIMEOUT_DEVICE
#define LIBUSB_NO_SEIZE_DEVICE
#define DeviceVersion 180
#endif
typedef IOReturn io_return_t;
typedef IOCFPlugInInterface *io_cf_plugin_ref_t;
typedef SInt32 s_int32_t;
typedef IOReturn (*rw_async_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size,
IOAsyncCallback1 callback, void *refcon);
typedef IOReturn (*rw_async_to_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size,
UInt32 noDataTimeout, UInt32 completionTimeout,
IOAsyncCallback1 callback, void *refcon);
#if !defined(IO_OBJECT_NULL)
#define IO_OBJECT_NULL ((io_object_t)0)
#endif
struct darwin_dev_handle {
usb_device_t **device;
usb_interface_t **interface;
int open;
int num_endpoints;
unsigned char *endpoint_addrs;
};
static IONotificationPortRef gNotifyPort;
static mach_port_t masterPort = MACH_PORT_NULL;
static void darwin_cleanup (void)
{
IONotificationPortDestroy(gNotifyPort);
mach_port_deallocate(mach_task_self(), masterPort);
}
static char *darwin_error_str (int result) {
switch (result) {
case kIOReturnSuccess:
return "no error";
case kIOReturnNotOpen:
return "device not opened for exclusive access";
case kIOReturnNoDevice:
return "no connection to an IOService";
case kIOUSBNoAsyncPortErr:
return "no async port has been opened for interface";
case kIOReturnExclusiveAccess:
return "another process has device opened for exclusive access";
case kIOUSBPipeStalled:
return "pipe is stalled";
case kIOReturnError:
return "could not establish a connection to the Darwin kernel";
case kIOUSBTransactionTimeout:
return "transaction timed out";
case kIOReturnBadArgument:
return "invalid argument";
case kIOReturnAborted:
return "transaction aborted";
case kIOReturnNotResponding:
return "device not responding";
default:
return "unknown error";
}
}
#define LUSBDARWINSTALL (ELAST+1)
static int darwin_to_errno (int result) {
switch (result) {
case kIOReturnSuccess:
return 0;
case kIOReturnNotOpen:
return EBADF;
case kIOReturnNoDevice:
case kIOUSBNoAsyncPortErr:
return ENXIO;
case kIOReturnExclusiveAccess:
return EBUSY;
case kIOUSBPipeStalled:
return LUSBDARWINSTALL;
case kIOReturnBadArgument:
return EINVAL;
case kIOUSBTransactionTimeout:
return ETIMEDOUT;
case kIOReturnNotResponding:
return EIO;
case kIOReturnError:
default:
return 1;
}
}
static int usb_setup_iterator (io_iterator_t *deviceIterator)
{
int result;
CFMutableDictionaryRef matchingDict;
if ((matchingDict = IOServiceMatching(kIOUSBDeviceClassName)) == NULL) {
darwin_cleanup ();
USB_ERROR_STR(-1, "libusb/darwin.c usb_setup_iterator: Could not create a matching dictionary.\n");
}
result = IOServiceGetMatchingServices(masterPort, matchingDict, deviceIterator);
matchingDict = NULL;
if (result != kIOReturnSuccess)
USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_setup_iterator: IOServiceGetMatchingServices: %s\n",
darwin_error_str(result));
return 0;
}
static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator, UInt32 *locationp)
{
io_cf_plugin_ref_t *plugInInterface = NULL;
usb_device_t **device;
io_service_t usbDevice;
long result; int32_t score;
if (!IOIteratorIsValid (deviceIterator) || !(usbDevice = IOIteratorNext(deviceIterator)))
return NULL;
result = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID,
kIOCFPlugInInterfaceID, &plugInInterface,
&score);
result = IOObjectRelease(usbDevice);
if (result || !plugInInterface)
return NULL;
(*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID),
(LPVOID)&device);
(*plugInInterface)->Stop(plugInInterface);
IODestroyPlugInInterface (plugInInterface);
plugInInterface = NULL;
(*(device))->GetLocationID(device, locationp);
return device;
}
int usb_os_open(usb_dev_handle *dev)
{
struct darwin_dev_handle *device;
io_return_t result;
io_iterator_t deviceIterator;
usb_device_t **darwin_device;
UInt32 location = *((UInt32 *)dev->device->dev);
UInt32 dlocation;
if (!dev)
USB_ERROR(-ENXIO);
if (masterPort == MACH_PORT_NULL)
USB_ERROR(-EINVAL);
device = calloc(1, sizeof(struct darwin_dev_handle));
if (!device)
USB_ERROR(-ENOMEM);
if (usb_debug > 3)
fprintf(stderr, "usb_os_open: %04x:%04x\n",
dev->device->descriptor.idVendor,
dev->device->descriptor.idProduct);
if ((result = usb_setup_iterator (&deviceIterator)) < 0)
return result;
while ((darwin_device = usb_get_next_device (deviceIterator, &dlocation)) != NULL) {
if (dlocation == location)
break;
(*darwin_device)->Release(darwin_device);
}
IOObjectRelease(deviceIterator);
device->device = darwin_device;
if (device->device == NULL)
USB_ERROR_STR (-ENOENT, "usb_os_open: %s\n", "Device not found!");
#if !defined (LIBUSB_NO_SEIZE_DEVICE)
result = (*(device->device))->USBDeviceOpenSeize (device->device);
#else
result = (*(device->device))->USBDeviceOpen (device->device);
#endif
if (result != kIOReturnSuccess) {
switch (result) {
case kIOReturnExclusiveAccess:
if (usb_debug > 0)
fprintf (stderr, "usb_os_open(USBDeviceOpenSeize): %s\n", darwin_error_str(result));
break;
default:
(*(device->device))->Release (device->device);
USB_ERROR_STR(-darwin_to_errno (result), "usb_os_open(USBDeviceOpenSeize): %s",
darwin_error_str(result));
}
device->open = 0;
} else
device->open = 1;
dev->impl_info = device;
dev->interface = -1;
dev->altsetting = -1;
device->num_endpoints = 0;
device->endpoint_addrs = NULL;
return 0;
}
int usb_os_close(usb_dev_handle *dev)
{
struct darwin_dev_handle *device;
io_return_t result;
if (!dev)
USB_ERROR(-ENXIO);
if ((device = dev->impl_info) == NULL)
USB_ERROR(-ENOENT);
usb_release_interface(dev, dev->interface);
if (usb_debug > 3)
fprintf(stderr, "usb_os_close: %04x:%04x\n",
dev->device->descriptor.idVendor,
dev->device->descriptor.idProduct);
if (device->open == 1)
result = (*(device->device))->USBDeviceClose(device->device);
else
result = kIOReturnSuccess;
(*(device->device))->Release(device->device);
if (result != kIOReturnSuccess)
USB_ERROR_STR(-darwin_to_errno(result), "usb_os_close(USBDeviceClose): %s", darwin_error_str(result));
free (device);
return 0;
}
static int get_endpoints (struct darwin_dev_handle *device)
{
io_return_t ret;
u_int8_t numep, direction, number;
u_int8_t dont_care1, dont_care3;
u_int16_t dont_care2;
int i;
if (device == NULL || device->interface == NULL)
return -EINVAL;
if (usb_debug > 1)
fprintf(stderr, "libusb/darwin.c get_endpoints: building table of endpoints.\n");
ret = (*(device->interface))->GetNumEndpoints(device->interface, &numep);
if ( ret ) {
if ( usb_debug > 1 )
fprintf ( stderr, "get_endpoints: interface is %p\n", device->interface );
USB_ERROR_STR ( -ret, "get_endpoints: can't get number of endpoints for interface" );
}
free (device->endpoint_addrs);
device->endpoint_addrs = calloc (sizeof (unsigned char), numep);
for (i = 1 ; i <= numep ; i++) {
ret = (*(device->interface))->GetPipeProperties(device->interface, i, &direction, &number,
&dont_care1, &dont_care2, &dont_care3);
if (ret != kIOReturnSuccess) {
fprintf (stderr, "get_endpoints: an error occurred getting pipe information on pipe %d\n",
i );
USB_ERROR_STR(-darwin_to_errno(ret), "get_endpoints(GetPipeProperties): %s", darwin_error_str(ret));
}
if (usb_debug > 1)
fprintf (stderr, "get_endpoints: Pipe %i: DIR: %i number: %i\n", i, direction, number);
device->endpoint_addrs[i - 1] = ((direction << 7 & USB_ENDPOINT_DIR_MASK) |
(number & USB_ENDPOINT_ADDRESS_MASK));
}
device->num_endpoints = numep;
if (usb_debug > 1)
fprintf(stderr, "libusb/darwin.c get_endpoints: complete.\n");
return 0;
}
static int claim_interface (usb_dev_handle *dev, int interface)
{
io_iterator_t interface_iterator;
io_service_t usbInterface = IO_OBJECT_NULL;
io_return_t result;
io_cf_plugin_ref_t *plugInInterface = NULL;
IOUSBFindInterfaceRequest request;
struct darwin_dev_handle *device;
SInt32 score;
int current_interface;
device = dev->impl_info;
request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator);
if (result != kIOReturnSuccess)
USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s",
darwin_error_str(result));
for ( current_interface=0 ; current_interface <= interface ; current_interface++ ) {
usbInterface = IOIteratorNext(interface_iterator);
if ( usb_debug > 3 )
fprintf ( stderr, "Interface %d of device is 0x%08x\n",
current_interface, usbInterface );
}
current_interface--;
IOObjectRelease(interface_iterator);
if (!usbInterface) {
u_int8_t nConfig;
IOUSBConfigurationDescriptorPtr configDesc;
if ( usb_debug > 3 )
fprintf ( stderr,"claim_interface: No interface found; selecting configuration\n" );
result = (*(device->device))->GetNumberOfConfigurations ( device->device, &nConfig );
if (result != kIOReturnSuccess)
USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetNumberOfConfigurations): %s",
darwin_error_str(result));
if (nConfig < 1)
USB_ERROR_STR(-ENXIO ,"claim_interface(GetNumberOfConfigurations): no configurations");
else if ( nConfig > 1 && usb_debug > 0 )
fprintf ( stderr, "claim_interface: device has more than one"
" configuration, using the first (warning)\n" );
if ( usb_debug > 3 )
fprintf ( stderr, "claim_interface: device has %d configuration%s\n",
(int)nConfig, (nConfig>1?"s":"") );
result = (*(device->device))->GetConfigurationDescriptorPtr ( (device->device), 0, &configDesc );
if (result != kIOReturnSuccess) {
if (device->open == 1) {
(*(device->device))->USBDeviceClose ( (device->device) );
(*(device->device))->Release ( (device->device) );
}
USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetConfigurationDescriptorPtr): %s",
darwin_error_str(result));
} else if ( usb_debug > 3 )
fprintf ( stderr, "claim_interface: configuration value is %d\n",
configDesc->bConfigurationValue );
if (device->open == 1) {
result = (*(device->device))->SetConfiguration ( (device->device), configDesc->bConfigurationValue );
if (result != kIOReturnSuccess) {
(*(device->device))->USBDeviceClose ( (device->device) );
(*(device->device))->Release ( (device->device) );
USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(SetConfiguration): %s",
darwin_error_str(result));
}
dev->config = configDesc->bConfigurationValue;
}
request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator);
if (result != kIOReturnSuccess)
USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s",
darwin_error_str(result));
for (current_interface = 0 ; current_interface <= interface ; current_interface++) {
usbInterface = IOIteratorNext(interface_iterator);
if ( usb_debug > 3 )
fprintf ( stderr, "claim_interface: Interface %d of device is 0x%08x\n",
current_interface, usbInterface );
}
current_interface--;
IOObjectRelease(interface_iterator);
if (!usbInterface)
USB_ERROR_STR (-ENOENT, "claim_interface: interface iterator returned NULL");
}
result = IOCreatePlugInInterfaceForService(usbInterface,
kIOUSBInterfaceUserClientTypeID,
kIOCFPlugInInterfaceID,
&plugInInterface, &score);
result = IOObjectRelease(usbInterface);
if (result || !plugInInterface)
USB_ERROR(-ENOENT);
result = (*plugInInterface)->QueryInterface(plugInInterface,
CFUUIDGetUUIDBytes(InterfaceInterfaceID),
(LPVOID) &device->interface);
(*plugInInterface)->Stop(plugInInterface);
IODestroyPlugInInterface (plugInInterface);
if (result != kIOReturnSuccess)
USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(QueryInterface): %s",
darwin_error_str(result));
if (!device->interface)
USB_ERROR(-EACCES);
if ( usb_debug > 3 )
fprintf ( stderr, "claim_interface: Interface %d of device from QueryInterface is %p\n",
current_interface, device->interface);
result = (*(device->interface))->USBInterfaceOpen(device->interface);
if (result)
USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(USBInterfaceOpen): %s",
darwin_error_str(result));
result = get_endpoints (device);
if (result) {
usb_release_interface (dev, interface);
USB_ERROR_STR ( result, "claim_interface: could not build endpoint table");
}
return 0;
}
int usb_set_configuration (usb_dev_handle *dev, int configuration)
{
struct darwin_dev_handle *device;
io_return_t result;
int interface;
if ( usb_debug > 3 )
fprintf ( stderr, "usb_set_configuration: called for config %x\n", configuration );
if (!dev)
USB_ERROR_STR ( -ENXIO, "usb_set_configuration: called with null device\n" );
if ((device = dev->impl_info) == NULL)
USB_ERROR_STR ( -ENOENT, "usb_set_configuration: device not properly initialized" );
interface = dev->interface;
if ( device->interface )
usb_release_interface(dev, dev->interface);
result = (*(device->device))->SetConfiguration(device->device, configuration);
if (result)
USB_ERROR_STR(-darwin_to_errno(result), "usb_set_configuration(SetConfiguration): %s",
darwin_error_str(result));
if (interface != -1)
result = usb_claim_interface (dev, interface);
dev->config = configuration;
return result;
}
int usb_claim_interface(usb_dev_handle *dev, int interface)
{
struct darwin_dev_handle *device = dev->impl_info;
io_return_t result;
if ( usb_debug > 3 )
fprintf ( stderr, "usb_claim_interface: called for interface %d\n", interface );
if (!device)
USB_ERROR_STR ( -ENOENT, "usb_claim_interface: device is NULL" );
if (!(device->device))
USB_ERROR_STR ( -EINVAL, "usb_claim_interface: device->device is NULL" );
if ( device->interface )
usb_release_interface(dev, dev->interface);
result = claim_interface ( dev, interface );
if ( result )
USB_ERROR_STR ( result, "usb_claim_interface: couldn't claim interface" );
dev->interface = interface;
return 0;
}
int usb_release_interface(usb_dev_handle *dev, int interface)
{
struct darwin_dev_handle *device;
io_return_t result;
if (!dev)
USB_ERROR(-ENXIO);
if ((device = dev->impl_info) == NULL)
USB_ERROR(-ENOENT);
if (!device->interface)
return 0;
result = (*(device->interface))->USBInterfaceClose(device->interface);
if (result != kIOReturnSuccess)
USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(USBInterfaceClose): %s",
darwin_error_str(result));
result = (*(device->interface))->Release(device->interface);
if (result != kIOReturnSuccess)
USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(Release): %s",
darwin_error_str(result));
device->interface = NULL;
free (device->endpoint_addrs);
device->num_endpoints = 0;
device->endpoint_addrs = NULL;
dev->interface = -1;
dev->altsetting = -1;
return 0;
}
int usb_set_altinterface(usb_dev_handle *dev, int alternate)
{
struct darwin_dev_handle *device;
io_return_t result;
if (!dev)
USB_ERROR(-ENXIO);
if ((device = dev->impl_info) == NULL)
USB_ERROR(-ENOENT);
if (!device->interface)
USB_ERROR_STR(-EACCES, "usb_set_altinterface: interface used without being claimed");
result = (*(device->interface))->SetAlternateInterface(device->interface, alternate);
if (result)
USB_ERROR_STR(result, "usb_set_altinterface: could not set alternate interface");
dev->altsetting = alternate;
result = get_endpoints (device);
if (result) {
USB_ERROR_STR ( result, "usb_set_altinterface: could not build endpoint table");
}
return 0;
}
static int ep_to_pipeRef (struct darwin_dev_handle *device, int ep)
{
int i;
if (usb_debug > 1)
fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: Converting ep address to pipeRef.\n");
for (i = 0 ; i < device->num_endpoints ; i++)
if (device->endpoint_addrs[i] == ep)
return i + 1;
if (usb_debug > 1)
fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: No pipeRef found with endpoint address 0x%02x.\n", ep);
return -1;
}
static int usb_bulk_transfer (usb_dev_handle *dev, int ep, char *bytes, u_int32_t size, int timeout, int usb_bt_read)
{
struct darwin_dev_handle *device;
io_return_t result = -1;
int pipeRef;
u_int8_t transferType, direction, number, interval;
u_int16_t maxPacketSize;
if (!dev)
USB_ERROR_STR ( -ENXIO, "libusb/darwin.c usb_bulk_transfer: Called with NULL device" );
if ((device = dev->impl_info) == NULL)
USB_ERROR_STR ( -ENOENT, "libusb/darwin.c usb_bulk_transfer: Device not open" );
if (!device->interface)
USB_ERROR_STR(-EACCES, "libusb/darwin.c usb_bulk_transfer: Interface used before it was opened");
if ((pipeRef = ep_to_pipeRef(device, ep)) < 0)
USB_ERROR_STR ( -EINVAL, "libusb/darwin.c usb_bulk_transfer: Invalid pipe reference" );
(*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number,
&transferType, &maxPacketSize, &interval);
if (usb_debug > 0)
fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n", size, ep);
if (transferType == kUSBInterrupt && usb_debug > 3)
fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n");
#if !defined(LIBUSB_NO_TIMEOUT_INTERFACE)
if ( transferType != kUSBInterrupt) {
if (usb_bt_read != 0)
result = (*(device->interface))->ReadPipeTO (device->interface, pipeRef, bytes, (UInt32 *)&size, timeout, timeout);
else
result = (*(device->interface))->WritePipeTO (device->interface, pipeRef, bytes, size, timeout, timeout);
if (result == kIOUSBTransactionTimeout && (*(device->interface))->GetPipeStatus (device->interface, pipeRef) == kIOUSBPipeStalled)
usb_clear_halt (dev, ep);
} else
#endif
{
if (usb_bt_read != 0)
result = (*(device->interface))->ReadPipe (device->interface, pipeRef, bytes, (UInt32 *)&size);
else
result = (*(device->interface))->WritePipe (device->interface, pipeRef, bytes, size);
}
if (result != kIOReturnSuccess)
USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_bulk_transfer: %s", darwin_error_str (result));
return size;
}
#if 0
struct rw_complete_arg {
UInt32 io_size;
IOReturn result;
CFRunLoopRef cf_loop;
};
static void rw_completed(void *refcon, io_return_t result, void *io_size)
{
struct rw_complete_arg *rw_arg = (struct rw_complete_arg *)refcon;
if (usb_debug > 2)
fprintf(stderr, "io async operation completed: %s, size=%lu, result=0x%08x\n", darwin_error_str(result),
(UInt32)io_size, result);
rw_arg->io_size = (UInt32)io_size;
rw_arg->result = result;
CFRunLoopStop(rw_arg->cf_loop);
}
static int usb_bulk_transfer_async (usb_dev_handle *dev, int ep, char *bytes, int size, int timeout,
rw_async_func_t rw_async, rw_async_to_func_t rw_async_to)
{
struct darwin_dev_handle *device;
io_return_t result = -1;
CFRunLoopSourceRef cfSource;
int pipeRef;
struct rw_complete_arg rw_arg;
u_int8_t transferType;
u_int8_t direction, number, interval;
u_int16_t maxPacketSize;
if (!dev)
USB_ERROR_STR ( -ENXIO, "usb_bulk_transfer: Called with NULL device" );
if ((device = dev->impl_info) == NULL)
USB_ERROR_STR ( -ENOENT, "usb_bulk_transfer: Device not open" );
if (!device->interface)
USB_ERROR_STR(-EACCES, "usb_bulk_transfer: Interface used before it was opened");
if ((pipeRef = ep_to_pipeRef(device, ep)) < 0)
USB_ERROR_STR ( -EINVAL, "usb_bulk_transfer: Invalid pipe reference" );
(*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number,
&transferType, &maxPacketSize, &interval);
bzero((void *)&rw_arg, sizeof(struct rw_complete_arg));
rw_arg.cf_loop = CFRunLoopGetCurrent();
CFRetain (rw_arg.cf_loop);
(*(device->interface))->CreateInterfaceAsyncEventSource(device->interface, &cfSource);
CFRunLoopAddSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode);
if (usb_debug > 0)
fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n",
size, ep);
if (transferType == kUSBInterrupt && usb_debug > 3)
fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n");
if ( transferType != kUSBInterrupt && rw_async_to != NULL)
result = rw_async_to (device->interface, pipeRef, bytes, size, timeout, timeout,
(IOAsyncCallback1)rw_completed, (void *)&rw_arg);
else
result = rw_async (device->interface, pipeRef, bytes, size, (IOAsyncCallback1)rw_completed,
(void *)&rw_arg);
if (result == kIOReturnSuccess) {
if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, (timeout+999)/1000, true) == kCFRunLoopRunTimedOut) {
(*(device->interface))->AbortPipe(device->interface, pipeRef);
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
if (usb_debug)
fprintf(stderr, "usb_bulk_transfer: timed out\n");
}
}
CFRunLoopRemoveSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode);
CFRelease (rw_arg.cf_loop);
if (result != kIOReturnSuccess || (rw_arg.result != kIOReturnSuccess &&
rw_arg.result != kIOReturnAborted) ) {
int error_code;
char *error_str;
if (result == kIOReturnSuccess) {
error_code = darwin_to_errno (rw_arg.result);
error_str = darwin_error_str (rw_arg.result);
} else {
error_code = darwin_to_errno(result);
error_str = darwin_error_str (result);
}
if (transferType != kUSBInterrupt && rw_async_to != NULL)
USB_ERROR_STR(-error_code, "usb_bulk_transfer (w/ Timeout): %s", error_str);
else
USB_ERROR_STR(-error_code, "usb_bulk_transfer (No Timeout): %s", error_str);
}
return rw_arg.io_size;
}
#endif
int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)
{
int result;
if (dev == NULL || dev->impl_info == NULL)
return -EINVAL;
if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, 0)) < 0)
USB_ERROR_STR (result, "usb_bulk_write: An error occured during write (see messages above)");
return result;
}
int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)
{
int result;
if (dev == NULL || dev->impl_info == NULL)
return -EINVAL;
ep |= 0x80;
if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, 1)) < 0)
USB_ERROR_STR (result, "usb_bulk_read: An error occured during read (see messages above)");
return result;
}
int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
int timeout)
{
return usb_bulk_write (dev, ep, bytes, size, timeout);
}
int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
int timeout)
{
return usb_bulk_read (dev, ep, bytes, size, timeout);
}
int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
int value, int index, char *bytes, int size, int timeout)
{
struct darwin_dev_handle *device = dev->impl_info;
io_return_t result;
#if !defined (LIBUSB_NO_TIMEOUT_DEVICE)
IOUSBDevRequestTO urequest;
#else
IOUSBDevRequest urequest;
#endif
if (usb_debug >= 3)
fprintf(stderr, "libusb/darwin.c usb_control_msg (device: %s): %d %d %d %d %p %d %d\n",
dev->device->filename, requesttype, request, value, index, bytes, size, timeout);
bzero(&urequest, sizeof(urequest));
urequest.bmRequestType = requesttype;
urequest.bRequest = request;
urequest.wValue = value;
urequest.wIndex = index;
urequest.wLength = size;
urequest.pData = bytes;
#if !defined (LIBUSB_NO_TIMEOUT_DEVICE)
urequest.completionTimeout = timeout;
urequest.noDataTimeout = timeout;
result = (*(device->device))->DeviceRequestTO(device->device, &urequest);
#else
result = (*(device->device))->DeviceRequest(device->device, &urequest);
#endif
if (result != kIOReturnSuccess)
USB_ERROR_STR(-darwin_to_errno(result), "libusb/darwin.c usb_control_msg(DeviceRequestTO): %s", darwin_error_str(result));
return urequest.wLenDone;
}
int usb_os_find_busses(struct usb_bus **busses)
{
struct usb_bus *fbus = NULL;
io_iterator_t deviceIterator;
io_return_t result;
usb_device_t **device;
UInt32 location;
char buf[20];
int i = 1;
if (masterPort == MACH_PORT_NULL) {
usb_init ();
if (masterPort == MACH_PORT_NULL)
USB_ERROR(-ENOENT);
}
if ((result = usb_setup_iterator (&deviceIterator)) < 0)
return result;
while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) {
struct usb_bus *bus;
if (location & 0x00ffffff)
continue;
bus = calloc(1, sizeof(struct usb_bus));
if (bus == NULL)
USB_ERROR(-ENOMEM);
sprintf(buf, "%03i", i++);
bus->location = location;
strncpy(bus->dirname, buf, sizeof(bus->dirname) - 1);
bus->dirname[sizeof(bus->dirname) - 1] = 0;
LIST_ADD(fbus, bus);
if (usb_debug >= 2)
fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname);
(*(device))->Release(device);
}
IOObjectRelease(deviceIterator);
*busses = fbus;
return 0;
}
int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
{
struct usb_device *fdev = NULL;
io_iterator_t deviceIterator;
io_return_t result;
usb_device_t **device;
u_int16_t address;
UInt32 location;
UInt32 bus_loc = bus->location;
int devnum;
IOUSBDevRequest req;
if (masterPort == MACH_PORT_NULL)
USB_ERROR(-ENOENT);
if ((result = usb_setup_iterator (&deviceIterator)) < 0)
return result;
req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
req.bRequest = kUSBRqGetDescriptor;
req.wValue = kUSBDeviceDesc << 8;
req.wIndex = 0;
req.wLength = sizeof(IOUSBDeviceDescriptor);
devnum = 0;
while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) {
unsigned char device_desc[DEVICE_DESC_LENGTH];
UInt8 bDeviceClass, bDeviceSubClass;
UInt16 idVendor, idProduct;
result = (*(device))->GetDeviceAddress(device, (USBDeviceAddress *)&address);
if (result == kIOReturnSuccess) {
(*(device))->GetDeviceClass (device, &bDeviceClass);
(*(device))->GetDeviceSubClass (device, &bDeviceSubClass);
(*(device))->GetDeviceProduct (device, &idProduct);
(*(device))->GetDeviceVendor (device, &idVendor);
if ((location >> 24) == (bus_loc >> 24)) {
struct usb_device *dev;
if (usb_debug >= 2)
fprintf(stderr, "libusb/darwin.c usb_os_find_devices: Found USB device on bus 0x%08x: 0x%08x\n",
(uint32_t)bus_loc, (uint32_t)location);
dev = calloc(1, sizeof(struct usb_device));
if (dev == NULL)
USB_ERROR(-ENOMEM);
dev->bus = bus;
req.pData = device_desc;
result = (*(device))->DeviceRequest(device, &req);
if (result != kIOReturnSuccess) {
free (dev);
if (usb_debug)
fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Could not retrieve device descriptor: %s. Skipping device.\n",
darwin_error_str(result));
(*(device))->Release(device);
continue;
}
usb_parse_descriptor(device_desc, "bbwbbbbwwwbbbb", &dev->descriptor);
if (dev->descriptor.idProduct != idProduct) {
free (dev);
if (usb_debug)
fprintf (stderr, "libusb/darwin.c usb_os_find_devices: idProduct from iokit does not match idProduct in descriptor. Skipping device\n");
(*(device))->Release(device);
continue;
}
dev->devnum = devnum++;
sprintf(dev->filename, "%03i-%04x-%04x-%02x-%02x", address, idVendor, idProduct, bDeviceClass, bDeviceSubClass);
dev->dev = (USBDeviceAddress *) calloc (1, 4);
if (dev->dev == NULL)
USB_ERROR(-ENOMEM);
memcpy(dev->dev, &location, 4);
LIST_ADD(fdev, dev);
if (usb_debug >= 2)
fprintf(stderr, "libusb/darwin.c usb_os_find_devices: Found %s on %s at location 0x%08x\n",
dev->filename, bus->dirname, (uint32_t)location);
}
} else if (usb_debug)
fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Could not retrieve device address: %s\n",
darwin_error_str(result));
(*(device))->Release(device);
}
IOObjectRelease(deviceIterator);
*devices = fdev;
if (usb_debug)
fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Complete\n");
return 0;
}
int usb_os_determine_children(struct usb_bus *bus)
{
return 0;
}
void usb_os_init(void)
{
if (masterPort == MACH_PORT_NULL) {
IOMasterPort(masterPort, &masterPort);
gNotifyPort = IONotificationPortCreate(masterPort);
}
}
void usb_os_cleanup (void)
{
if (masterPort != MACH_PORT_NULL)
darwin_cleanup ();
}
int usb_resetep(usb_dev_handle *dev, unsigned int ep)
{
struct darwin_dev_handle *device;
io_return_t result = -1;
int pipeRef;
if (!dev)
USB_ERROR(-ENXIO);
if ((device = dev->impl_info) == NULL)
USB_ERROR(-ENOENT);
if (!device->interface)
USB_ERROR_STR(-EACCES, "usb_resetep: interface used without being claimed");
if ((pipeRef = ep_to_pipeRef(device, ep)) == -1)
USB_ERROR(-EINVAL);
result = (*(device->interface))->ResetPipe(device->interface, pipeRef);
if (result != kIOReturnSuccess)
USB_ERROR_STR(-darwin_to_errno(result), "usb_resetep(ResetPipe): %s", darwin_error_str(result));
return 0;
}
int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
{
struct darwin_dev_handle *device;
io_return_t result = -1;
int pipeRef;
if (!dev)
USB_ERROR(-ENXIO);
if ((device = dev->impl_info) == NULL)
USB_ERROR(-ENOENT);
if (!device->interface)
USB_ERROR_STR(-EACCES, "usb_clear_halt: interface used without being claimed");
if ((pipeRef = ep_to_pipeRef(device, ep)) == -1)
USB_ERROR(-EINVAL);
#if (InterfaceVersion < 190)
result = (*(device->interface))->ClearPipeStall(device->interface, pipeRef);
#else
result = (*(device->interface))->ClearPipeStallBothEnds(device->interface, pipeRef);
#endif
if (result != kIOReturnSuccess)
USB_ERROR_STR(-darwin_to_errno(result), "usb_clear_halt(ClearPipeStall): %s", darwin_error_str(result));
return 0;
}
int usb_reset(usb_dev_handle *dev)
{
struct darwin_dev_handle *device;
io_return_t result;
if (!dev)
USB_ERROR(-ENXIO);
if ((device = dev->impl_info) == NULL)
USB_ERROR(-ENOENT);
if (!device->device)
USB_ERROR_STR(-ENOENT, "usb_reset: no such device");
result = (*(device->device))->ResetDevice(device->device);
if (result != kIOReturnSuccess)
USB_ERROR_STR(-darwin_to_errno(result), "usb_reset(ResetDevice): %s", darwin_error_str(result));
return 0;
}