hidapi
hidapi copied to clipboard
Invalid usage_page values in Linux
I have a Honeywell 1400g barcode scanner which identifies itself as:
Vendor | Product | Serial |
---|---|---|
0x0c2e | 0x0b87 | 17338B352C |
It has two endpoints:
Endpoint 1 | Endpoint 2 | |
---|---|---|
UsagePage | -116 | 140 |
On Windows and MacOS, I can use UsagePage to distinguish between the two. We toss out the -116
and keep the 140
and we have the proper device and can read HID data from it.
Unfortunately, the two endpoints are causing trouble when claiming the device in Linux: both UsagePage values return zero.
The source of hid.c
makes this appear intentional:
/* Uncomment to enable the retrieval of Usage and Usage Page in
hid_enumerate(). Warning, on platforms different from FreeBSD
this is very invasive as it requires the detach
and re-attach of the kernel driver. See comments inside hid_enumerate().
libusb HIDAPI programs are encouraged to use the interface number
instead to differentiate between interfaces on a composite HID device. */
/*#define INVASIVE_GET_USAGE*/
Although the documentation recommends to use interface number, for the hardware I'm testing on, interface number is the same between devices. How do other users handle edge-cases where HID returns two device matches on the same physical device on Linux?
It sounds like you're using the 'libusb' driver on Linux.
The libusb
Linux driver does not have usage
and usagePage
properties, but the hidraw
Linux driver does. You should be able to switch the driver for your app and have it still work.
Note you'll need to change your udev rules if you're using those, swapping KERNEL=="hidraw*"
for SUBSYSTEM=="usb"
.
@todbot yes, I believe I am. I'm using it indirectly through a third party, so I'll have to see if switching is an option. Thanks.
The hid4java
's build process is pretty foreign to me. I can't see how hidapi
is even being compiled from the docs for hid4java
, making me think he hand-compiles them and then copies them over.
If that's the case, I would try hand-compiling hidapi
and copying the file yourself. The README gives how to do that, but in summary, on Linux it would be:
sudo apt-get install libudev-dev autotools-dev autoconf automake libtool build-essential
git clone https://github.com/signal11/hidapi
cd hidapi
./bootstrap
./configure --prefix=${HOME}/hidapi_tmp
make
make install
And then you'll have a libhidapi_tmp/lib/libhidapi-hidraw.so.0.0.0
file.
Copy that file on top of the file hid4java/src/main/resources/linux-x86/libhidapi.so
@todbot thanks kindly for this information! What's not immediately obvious is why the libusb-1.0-0
, libusb-1.0-0-dev
are left out... or more specifically... how to build without them. How does the build system know to use hidraw
, or does the target provide both when done?
does the target provide both when done?
Answering my own question, libusb-1.0-0 libusb-1.0-0-dev
required and yes, both libraries are built.
@todbot I have to thank you for going out of your way to look into the 3rd party library, that's very kind.
So I've replaced /linux-x86-64/libhidapi.so
in hid4java-0.5.0.jar
with libhidapi-hidraw.so.0.0.0
and I can confirm that UsagePage
is returned, but there's some disparity...
Endpoint 1 | Endpoint 2 | |
---|---|---|
MacOS UsagePage | -116 | 140 |
Windows UsagePage | -116 | 140 |
Linux UsagePage | 0 | 14776 |
Is there some translation that can be used to map these values to each other? Grabbing at straws here. :)
Note you'll need to change your udev rules if you're using those, swapping
KERNEL=="hidraw*" for SUBSYSTEM=="usb"
We've been using SUBSYSTEM=="usb"
historically. For some odd reason, this machine works (standard user, not root) without the rules I usually install. It's running VirtualBox VM with Guest Additions, device attached as same user.
ubuntu@ubuntu1404:~$ cat /etc/udev/rules.d/*.rules
# libusb device access
SUBSYSTEM=="usb_device", ACTION=="add", RUN+="/usr/bin/killall -sUSR1 portcommunicationserviced"
SUBSYSTEM=="usb_device", ACTION=="remove", RUN+="/usr/bin/killall -sUSR2 portcommunicationserviced"
SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", RUN+="/usr/bin/killall -sUSR1 portcommunicationserviced"
SUBSYSTEM=="usb", ACTION=="remove", ENV{DEVTYPE}=="usb_device", RUN+="/usr/bin/killall -sUSR2 portcommunicationserviced"
KERNEL=="vboxguest", NAME="vboxguest", OWNER="vboxadd", MODE="0660"
KERNEL=="vboxuser", NAME="vboxuser", OWNER="vboxadd", MODE="0666"
Tested UsagePage
on physical hardware (identical OS, NOT in a VM) and received different and even less useful results:
Endpoint 1 | Endpoint 2 | |
---|---|---|
MacOS UsagePage | -116 | 140 |
Windows UsagePage | -116 | 140 |
Linux UsagePage (VM) | 0 | 14776 |
Linux UsagePage (Physical) | 18432 | 18432 |
I could solve the problem of zero values by moving to hidraw. However, I now receive odd/incorrect numbers.
@tresf Could you find a solution to this problem? I have seeing something similar. Actually, same device, same host, different libraries show the following:
If I use https://github.com/flynn/hid path: /dev/hidraw5 VendorID : 0x2c97 UsagePage : 0xffa0
However, when I use a library that is signal11 based:
path: "/dev/hidraw5", vendor_id: 0x2c97, usage_page: 0x0032
Unfortunately no. We (my project) simply cannot support this type of hardware on Linux using the hidapi
library.
it seems to me that the usage_page is not even set and the values we are seeing are some left over.
https://github.com/signal11/hidapi/blob/a6a622ffb680c55da0de787ff93b80280498330f/linux/hid.c#L479-L555
Actually, it seems that here is a dead PR with the fix:
https://github.com/signal11/hidapi/pull/6
It is unfortunate that the project has no activity since 2016
@tresf would you mind renaming the issue to: "Invalid usage_page values in Linux" ?
@tresf would you mind renaming the issue to: "Invalid usage_page values in Linux" ?
Done.