Possible regression in mac get_feature_report #60
Labels
No labels
3rdparty
Android
API
Author does not respond
bsd
bug
build system/CI
ci-virtual-device
CMake
Contributions Welcome
Core
dependencies
device-specific
documentation
don't_merge
duplicate
enhancement
Example
Haiku
hidraw
hotplug
info required
invalid
libusb
macOS
Misc
Not an issue
question
Release
Test
Test GUI
Windows
wontfix
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
gh-libusb/hidapi#60
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Prior to /pull/3 being merged get_feature_report was working identically for me on all platforms. Now the mac driver is failing as the returned buffer is different from the other platforms. My device does use report ids.
Is it possible that the behavior of OSX was changed from when this change was originally requested back in 2015?
Can anyone reproduce this issue?
Can you describe how different is it?
And is it different from previous release shipped with homebrew (0.8.0)?
The message that it is sending on the mac does not appear to include the report ID, so my device reports an error. If I write the rid in both the 1st and 2nd byte it sends the rid as part of the report. However I get a response on the mac of rid, rid, bytes as the mac library is writing the response out starting at the 2nd byte rather then the 1st. Prior to this change it worked correctly.
Other platforms include the rid in the (outbound) report and responded with the expected rid, bytes.
I wasn't using homebrew, I am building this myself. I was using Signal11/HidAPI (where it worked) but am trying to switch to yours as it is maintained. Once I reverted this pull everything worked as it did before.
Documentation of IOHIDDeviceGetReport is very explicit, that
reportshould contain only inbound report data, and that is what #3 is about.Can you confirm, that rid is other than 0x0 ?
I agree that it is very explicit, that's why I asked if anyone else experienced this issue. In this case the report id values that are not working are 0x14, 0x15 and 0x16.
It is possible that there is something out of spec with the device I have been using for testing. However it works just fine on all other platforms and on mac without this change.
What's happening at a protocol level (see section 8.2 of HID 1.11 spec), is that the Report ID will be removed from a response when a device doesn't use Report IDs.
This leaves some gaps – it's now up to the kernel to figure out if there's a report ID in there or not.
HID has other platform differences:
Linux's
HIDIOCGFEATUREioctl documentation says (emphasis mine):HIDAPI does not modify the return value, and so
get_feature_reportwithhidrawreturns just the report, and never the report ID (even if specified).I've tried to trace this through the kernel, and I think the report ID statement is actually false --
HIDIOCGFEATURE->hidraw_get_report->hid_hw_raw_request-> hid_device->ll_driver goes intousb_hid_driver->usbhid_raw_request->usbhid_get_raw_reportwhich addsreport_idifreport_id=0(otherwise, it presumes it'll get one back from the device, per protocol).libusb (Linux/BSD) always returns the report_number, adding one in if
report_id=0(otherwise, it presuming it'll get one back from the device)The Windows API docs say (emphasis mine):
This would suggest Windows will always need an extra byte for the Report ID, even if not used, and this is always returned by HIDAPI.
macOS's documentation suggests that it should never return a report ID, and the patch in #3 would change it to make it like all the others. However, I don't think I have something that uses multiple feature descriptors.
Running captures on
XHC20(USB sniffing) for something with one feature descriptor on 10.14 gives me weirdness forset_feature_report(report_id + 8 bytes): Adding a non-zeroreport_id (0x13)sendsURB_CONTROLwithwValue=0x0313; wLength=9and "completes" with datareport_id + 7 bytes (truncated):But doing a request with
report_id=0does the "complete" step without appending thereport_idand truncating:But, the more I look at this, the more that I see the API is unclear in the first instance. I'm of the opinion that returning a
report_idis essentially irrelevant, because it was already passed in the API in the first place.Chromium's mac implementation of this may be a useful reference
I think the best way to solve this is to explicitly break compatibility with all callers, with a new method signature that makes intent clearer:
report_idis the Report ID to get a feature report for. This may be0.bufis a buffer that HIDAPI can write to, or read from. The returned report always starts at byte 0 of that buffer.lengthis the exact number of bytes to request from the device.What is needed here is XHC20 (USB) captures from your software and device running with and without PR #3 on macOS. I suspect there is some other weirdness going on here. You'll need to bring up XHC20 with
sudo ifconfig XHC20 upbefore you can capture it with Wireshark on macOS.Then compare it to other platforms with the same code.
yeah, looks like that documentation isn't right (even though it was written by the same person, as hidapi itself)
this is questionable solution:
I did my best to understand Chromium's implementation if HID Get/SetFuature report, and so far I come to a conclusion, that
IOHIDDeviceGetReport's 4-th parameterreport, which is:Pointer to preallocated buffer in which to copy inbound report data.will contain a Report ID as its first byte, but only if device is using numbered reports.To properly know, whether device is using numbered reports or not, it would require parsing device's descriptor and searching if there defined at least one Report ID. (And that is exactly what Chromium's implementation does (e.g. here and here), and I believe that is the right way to do it).
So far,
hidapimakes a simpler assumption, aka: "device uses numbered reports, if Report ID is non-zero", so simplest fix I see here, is to make the same check forget_feature_reportas we do for hid_send_feature_report, and adjustIOHIDDeviceGetReport's arguments conditionally.Even though it looks like a proper fix to me, I don't have a devices to verify, and it probably may break existing application on macOS, that are already using builds before #3 or after (since patch #3 was applied to homebrew's formula for some while).
My personal observation: I have one HID device (and the application), that uses numbered reports, and #3 broke that application on macOS (I'm still using a local copy of hidapi for that one with a few patches on my own for now).
Having conditional argument change will not brake it though.
Fixed with #70