hidapi icon indicating copy to clipboard operation
hidapi copied to clipboard

Stable path for multiple USB devices (on LInux)?

Open derekatkins opened this issue 5 years ago • 8 comments

I've got multiple devices that I'm trying to access in a stable manner. They do not provide a serial number or other uniquifying data that I can see. I tried to use the HID path but it looks like that's not a stable number -- each time I remove and re-insert the device (into the same USB port) the HID path changes. Is there some way to access the underlying USB path (which DOES appear to be stable)? E.g.:

[2332915.679529] hid-generic 0003:0416:5020.0005: input,hidraw0: USB HID v1.10 Device [Nuvoton HID Transfer] on usb-0000:00:14.0-4/input0
[2333625.965356] hid-generic 0003:0416:5020.0006: input,hidraw0: USB HID v1.10 Device [Nuvoton HID Transfer] on usb-0000:00:14.0-4/input0
[2336516.928041] hid-generic 0003:0416:5020.0007: input,hidraw0: USB HID v1.10 Device [Nuvoton HID Transfer] on usb-0000:00:14.0-4/input0
[2337168.447530] hid-generic 0003:0416:5020.0008: input,hidraw0: USB HID v1.10 Device [Nuvoton HID Transfer] on usb-0000:00:14.0-1/input0

I had the first device on usb-0000:00:14.0-4 which I removed and reinserted, and then I removed/reinserted the second device on usb-0000:00:14.0-1. Unfortunately I don't see any way to access this information from hidapi. Worse, the hid path changes on every insert (see the 0005, 0006, 0007, 0008? That gets reflected in an increasing hid path).

So without a serial number, what's the path (pun intended) to a stable reference to a HID device? The full dmesg for an insertion looks like:

[2336516.733051] usb 1-4: new full-speed USB device number 16 using xhci_hcd
[2336516.919895] usb 1-4: New USB device found, idVendor=0416, idProduct=5020
[2336516.919896] usb 1-4: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[2336516.919897] usb 1-4: Product: HID Transfer
[2336516.919898] usb 1-4: Manufacturer: Nuvoton
[2336516.927801] input: Nuvoton HID Transfer as /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/0003:0416:5020.0007/input/input24

Thanks.

derekatkins avatar Aug 20 '18 21:08 derekatkins

Hi,

You may find that if you recompile hidapi to use the libusb driver instead of the hidraw driver, the path property you get back could be constant enough for you.

Also, you say you don't have a serial number, but is there something in your device's protocol where you can write a non-volatile bit of data you could use as an ID?

todbot avatar Aug 20 '18 22:08 todbot

HI,

You may find that if you recompile hidapi to use the libusb driver instead of the hidraw driver, the path property you get back could be constant enough for you.

This is on Fedora. I am not (yet) building from source. It does depend on libusb, but I haven't checked to see how it's built, nor have I tried to rebuild it, yet.

Also, you say you don't have a serial number, but is there something in your device's protocol where you can write a non-volatile bit of data you could use as an ID?

Not that I'm aware of. It's a Sainsmart-16 relay board. The protocol appears to be pretty simple, to get and set 16 bits of data (to turn on and off each of the 16 relays). I know of no NV data, but the docs are pretty thin as-is.

derekatkins avatar Aug 20 '18 22:08 derekatkins

Here's a quick hidapi test program you can try: https://gist.github.com/todbot/12f4a26e840e3229a04aeac883fae332 Compile the libusb version and run it. You should see your devices listed with their paths listed. These paths are based on the USB port so shouldn't change on replug.

todbot avatar Aug 21 '18 03:08 todbot

Apologies, I am wrong. Disregard the above comment. I really thought the path on Linux libusb was consistent across replugs but I'm seeing it increment now as you originally describe.

todbot avatar Aug 21 '18 03:08 todbot

I know that the kernel has the information about what port the device is plugged into. It's printed clearly in the dmesg log, so the information is available -- it's just a question of reading it (or using it). I wonder if I can use a udev rule to "stabilize" the HID Path for the device?

derekatkins avatar Aug 21 '18 12:08 derekatkins

@todbot -- it looks like libusb_get_port_numbers(), possibly combined with libusb_get_bus_number(), will get me a stable identifier. I modified the libusb hid_enumerate to print out the bus/portnum-list and the results are 100% stable across plug-ins, even with the "path" changes on each plug-in. Unfortunately it does not appear that hidapi gives me access to the underlying libusb_dev.

derekatkins avatar Aug 22 '18 16:08 derekatkins

For the record, if I use the linux/hidraw version I could easily combine it with a udev rule to stabilize the path.

I think the problem here is hidapi using libusb_get_device_address() in make_path() instead of using libusb_get_port_numbers() and building the path that way. The address clearly changes over time (at every re-plug).

derekatkins avatar Aug 22 '18 17:08 derekatkins

C.f. https://github.com/signal11/hidapi/pull/406

derekatkins avatar Sep 04 '18 15:09 derekatkins