diff --git a/darwin.c b/darwin.c --- a/darwin.c +++ b/darwin.c @@ -1,8 +1,10 @@ /* * Darwin/MacOS X Support * - * (c) 2002-2005 Nathan Hjelm + * (c) 2002-2006 Nathan Hjelm * + * (06/26/2006): + * - Bulk functions no longer use async transfer functions. * (04/17/2005): * - Lots of minor fixes. * - Endpoint table now made by claim_interface to fix a bug. @@ -51,6 +53,7 @@ #include "config.h" #endif +#include #include #include #include @@ -146,7 +149,6 @@ #define IO_OBJECT_NULL ((io_object_t)0) #endif -/* Darwin/OS X impl does not use fd field, instead it uses this */ struct darwin_dev_handle { usb_device_t **device; usb_interface_t **interface; @@ -157,7 +159,6 @@ unsigned char *endpoint_addrs; }; -static CFMutableDictionaryRef matchingDict; static IONotificationPortRef gNotifyPort; static mach_port_t masterPort = MACH_PORT_NULL; @@ -223,6 +224,7 @@ static int usb_setup_iterator (io_iterator_t *deviceIterator) { int result; + CFMutableDictionaryRef matchingDict; /* set up the matching dictionary for class IOUSBDevice and its subclasses. It will be consumed by the IOServiceGetMatchingServices call */ @@ -247,7 +249,8 @@ io_cf_plugin_ref_t *plugInInterface = NULL; usb_device_t **device; io_service_t usbDevice; - long result, score; + long result; + SInt32 score; if (!IOIteratorIsValid (deviceIterator) || !(usbDevice = IOIteratorNext(deviceIterator))) return NULL; @@ -447,7 +450,7 @@ IOUSBFindInterfaceRequest request; struct darwin_dev_handle *device; - long score; + SInt32 score; int current_interface; device = dev->impl_info; @@ -756,6 +759,70 @@ 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" ); + + /* interface is not open */ + if (!device->interface) + USB_ERROR_STR(-EACCES, "libusb/darwin.c usb_bulk_transfer: Interface used before it was opened"); + + + /* Set up transfer */ + 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); + /* Transfer set up complete */ + + if (usb_debug > 0) + fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n", size, ep); + + /* Do bulk transfer */ + 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); + + /* pipe bits may need to be cleared after a timeout. should this be done here or in user code? */ + 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 +/* NOT USED */ /* argument to handle multiple parameters to rw_completed */ struct rw_complete_arg { UInt32 io_size; @@ -777,7 +844,7 @@ CFRunLoopStop(rw_arg->cf_loop); } -static int usb_bulk_transfer (usb_dev_handle *dev, int ep, char *bytes, int size, int timeout, +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; @@ -813,11 +880,12 @@ (*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number, &transferType, &maxPacketSize, &interval); - (*(device->interface))->CreateInterfaceAsyncEventSource(device->interface, &cfSource); - CFRunLoopAddSource(CFRunLoopGetCurrent(), cfSource, kCFRunLoopDefaultMode); - 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); /* Transfer set up complete */ if (usb_debug > 0) @@ -842,11 +910,12 @@ (*(device->interface))->AbortPipe(device->interface, pipeRef); CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); /* Pick up aborted callback */ if (usb_debug) - fprintf(stderr, "usb_bulk_read: input timed out\n"); + fprintf(stderr, "usb_bulk_transfer: timed out\n"); } } - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), cfSource, kCFRunLoopDefaultMode); + CFRunLoopRemoveSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode); + CFRelease (rw_arg.cf_loop); /* Check the return code of both the write and completion functions. */ if (result != kIOReturnSuccess || (rw_arg.result != kIOReturnSuccess && @@ -870,24 +939,16 @@ return rw_arg.io_size; } +#endif int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout) { int result; - rw_async_to_func_t to_func = NULL; - struct darwin_dev_handle *device; if (dev == NULL || dev->impl_info == NULL) return -EINVAL; - device = dev->impl_info; - -#if !defined (LIBUSB_NO_TIMEOUT_INTERFACE) - to_func = (*(device->interface))->WritePipeAsyncTO; -#endif - - if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, - (*(device->interface))->WritePipeAsync, to_func)) < 0) + 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; @@ -896,28 +957,19 @@ int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout) { int result; - rw_async_to_func_t to_func = NULL; - struct darwin_dev_handle *device; if (dev == NULL || dev->impl_info == NULL) return -EINVAL; ep |= 0x80; - - device = dev->impl_info; -#if !defined (LIBUSB_NO_TIMEOUT_INTERFACE) - to_func = (*(device->interface))->ReadPipeAsyncTO; -#endif - - if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, - (*(device->interface))->ReadPipeAsync, to_func)) < 0) + 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; } -/* interrupt endpoints seem to be treated just like any other endpoint under OSX/Darwin */ +/* interrupt endpoints appear to be treated the same as non-interrupt endpoints under OSX/Darwin */ int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout) { @@ -1064,7 +1116,8 @@ result = (*(device))->GetDeviceAddress(device, (USBDeviceAddress *)&address); if (usb_debug >= 2) - fprintf(stderr, "usb_os_find_devices: Found USB device at location 0x%08lx\n", location); + fprintf(stderr, "usb_os_find_devices: Found USB device at location 0x%08" PRIx32 "\n", + (uint32_t) location); /* first byte of location appears to be associated with the device's bus */ if (location >> 24 == bus_loc >> 24) { @@ -1091,8 +1144,8 @@ LIST_ADD(fdev, dev); if (usb_debug >= 2) - fprintf(stderr, "usb_os_find_devices: Found %s on %s at location 0x%08lx\n", - dev->filename, bus->dirname, location); + fprintf(stderr, "usb_os_find_devices: Found %s on %s at location 0x%08" PRIx32 "\n", + dev->filename, bus->dirname, (uint32_t) location); } /* release the device now */ @@ -1177,7 +1230,12 @@ if ((pipeRef = ep_to_pipeRef(device, ep)) == -1) USB_ERROR(-EINVAL); +#if (InterfaceVersion < 190) result = (*(device->interface))->ClearPipeStall(device->interface, pipeRef); +#else + /* newer versions of darwin support clearing additional bits on the device's endpoint */ + 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));