From 0b381a81bed9051bfac7a4f5a16358182c7e7f9a Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Wed, 20 Mar 2019 11:34:41 +0000 Subject: darwin: Retry IOCreatePlugInInterfaceForService on failure We have a case where a device might not be detected by libusb if we plug it after initializing the library. We were able to reproduce this issue pretty consistently on a Mac Mini and several MacBook Pros running very recent macOS versions (Mojave) using the Balena Fin board (https://www.balena.io/fin/). I don't know if this happens with other USB devices. Enabling debug output revealed the following: ``` [ 7.901582] [00004f07] libusb: debug [darwin_get_cached_device] finding cached device for sessionID 0x2a9b5279f04 [ 7.901764] [00004f07] libusb: debug [darwin_get_cached_device] matching sessionID 0x2a9b5279f04 against cached device with sessionID 0x17dbd029b6a [ 7.901798] [00004f07] libusb: debug [darwin_get_cached_device] matching sessionID 0x2a9b5279f04 against cached device with sessionID 0x1688763269f [ 7.901818] [00004f07] libusb: debug [darwin_get_cached_device] matching sessionID 0x2a9b5279f04 against cached device with sessionID 0x4c0aefaa [ 7.901831] [00004f07] libusb: debug [darwin_get_cached_device] matching sessionID 0x2a9b5279f04 against cached device with sessionID 0x0 [ 7.901845] [00004f07] libusb: debug [darwin_get_cached_device] caching new device with sessionID 0x2a9b5279f04 [ 7.903377] [00004f07] libusb: debug [darwin_device_from_service] could not set up plugin for service: out of resources [ 8.029152] [00000307] libusb: debug [libusb_get_device_list] ``` The "out of resources" error comes from `IOCreatePlugInInterfaceForService` which will apparently return this error if the `Start` method of the interface is not success (see https://github.com/opensource-apple/IOKitUser/blob/b80a5cbc0ebfb5c4954ef6d757918db0e4dc4b7f/IOCFPlugIn.c#L232). Retrying `IOCreatePlugInInterfaceForService` makes it work for me. Closes #542 Signed-off-by: Juan Cruz Viotti Signed-off-by: Nathan Hjelm --- libusb/os/darwin_usb.c | 20 +++++++++++++++++--- libusb/version_nano.h | 2 +- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c index dd391db..f6e853b 100644 --- a/libusb/os/darwin_usb.c +++ b/libusb/os/darwin_usb.c @@ -297,10 +297,24 @@ static usb_device_t **darwin_device_from_service (io_service_t service) usb_device_t **device; IOReturn kresult; SInt32 score; + const int max_retries = 5; + + /* The IOCreatePlugInInterfaceForService function might consistently return + an "out of resources" error with certain USB devices the first time we run + it. The reason is still unclear, but retrying fixes the problem */ + for (int count = 0; count < max_retries; count++) { + kresult = IOCreatePlugInInterfaceForService(service, kIOUSBDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, &plugInInterface, + &score); + if (kIOReturnSuccess == kresult && plugInInterface) { + break; + } - kresult = IOCreatePlugInInterfaceForService(service, kIOUSBDeviceUserClientTypeID, - kIOCFPlugInInterfaceID, &plugInInterface, - &score); + usbi_dbg ("set up plugin for service retry: %s", darwin_error_str (kresult)); + + /* sleep for a little while before trying again */ + nanosleep(&(struct timespec){.tv_sec = 0, .tv_nsec = 1000}, NULL); + } if (kIOReturnSuccess != kresult || !plugInInterface) { usbi_dbg ("could not set up plugin for service: %s", darwin_error_str (kresult)); diff --git a/libusb/version_nano.h b/libusb/version_nano.h index ae13822..e542188 100644 --- a/libusb/version_nano.h +++ b/libusb/version_nano.h @@ -1 +1 @@ -#define LIBUSB_NANO 11361 +#define LIBUSB_NANO 11362 -- cgit v1.2.1