[macOS 10.11.6-] libusb_claim_interface returns error -99 with "QueryInterface: unknown error"
Hi all,
Since upgrading from libusb 1.0.23 to libusb 1.0.26, we got specifically on MacOS 10.11.6 El Captain and lower, the following error, when calling libusb_claim_interface:
Error code: -99
Log: libusb: error [darwin_claim_interface] QueryInterface: unknown error (0x80000004)
Therefore, obviously, I can't connect to my device. Please, does that ring a bell to anyone ?
Thanks in advance.
Can you please attach a full debug log? See also https://github.com/libusb/libusb/wiki/Troubleshooting
Here's the debug log of this issue debug-1.0.26.txt. I'm also interested in a fix.
I think this happens when libusb is built with newer macOS SDK and run on older OS. The logic in libusb/os/darwin_usb.h doesn't take into account deployment target, but just checks if symbol is defined. So libusb ends up requesting kIOUSBInterfaceInterfaceID800 even on macOS < 10.12, where it's unavailable.
Probably caused by 00688d059262b291d1bf9ef48865f0d3e0a48952
Also see 0f59214f1253a36f27c3acbcd9601d026d4741b1
Please see also commit d520f4d - is this still a problem on latest master?
clock_gettime logic works fine - otherwise it wouldn’t even start in the case we’re discussing.
I think 00688d0 should be reverted. I've looked at the linked PR #911 and have no idea how they are related. Pinging @osy (PR author), so that he could maybe explain it. Or maybe @hjelmn have an idea, since he reviewed and merged that PR.
Okay I see what the issue is. There are a few different build settings:
- The version of Xcode/macOS SDK that is being used
- The minimum deployment macOS specified at build time
- The version of the currently running macOS
Previously the logic was this: if the SDK supports the USB interface version AND the minimum deployment version supports it THEN use (highest) supported USB interface version.
I changed it to just checking if the SDK supports the USB interface version because I erroneously assumed that the macOS SDK version being used is the same as the currently running macOS. But obviously that's wrong because you can build with a newer SDK and set the deployment version to a lower macOS.
So it should be reverted but then we run into the error of libusb not working properly when deploying for other Apple systems like iOS and tvOS. An easy fix would be to OR in versions from iOS and tvOS and etc as well but perhaps there's a better solution?
Another solution is to figure out the maximum supported interface version at runtime somehow. It will be the most flexible solution (one build supporting both old OS versions and features of new OSes, if they are available), but it's more code someone has to write (and test on various OS versions) and maintain.
Hi guys, thanks for your quick feedback which confirms my suspicion regarding a probable bad management of deployment target. It's clearer now.
Don't really know your plan but if we go with your solution @parafin, it seems this issue won't be resolved in a close future because of the probable big amount of test to perform... Now, do you think this issue is major enough to be included in the next 1.0.27 milestone? Or do we now have to deal with a restricted range of macOS versions? What do you think ?
Probably a good idea to first do a simple fix (or just revert) before considering runtime detection. And to me this bug is a major issue.
Oh yep for sure, fixing it first at "compilation step" would be ideal and for that, @osy proposal (which, I confirm, works) seems for now the only "simple" solution. So ok, now I get what you think regarding the level of priority. Thanks again for your feedback.
Is this an issue in master? I think I fixed up all the version checks some months ago...
There were no relevant changes to darwin backend since the start of discussion of this bug. You’re probably referring to your changes about clock_gettime - those are working fine. To summarise - this is still not fixed.
Oh, I see. I thought I fixed all this in https://github.com/libusb/libusb/commit/0f59214f1253a36f27c3acbcd9601d026d4741b1 but I see now subsequent changes since have regressed things.
I'll make a new patch...
See also the discussion in issue #519.
So it should be reverted but then we run into the error of libusb not working properly when deploying for other Apple systems like iOS and tvOS.
Is that even possible? I can't find IOUSBLib.h in any other Xcode SDK besides the macOS SDK:
% find /Applications/Xcode.app/Contents/Developer/Platforms -name IOUSBLib.h
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/IOKit.framework/Versions/A/Headers/usb/IOUSBLib.h
Is there a good way to do runtime detection? For some purposes, we want to know the version we're actually running against, not just what APIs are available. In particular, for whether we need to call ClearPipeStallBothEnds in libusb_cancel_transfer as introduced by #1117. That function is always available, but whether or not we need to run it depends on the OS version.
Is there a good way to do runtime detection?
@martinling There are several ways, like @available and NSFoundationVersionNumber, but both these require Objective-C (or swift I guess).
From plain C there are some sysctls that could be used: https://stackoverflow.com/questions/5969485/getting-the-os-version-in-mac-os-x-using-standard-c
I'd still like to understand: from what I can tell from Apple's docs, IOKit is not available on all the other Darwin variants (except macOS), so what's the talk of using libusb on iOS and tvOS? Is it via hacks?
I'd still like to understand: from what I can tell from Apple's docs, IOKit is not available on all the other Darwin variants (except macOS), so what's the talk of using libusb on iOS and tvOS? Is it via hacks?
Yes, they are currently only available to jailbroken devices. Although in the past Apple has moved older APIs to iOS in an update (CoreAudio for example).
but both these require Objective-C (or swift I guess).
They do not.
HIDAPI uses something very similar in plain C: https://github.com/libusb/hidapi/blob/88a0f029b7f18fc7b3c3858d652494428b3ebc2e/mac/hid.c#L41
Let me take a crack at addressing this. I think I have an idea of how to manage it.
Mostly done but found an annoying edge case. I can't detect 10.8.3 with the method I am using so I can either use interface 550 always with 10.8.x (which would error for 10.8.0 -> 10.8.2) or just remove interface 550 support entirely (version 650 is in 10.9.0). I am leaning towards just removing it entirely since 10.8.x is 10+ years old now. We can discuss in the PR if needed.
Almost final version up at https://github.com/libusb/libusb/pull/1266 . I need to clean some things up but would love comments.
To close the loop the implementation uses sysctlbyname to get the running OS version. To avoid the weirdness with kern.osversion which requires some tweaking to get the right version from the kernel version I used kern.osproductversion instead. This gives the OS version after 10.13 or so. For earlier versions the code falls back on reading /System/Library/CoreServices/SystemVersion.plist to get the macOS/Mac OS X version. This is the source of truth for the deprecated Gestalt system call.
Tested only on macOS 13.3 so will need additional testing to make sure it works as expected.
FWIW I have tested git master (with #1266 merged) on macOS 11.6.1 (on an MBP Mid 2010!), both natively built binaries as well as binaries built on a 13.6 system, and it seems to work fine (our tests/* and in particular examples/xusb claiming an interface). However I understand that the reported here is only on 10.11.6 and older. So someone else has to verify there.