Native BSD backend using uhid #608
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#608
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?
I was curious about the pragmatics of supporting various BSDs. There seems to be a fairly common API for HID over USB on most common BSDs called
usbhidwhich is intended to be used with theuhidkernel driver for generic HID devices. Support for this is likely a necessity because several BSD ports oflibusbcannot be used with USB devices already reserved by a kernel driver.I'm too unfamiliar with HID myself to work on this at present, but is there anyone else willing to put in the effort to add this as a
hidapibackend?Duplicate of #543 ?
I don't believe so. There's more BSDs than just FreeBSD. And #543 is about the
hidrawcompatibility layer that is only on FreeBSD. This is about the HID layer that exists on multiple BSDs, though they have diverged a bit over the years. It may be feasible to manage that with some clever use of the preprocessor.For those who potentially want to start implementing this but don't know where to start (from HIDAPI POV) - here is an example me adding an experimental WinRT backend: https://github.com/libusb/hidapi/compare/winrt
Some relevant links for
uhid:https://man.openbsd.org/uhid.4
https://man.netbsd.org/uhid.4
https://man.freebsd.org/cgi/man.cgi?query=uhid&sektion=4
https://leaf.dragonflybsd.org/cgi/web-man?command=uhid§ion=4
I don't believe a native port for DragonFly is feasible unless they fix their UHID ioctl situation. It doesn't appear to support getting any information about the device behind the UHID device such as the USB device information. The other 3 still appear to be viable.
I am not so sure if there is any interest to have the uhid backend for FreeBSD as the existing libusb backedn works fine (libusb is part of FreeBSD now, and it is using FreeBSD's own libusb implementation with BSD license). So you can arguably call it native for FreeBD as well. hidraw backend seems to be more interesting for FreeBSD.
But I agree that it will be good to have uhid backend for NetBSD and OpenBSD, if it is possible. HIDAPI libusb backend for NetBSD/OpenBSD require rebuilding the kernel last time I checked, so it is not really that useful.
Further research reveals a problem with the current
hidapipublic API. There's a symbol conflict betweenhidapiandusbhid. The functionhid_initis used in both. At the very least this makes it impossible to combinehidapiandusbhidin the same program. I can see two options. Just don't useusbhidand hope the developer doesn't either or renamehid_initinhidapiwhich would break the library ABI.usbhidmainly exists as an optional BSD library to handle a subset of whathidapidoes but I was wanting to use its report parsing functionality.Instead of linking against
uhidusbhidHIDAPI could load it dynamically - that way we avoid symbol conflict.Also, for HIDAPI v1 I think
hid_initwill be renamed tohidapi_initialize(and it will become context-specific initialisation, similar to whatlibusbuses).Actually
uhidAPI is entirely contained in headers since it all goes throughioctl. What I was referring to it the optional high level libraryusbhid. I think it will be a non-issue since I can just avoid using it.I have done a fair amount of work on a NetBSD port via
uhidand have discovereduhidappears to be intended to be used withusbhidat the same time. TheuhidAPI appears to assign a single device with multiple report IDs to separateuhiddevices, and you are expected to get the report ID and descriptor from theuhidkernel APIs and to then parse them withusbhidor another HID parser to get the missing information for how to properly use the device.Is there even an API in
hidapito handle this? It seems to assume you can just pass any arbitrary report ID through the API and it will just handle it butuhidalready decides which one you are assigned and expects you to structure your reports in accordance to the exposed information. In the case of a device with multiple report IDs being split across multiple devices, how should I approach this?Excuse me for confusion, I really meant
usbhid.This is an interesting problem.
As per current HIDAPI design, each
hid_deviceis only as unique as VID/PID/SerialNumber/UsagePage/Usage combination (and it is not even always true for the UsagePage/Usage part - but that's a different story).HIDAPI doesn't support "device-per-report" abstraction as it assumes that a single device may support multiple reports (that's why a report ID is explicitly passed as part of data payload).
To support the
uhidabstraction, the HIDAPI implementation would have to do it under the hood:uhiddevice and use it to send/receive data.I don't see any better way.
I am considering an approach that opens all the
uhiddevices and uses their USB device information to construct a proper abstraction. We could use an internal per device lookup table to quickly see if there's a corresponding device for the requested report ID to know where to forward the IO requests to.I believe opening all devices at once would be overkill, if even possible (what about exclusive/shared access, read/write permissions, etc.?). Lookup table - yes, plus lazy device opening, only if/when needed.
Well, we have to do that anyway to properly enumerate devices, don't we? I only intended this to be done during an initial search for all the
uhiddevices connected to the same HID device or during enumeration.Ok. I am beginning to think a
uhidimplementation may be untenable due to serious limitations. Devices are opened exclusively. So how does one even do enumeration when another program might be using them? And I know of no other way to interact with the HID layer. I think I am done exploring this. I can see now whyhidrawon FreeBSD is considered a big deal.Nevertheless thanks for great investigation.
No one has check it this deep in context of HIDAPI.
I'll keep this ticket open for now. Maybe there will be more findings/details.
Don't fret. I at least did learn that
uhidis going to need a lot of help from other platform specific APIs to integrate well withhidapi. After looking atusbdevssource code on NetBSD I discovered you can usedrvctlAPI combined withusbAPI to enumerate theuhidparent device,uhidev. This avoids the major problem with the exclusive lock enforced by the kernel and you only have to open anuhiddevice to get the report descriptor now, which is just needed for the the usage fields. This can be left out if the device is already in use.That should do it for the majority of the work. I thought I might as well put my research into actual code.
I also looked into making a native one for OpenBSD but despite having similar APIs to NetBSD there is no apparent way to connect the
uhidparent device to theuhiddevices it is exposing so I cannot see myself being able to write a port that would be comparable to the level that the NetBSD one is at.Without the ability to explore the device relationships like this I cannot see a way to workaround the
uhidlimitations and design differences like I did for NetBSD. You need something akin to NetBSD'sdrvctlinterface which allows you to walk the device tree. I used this extensively in the port to avoid needlessly openinguhiddevices and also to connect the parent deviceuhidevto itsuhidchildren.All that said I believe a port to FreeBSD is still possible due to how advanced its
sysctlinterface is. It should be possible to explore the device tree sufficiently to get the needed information for ahidraworuhidinterface. In this situation it might be a good idea to share code between the two since they are operating on the same platform just different native APIs.@Youw Does the libusb backend on FreeBSD have to completely disable the HID kernel driver to work? I was considering that in some niche situations it may be good to have the option to use the native kernel interface since devices in some cases will expose multiple HID interfaces.
No. That is the beauty of FreeBSD USB stack. It exposes ugen driver along with uhid for generic USB HID devices, so that you can use libusb backend out of box.
Unfortunately Hans Petter Selasky passed away recently. If not I would ask him to explain how it works.
I see. How unfortunate. I think I will just work on OpenBSD backend and consider
uhidwork complete. I have an idea for how to make it work. It won't be ideal but it is still an improvement due to how limitedlibusbon OpenBSD is. Notable limitations would be that it would not be possible to enumerateuhiddevices that are already in use.Having a uhid backend for OpenBSD will be great. Thanks. As you mentioned, it will still be much better than libusb backend.
In fact I consider HIDAPI libusb backend not so useful (in fact kind of useless) for NetBSD/OpenBSD users.
Right, closing