--- libusb-0.1.12/darwin.c	2006-03-03 21:52:46.000000000 -0500
+++ libusb-0.1.12a/darwin.c	2016-05-03 21:50:23.000000000 -0400
@@ -54,6 +54,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <sys/time.h>
 
 /* standard includes for darwin/os10 (IOKit) */
 #include <mach/mach_port.h>
@@ -247,7 +248,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 +449,7 @@
   IOUSBFindInterfaceRequest request;
 
   struct darwin_dev_handle *device;
-  long score;
+  SInt32 score;
   int current_interface;
 
   device = dev->impl_info;
@@ -758,6 +760,7 @@
 
 /* argument to handle multiple parameters to rw_completed */
 struct rw_complete_arg {
+  UInt32        done;
   UInt32        io_size;
   IOReturn      result;
   CFRunLoopRef  cf_loop;
@@ -768,15 +771,28 @@
   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);
+    fprintf(stderr, "io async operation completed: %s, size=%u, result=0x%08x\n", darwin_error_str(result),
+	    (unsigned int)io_size, result);
 
   rw_arg->io_size = (UInt32)io_size;
   rw_arg->result  = result;
+  rw_arg->done  = 1;
 
   CFRunLoopStop(rw_arg->cf_loop);
 }
 
+#define S_TO_NS(x)  ( (x) * 1000000000ULL )
+#define MS_TO_NS(x) ( (x) * 1000000ULL )
+#define US_TO_NS(x) ( (x) * 1000ULL )
+#define NS_TO_MS(x) ( ((x)+999999) / 1000000ULL )
+
+static uint64_t GetTod()
+{
+   struct timeval now;
+   gettimeofday(&now, NULL);
+   return S_TO_NS(now.tv_sec) + US_TO_NS(now.tv_usec);
+}
+
 static int usb_bulk_transfer (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)
 {
@@ -825,24 +841,54 @@
 	     size, ep);
 
   /* 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");
-
+  uint64_t endtime = 0;
   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
+  else {
+    endtime = GetTod() + MS_TO_NS(timeout); /* Manual timeout handling */
     result = rw_async (device->interface, pipeRef, bytes, size, (IOAsyncCallback1)rw_completed,
 		       (void *)&rw_arg);
+  }
 
+  /* wait for transfer to complete */
   if (result == kIOReturnSuccess) {
-    /* wait for write to complete */
-    if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, (timeout+999)/1000, true) == kCFRunLoopRunTimedOut) {
-      (*(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");
+
+    if (endtime) {
+
+      /* No timeout support from USB, need to do it manually */
+      int aborted = 0;
+
+      /* Timeouts of a second or more get low resolution but efficient handling */
+      if (timeout >= 1000) {
+	if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, (timeout+999)/1000, false) == kCFRunLoopRunTimedOut) {
+	  (*(device->interface))->AbortPipe(device->interface, pipeRef);
+	  aborted = 1;
+	}
+      }
+
+      /* Wait for transfer to complete */
+      while (!rw_arg.done) {
+
+	if (!aborted && GetTod() >= endtime) {
+	  (*(device->interface))->AbortPipe(device->interface, pipeRef);
+	  aborted = 1; /* We've timed out, continue looping until abort happens */
+	}
+
+	CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
+
+	/* Relax CPU */
+	if (!rw_arg.done)
+	  usleep(5000);
+      }
+  
+      /* Abort means we timed out */
+      if (rw_arg.result == kIOReturnAborted)
+	result = kIOUSBTransactionTimeout;
+    } else {
+      /* Timeout handled automatically by USB */
+      /* Run loop is stopped when rw_completed callback runs */
+      CFRunLoopRun();
     }
   }
 
@@ -862,10 +908,7 @@
       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);
+    USB_ERROR_STR(-error_code, "usb_bulk_transfer: %s", error_str);
   }
 
   return rw_arg.io_size;
@@ -1064,7 +1107,7 @@
     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%08x\n", (unsigned int)location);
 
     /* first byte of location appears to be associated with the device's bus */
     if (location >> 24 == bus_loc >> 24) {
@@ -1091,8 +1134,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%08x\n",
+		dev->filename, bus->dirname, (unsigned int)location);
     }
 
     /* release the device now */
