Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible regression in mac get_feature_report #60

Closed
DanielVanNoord opened this issue Aug 1, 2019 · 8 comments
Closed

Possible regression in mac get_feature_report #60

DanielVanNoord opened this issue Aug 1, 2019 · 8 comments
Labels
info required Need more input from PR/issue author

Comments

@DanielVanNoord
Copy link
Contributor

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?

@Youw Youw added the info required Need more input from PR/issue author label Aug 1, 2019
@Youw
Copy link
Member

Youw commented Aug 1, 2019

Can you describe how different is it?
And is it different from previous release shipped with homebrew (0.8.0)?

@DanielVanNoord
Copy link
Contributor Author

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.

@Youw
Copy link
Member

Youw commented Aug 1, 2019

Documentation of IOHIDDeviceGetReport is very explicit, that report should contain only inbound report data, and that is what #3 is about.

Can you confirm, that rid is other than 0x0 ?

@DanielVanNoord
Copy link
Contributor Author

DanielVanNoord commented Aug 1, 2019

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.

@micolous
Copy link

micolous commented Aug 11, 2019

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:

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 for set_feature_report(report_id + 8 bytes): Adding a non-zero report_id (0x13) sends URB_CONTROL with wValue=0x0313; wLength=9 and "completes" with data report_id + 7 bytes (truncated):

Screen Shot 2019-08-11 at 17 23 42

Screen Shot 2019-08-11 at 17 24 24

But doing a request with report_id=0 does the "complete" step without appending the report_id and truncating:

Screen Shot 2019-08-11 at 17 27 25

Screen Shot 2019-08-11 at 17 27 42

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_id is 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:

int hid_get_feature_report(hid_device *dev, unsigned char report_id, unsigned char* buffer, size_t length);
  • report_id is the Report ID to get a feature report for. This may be 0.
  • buf is a buffer that HIDAPI can write to, or read from. The returned report always starts at byte 0 of that buffer.
  • length is 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 up before you can capture it with Wireshark on macOS.

Then compare it to other platforms with the same code.

@Youw
Copy link
Member

Youw commented Aug 11, 2019

and I think the report ID statement is actually false

yeah, looks like that documentation isn't right (even though it was written by the same person, as hidapi itself)

int hid_get_feature_report(hid_device dev, unsigned char report_id, unsigned char buffer, size_t length);

this is questionable solution:

  1. it will require creating new continues buffer in Windows/linux/libusb implementations, to copy Report ID before the data
  2. it still doesn't not give a complete answer what is the correct macOS implementation - before or after mac: fix behaviour of hid_get_feature_report (was writing on the repo… #3 (or should be it same as for hid_send_feature_report)

@Youw
Copy link
Member

Youw commented Aug 11, 2019

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 parameter report, 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, hidapi makes 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 for get_feature_report as we do for hid_send_feature_report, and adjust IOHIDDeviceGetReport'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.

@Youw
Copy link
Member

Youw commented Sep 24, 2019

Fixed with #70

@Youw Youw closed this as completed Sep 24, 2019
@vitalys vitalys mentioned this issue Sep 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
info required Need more input from PR/issue author
Projects
None yet
Development

No branches or pull requests

3 participants