MacOS: empty path for devices in long USB chain #236

Closed
opened 2021-01-22 15:40:58 -06:00 by todbot · 14 comments
todbot commented 2021-01-22 15:40:58 -06:00 (Migrated from github.com)

Problem: Plug two 8-port USB hubs in a chain, add a HID device to second hub: hidapi returns empty string for path.

This was an old signal11 issue https://github.com/signal11/hidapi/issues/301 and I think we still have it. Over in node-hid land (https://github.com/node-hid/node-hid/issues/417), someone was experiencing this problem and had a good test showing both hidapitester and node-hid being able to get a path when the device is plugged in at one leaf of the USB tree but not at the other.

I think the issue happens at Line 464 of hidapi/mac/hid.c and I think it's because io_string_t is 512 characters and MacOS USB paths are already > 200 chars if you have just a single external USB hub.

I'm looking into finding definitions of io_string_t and IORegistryEntryGetPath() to see what our options are.

(The reason why I specify 8-port hubs above is those are implemented as two 4-port hubs, meaning the external USB tree look can look like: hub->hub->hub->hub->device, depending on where you plug what into what)

Problem: Plug two 8-port USB hubs in a chain, add a HID device to second hub: hidapi returns empty string for path. This was an old signal11 issue https://github.com/signal11/hidapi/issues/301 and I think we still have it. Over in `node-hid` land (https://github.com/node-hid/node-hid/issues/417), someone was experiencing this problem and had a good test showing both `hidapitester` and `node-hid` being able to get a path when the device is plugged in at one leaf of the USB tree but not at the other. I think the issue happens at [Line 464 of hidapi/mac/hid.c](https://github.com/libusb/hidapi/blob/d15d594a415e5f51d2cd8ff8bb77b3765a539b98/mac/hid.c#L464) and I think it's because `io_string_t` is 512 characters and MacOS USB paths are already > 200 chars if you have just a single external USB hub. I'm looking into finding definitions of `io_string_t` and `IORegistryEntryGetPath()` to see what our options are. (The reason why I specify 8-port hubs above is those are implemented as two 4-port hubs, meaning the external USB tree look can look like: hub->hub->hub->hub->device, depending on where you plug what into what)
todbot commented 2021-01-22 16:01:58 -06:00 (Migrated from github.com)

It looks like perhaps a solution is to use IORegistryEntryGetRegistryEntryID() instead of IORegistryEntryGetPath(): https://github.com/Yubico/python-fido2/pull/94/commits/61c2a5d852118b60fbd19c0be91043a8a2172e78

It looks like perhaps a solution is to use `IORegistryEntryGetRegistryEntryID()` instead of `IORegistryEntryGetPath()`: https://github.com/Yubico/python-fido2/pull/94/commits/61c2a5d852118b60fbd19c0be91043a8a2172e78
Youw commented 2021-01-22 17:49:51 -06:00 (Migrated from github.com)
Related to https://github.com/libusb/hidapi/issues/127 and https://github.com/flirc/hidapi/commit/8d251c3854c3b1877509ab07a623dafc8e803db5 (the fix)?
todbot commented 2021-01-22 18:35:29 -06:00 (Migrated from github.com)

I think so. I'll be attempting it this weekend.

I think so. I'll be attempting it this weekend.
mcuee commented 2021-06-13 20:52:46 -05:00 (Migrated from github.com)

@Youw Maybe this can be merged as well. github.com/flirc/hidapi@8d251c3854

@Youw Maybe this can be merged as well. https://github.com/flirc/hidapi/commit/8d251c3854c3b1877509ab07a623dafc8e803db5
Youw commented 2021-06-14 05:41:37 -05:00 (Migrated from github.com)

I'd suggest a few changes to flirc/hidapi@8d251c3 before accepting it.

I'd suggest a few changes to flirc/hidapi@8d251c3 before accepting it.
mcuee commented 2021-08-06 20:29:48 -05:00 (Migrated from github.com)

https://github.com/libusb/hidapi/issues/249#issuecomment-894585228

I was hit by this issue as well, since I have two external powered USB hubs (one 7-port and one 11-port) which are actually complicate hubs (nested hub). So even the first hub (D-Link USB 3 powered 7-port hub) already cause issues.

https://github.com/libusb/hidapi/issues/249#issuecomment-894585228 I was hit by this issue as well, since I have two external powered USB hubs (one 7-port and one 11-port) which are actually complicate hubs (nested hub). So even the first hub (D-Link USB 3 powered 7-port hub) already cause issues.
mcuee commented 2021-08-08 07:10:19 -05:00 (Migrated from github.com)

@Youw @todbot It seems to me that hidapi has changed a lot that commit github.com/todbot/hidapi@8839e544a6 no longer applies. Please help if you got time. Thanks.

@Youw @todbot It seems to me that hidapi has changed a lot that commit https://github.com/todbot/hidapi/commit/8839e544a6a9b919fa3fc95c859b89816e19af8a no longer applies. Please help if you got time. Thanks.
Youw commented 2021-08-12 03:38:40 -05:00 (Migrated from github.com)

I'll work on it this week.

I'll work on it this week.
noah-nuebling commented 2021-08-14 04:36:35 -05:00 (Migrated from github.com)

Maybe we could use IORegistryEntryGetPath() and simply pass it a char buffer that‘s greater than 512 bytes.

(Since io_string_t is just a char[512])

Notice that the Swift version of this function just uses a char buffer of any size and the docs mention nothing about a 512 character limit.

Maybe we could use [`IORegistryEntryGetPath()`](https://developer.apple.com/documentation/iokit/1514229-ioregistryentrygetpath?language=objc) and simply pass it a char buffer that‘s greater than 512 bytes. (Since `io_string_t` is just a `char[512]`) Notice that the Swift version of this function just uses a char buffer of any size and the docs mention nothing about a 512 character limit.
Youw commented 2021-08-14 11:56:57 -05:00 (Migrated from github.com)

I'm confident that won't work. The implementation of IORegistryEntryGetPath expects char[512] as an input, which practically means that that parameter is passed by pointer/reference, but even if we pass a pointer/reference to a larger buffer - the implementation will only use what it originally expects.

I'm confident that won't work. The implementation of `IORegistryEntryGetPath` expects `char[512]` as an input, which practically means that that parameter is passed by pointer/reference, but even if we pass a pointer/reference to a larger buffer - the implementation will only use what it originally expects.
noah-nuebling commented 2021-08-14 13:41:28 -05:00 (Migrated from github.com)

I think it might be worth a shot.

The documentation reads like it just expect a char buffer of any length not just 512. E.g. „IORegistryEntryGetPath() will fail […] if the buffer is not large enough to contain the path.“

I think it might be worth a shot. The documentation reads like it just expect a char buffer of any length not just 512. E.g. „IORegistryEntryGetPath() will fail […] if the buffer is not large enough to contain the path.“
Youw commented 2021-08-14 14:51:55 -05:00 (Migrated from github.com)

And the documentation is missleading. The buffer size is not passed into IORegistryEntryGetPath. It is hard-coded in its declaration.

And the documentation is missleading. The buffer size _is not passed into `IORegistryEntryGetPath`_. It is hard-coded in its declaration.
noah-nuebling commented 2021-08-14 15:43:00 -05:00 (Migrated from github.com)

This probably isn't relevant anymore since the ID-based method is already implemented, but just out of interest, I dug through the Apple open source files and took a look at the implementation of IORegistryEntryGetPath(), and you're right - the limit of 512 characters is hardcoded into it.

However I found a newer pair of functions called IORegistryEntryCopyPath() and IORegistryEntryCopyFromPath() which seem to do the same thing as IORegistryEntryGetPath() and IORegistryEntryFromPath() but relying on CFStringRef instead of io_string_t. I'm quite certain that these functions don't have the 512 character limit.

However they are only available starting with macOS 10.11.

This probably isn't relevant anymore since the ID-based method is already implemented, but just out of interest, I dug through the Apple open source files and took a look at the implementation of `IORegistryEntryGetPath()`, and you're right - the limit of 512 characters is hardcoded into it. However I found a newer pair of functions called `IORegistryEntryCopyPath()` and `IORegistryEntryCopyFromPath()` which seem to do the same thing as `IORegistryEntryGetPath()` and `IORegistryEntryFromPath()` but relying on CFStringRef instead of io_string_t. I'm quite certain that these functions don't have the 512 character limit. However they are only available starting with macOS 10.11.
mcuee commented 2021-08-25 06:41:15 -05:00 (Migrated from github.com)

This should be fixed by #322. Tested with my Mac Mini M1.

This should be fixed by #322. Tested with my Mac Mini M1.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-libusb/hidapi#236
No description provided.