macOS Sierra: Fix detection of parent devices.
authortich <chris@tich.info>
Mon, 13 Mar 2017 16:37:33 +0000 (09:37 -0700)
committerNathan Hjelm <hjelmn@cs.unm.edu>
Fri, 17 Mar 2017 01:35:44 +0000 (19:35 -0600)
This fixes the output of libusb_get_port_numbers(), where it used to merely return the port number of the device itself.
Now that libusb properly detects parent devices, we get the entire port path of the device.
For reference, here's the output of the 'listdevs' example before my changes:

tich-mbp:libusb-1.0.21 tich$ ./examples/listdevs
0409:005a (bus 29, device 6) path: 1
05ac:8509 (bus 26, device 2) path: 1
05ac:821d (bus 29, device 7) path: 3
05ac:0252 (bus 29, device 5) path: 3
05ac:8242 (bus 29, device 4) path: 2
0a5c:4500 (bus 29, device 3) path: 1
0424:2513 (bus 29, device 2) path: 8
8087:0024 (bus 29, device 1) path: 1
8087:0024 (bus 26, device 1) path: 1

And here's the output after my changes:

tich-mbp:libusb-1.0.21 tich$ ./examples/listdevs
0409:005a (bus 29, device 6) path: 1.1
05ac:8509 (bus 26, device 2) path: 1.1
05ac:821d (bus 29, device 7) path: 1.8.1.3
05ac:0252 (bus 29, device 5) path: 1.8.3
05ac:8242 (bus 29, device 4) path: 1.8.2
0a5c:4500 (bus 29, device 3) path: 1.8.1
0424:2513 (bus 29, device 2) path: 1.8
8087:0024 (bus 29, device 1) path: 1
8087:0024 (bus 26, device 1) path: 1

Since we're now using "IOUSBHostDevice" as the matching service (starting with El Capitan), we need to walk up the IOService plane to look for parents.
You can manually walk up the IOService plane by executing "ioreg -p IOService -l -w 0 -x | less" and looking for your device. Notice that the parent device is always a parent in the tree, but it's not always the _immediate_ parent of the device.

libusb/os/darwin_usb.c
libusb/version_nano.h

index 68ed9b5..739644e 100644 (file)
@@ -875,14 +875,29 @@ static int get_device_port (io_service_t service, UInt8 *port) {
   return ret;
 }
 
+static int get_device_parent_sessionID(io_service_t service, UInt64 *parent_sessionID) {
+  kern_return_t result;
+  io_service_t parent;
+
+  /* Walk up the tree in the IOService plane until we find a parent that has a sessionID */
+  parent = service;
+  while((result = IORegistryEntryGetParentEntry (parent, kIOServicePlane, &parent)) == kIOReturnSuccess) {
+    if (get_ioregistry_value_number (parent, CFSTR("sessionID"), kCFNumberSInt64Type, parent_sessionID)) {
+        /* Success */
+        return 1;
+    }
+  }
+
+  /* We ran out of parents */
+  return 0;
+}
+
 static int darwin_get_cached_device(struct libusb_context *ctx, io_service_t service,
                                     struct darwin_cached_device **cached_out) {
   struct darwin_cached_device *new_device;
   UInt64 sessionID = 0, parent_sessionID = 0;
   int ret = LIBUSB_SUCCESS;
   usb_device_t **device;
-  io_service_t parent;
-  kern_return_t result;
   UInt8 port = 0;
 
   /* get some info from the io registry */
@@ -893,11 +908,8 @@ static int darwin_get_cached_device(struct libusb_context *ctx, io_service_t ser
 
   usbi_dbg("finding cached device for sessionID 0x%" PRIx64, sessionID);
 
-  result = IORegistryEntryGetParentEntry (service, kIOUSBPlane, &parent);
-
-  if (kIOReturnSuccess == result) {
-    (void) get_ioregistry_value_number (parent, CFSTR("sessionID"), kCFNumberSInt64Type, &parent_sessionID);
-    IOObjectRelease(parent);
+  if (get_device_parent_sessionID(service, &parent_sessionID)) {
+    usbi_dbg("parent sessionID: 0x%" PRIx64, parent_sessionID);
   }
 
   usbi_mutex_lock(&darwin_cached_devices_lock);
index 0c1b1c3..723c6c5 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 11193
+#define LIBUSB_NANO 11194