Add hidraw backend for FreeBSD #730
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!730
Loading…
Reference in a new issue
No description provided.
Delete branch "aokblast/use_hid_raw"
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?
FreeBSD support hidraw in Kernel from 13.0.
By using libusb only, we can only see the HID device from usb. To address this, we implement hidraw backend for FreeBSD.
Just like Linux use libudev to handle usb specified HID stuff (like Manufacture), we use libusb to handle it.
Sponsored-by: FreeBSD Foundation
Related to #274
Fixes #543
Assisted-by: codex:gpt-5
Currently, some stuff like the Report Descriptor parser and error registry routine are copied from Linux and I think they are platform independent. Can we create a common directory or hidraw directory in code then put them inside?
Have tested by the hidtest program.
typo?
@ -0,0 +1,46 @@cmake_minimum_required(VERSION 3.6.3...3.25 FATAL_ERROR)just to double-check - is there a minimum version of libusb that is required (at least to compile/API-wise)
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>what if there are muktiple devices with the same VID/PID? is there a better way to match the device?
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>since there are no other return statements I'd call it
end, notfailed@ -0,0 +1,1356 @@#include <dev/evdev/input.h>I'm no expert of FreeBSD, but isn't there a better way to enumerate all devices of a specific class? (like we do it for hidraw on Linux?)
If this is the "FreeBSD-way" - just confirm it
No more comments
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>I am not working on USB stuff quiet often. Is there any possibility to have same vendor id and same product id but different manufacturer string?
We cannot use serial number to distinguish them because a half of devices on my environment don't have serial number.
I can use bus and port number to distinguished between them on local machine. But that will needs a for loop each time to enumerate a usb device. I think libudev do the same thing.
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>libusb_open_device_with_vid_piddoes that under the hood anyway.Practically unlikely, but very possible - I had identical devices with different FW targeted for different countries, and one of the manufactures was written in CN.
Also, when you have multiple devices, one of the might be already exclusively open by some other application, and libusb_open might simply fail.
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>Oh, that is a good point! Thanks for your explanation! And fix it.
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>That is also the thing I would like to confirm. Each of the usb device have the specified usbhid deivce file. But in other type of the hid device (e.g. iic), it maybe not the case. Do you think fstat to check if file "/dev/hidraw%d" exist a good idea?
Also, I can ask the author of FreeBSD hidraw driver to confirm this.
Thanks for @Youw your review:).
Then, What is your opinion about this?
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>BTW: when I mentioned linux/hidraw backed - it actually uses libudev for enumeration, and that's not exactly what I meant.
On Linux there is
/sys/class/hidrawdirectory, which contains only hidraw devices, and it is enough to enumerate all/sys/class/hidraw/hidraw*files to get list of all devices.Otherwise, when devices are getting connected and disconnected, it is possible that
/dev/hidraw2exists, but/dev/hidraw1- does not, due to being disconnected at some point.I thinjk that is a good idea, but I don't think it really is nesessary to do so in scope of this PR.
There are really lots of stuff which I'd like to share among beckends, and I think it is going to be some refactoring after all.
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>I iterate all sysctl "dev.hidraw" subnode like the following code:
https://gist.github.com/aokblast/1aaf06e429899021320d045ff5387db9
The result is as the comment shows.
Then I match all dev.hidraw.%d by sscanf.
Nice. This will address the following issue.
Oops. I forget we have udev-devd stuff. Maybe we should use udev also?
I lost context here. What for? Seem like you have all the functionality implemented already. Aren't you?
Yes, all functionality is fully implemented. I am just thinking if we should use libudev make hidapi more portable.
First test under FreeBSD 14.1 Release, under a physical machine (Chuwi mini PC, Intel J4125 CPU, 8GB RAM, 256GB SSD)
There are a few compiler warnings.
Fix it:). Forget to fix the warning.
Somehow hidtest-hidraw will seg fault with the Microchip Simple HID example.
Thanks. The compiler warnings are gone.
The Segfault issue is still there though.
Can you show me where it cause segment fault?
You can use something like lldb with (sudo lldb <binary_location>). Then use r to run.
This is with Cmake build. Somehow it only build one version of hidtest.
More detailed build log using CMake.
At least the shared version of hidtest will depend on the new FreeBSD hidraw backend.
lldb does not seem to give much info.
After this is fixed, next test will be using hidapitester.
I do some small fix. Can you help me on testing this?
No more crashing. But somehow it cannot open any devices.
Please load the hidraw driver first by
I have done that but somehow the HID devices are not recognized by hidraw driver, only by ugen and uhid.
I found the reason. There are two usb hid driver in FreeBSD. One is uhid, another is usbhid. Only usbhid is compatible with hidraw. Also, unload and try to load usbhid is useless. The effective way to enable usbhid is through
Then when next time it is auto-loaded, the usbhid will replace the uhid:
If uhid is not auto reload:
If udev is generally available on FreeBSD and can be used in a similar way as in Linux/hidraw - it is probably a good idea to do so. And probably linux shouldn't be used in that case at all.
But I imagine that is a large change to this PR, so it is up to you.
Thanks. This method works to get hidraw to bound to the device.
However,
hidtest-hidrawis still problematic --> it cannot be stopped and keep repeating with the test device.If I unlug the test device and plug in another device, then it is working.
@aokblast
Looks like it is getting close. To reproduce the above issue, you can probably change hidtest example to open one of your HID device instead of 04d8:003f.
Using hidapitester and the FX2HID example to test.
Unfortunately the new hidraw backend does not work. The old libusb backend has the issue mentioned in #274.
The loop problem should be fix. Still investigate the read error.
Emm I cannot reproduce the problem. If the hid interrupt sucessfully triggered. I can receive the event by hid_read. At least I have tested with my keyboard.
Yes this has been fixed.
If I use the original fx2hid example (loop back of two bytes output report and input report), it seems to me this PR works fine.
http://janaxelson.com/hidpage.htm
http://janaxelson.com/files/fx2hid.zip
I read the issue he describe. So you think it is because usbhid does pass interrupt that report more 64bytes?
No, I am not so sure why this PR (FreeBSD usbhid/hidraw backend) does not work with HID device with reports length greater than 64 bytes.
The original libusb implementation under Linux/FreeBSD will suffer from #274. #728 is supposed to fix that but unfortunately it does not work for me.
Just wondering if which version of FreeBSD you are using to test this PR. Thanks. I will try to test with FreeBSD 14.2 Release as well to see if that makes any difference.
@wulf7
It will be greatly appreciated that you can take a look at this PR. Thanks.
Just wondering if FreeBSD hidraw implementation has any limitation with regard to report length. Thanks.
I think it is the problem but I have no way to verify it.
The hidraw works as follow:
@mcuee If I would like to build the test environment like you, I have to buy a development board like this, right?
I tested this PR with 15.0 which is compiled 1 weeks ago.
Yes, that is the one I am using now.
If you buy from AliExpress, maybe it will be even cheaper.
@ -0,0 +488,4 @@}libusb_free_device_list(list, 1);return handler;before return:
if (handle == NULL)- register_global_error@ -0,0 +1,1356 @@#include <dev/evdev/input.h>libusb doesn't specify that it would set the
errno@ -0,0 +1,1356 @@#include <dev/evdev/input.h>I don't see where we're registering device error in case of failure
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>this is a copy-paste and not accurate
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>we set a
device_pathinside ofhid_open_path, and user may provide a simlink, which may not be in format/dev/hidrawXI'm thinking maybe resolving symlinks would help inside of
hid_open_path, but I don't know if there could be other special files that are hidraw devices but not located at/dev/hidrawXbut otherwise a valid hidraw devices...(at least on Linux I believe something like that possible with udev rules)
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>and looks like we're leaking
devinfohereand why do we skip the first element?
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>Fix first problem.
For second problem, please see the comment at hid_create_device_info_by_hidraw_idx.
This function return the last element. Before return, it set the next element of the last element as the first element.
So using devinfo->next actually get the first element. Also, we have to set the devinfo->next = NULL as it point to the first element. That is the reason why we have infinity loop previously.
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>ignore Archlinux failure and revert your CI changes - not related to this PR - master is failing as well, I'll check
I am stupid. The get report and set report should return the actual length. @mcuee could you please help me test again?
Somehow it still does not work.
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>HID_INPUT_REPORT ?
@ -0,0 +190,4 @@if (hid_get_name_from_mib(mib, items, name_buffer, sizeof(name_buffer)) == 0)return -1;return sscanf(name_buffer, "dev.hidraw.%d", &result) == 1 ? result : -1;you may add "dev.uhid.%d" nodes here too as they are compatible with hidraw(4) in uhid mode on binary level.
@ -0,0 +629,4 @@info_template->next = NULL;hid_device_handle_bus_dependent(&devinfo, info_template, idx);error = ioctl(fd, HIDIOCGRDESCSIZE, &desc_size);Please, do not mix uhid and hidraw modes. If you choose uhid mode, replace HIDIOCGRDESCSIZE/HIDIOCGRDESC ioctl pair with HIDRAW_GET_REPORT_DESC
@ -0,0 +895,4 @@int res, desc_size = 0;/* Make sure this is a HIDRAW device - responds to HIDIOCGRDESCSIZE */res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size);In uhid mode it is better to execute e.g. HIDRAW_GET_REPORT_ID ioctl to test availability.
@ -0,0 +924,4 @@return -1;}bytes_written = write(dev->device_handle, data, length);Strip leading zero for unnumbered reports. See
writesection of FreeBSD hidraw(4) man.Don't forget to account for this byte in return value.
HIDRAW_GET_REPORT and HIDRAW_SET_REPORT callers should strip leading zero for unnumbered reports too
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>updated my comment: should be
errornoterrno@ -0,0 +924,4 @@return -1;}bytes_written = write(dev->device_handle, data, length);@wulf7 are you sure?
I believe this entire implementation should be about
hidraw, notuhid, and according to https://man.freebsd.org/cgi/man.cgi?hidraw(4)I.e. - no strip.
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>thans @wulf7 for the hint
We do not want to use
HIDRAW_GET_REPORT_DESChere, since it switches operation mode touhid.Use
HIDIOCGRDESCinstead.Sorry about the confusing code. I would like to clarify first that I think using hidraw mode is better for supporting non-usb hid device (e.g. iichid). I clean up the code so that there is hidraw mode only.
@ -0,0 +1,1356 @@#include <dev/evdev/input.h>@mcuee Could you help me test on this. I have apply the fix in my latest code.
uhid mode supports non-USB HID devices too. Both modes are comparable.
If they are compatible, then what point of using both?
HIDAPI is intended to be as thin wrapper as possible for HID device drivers (libusb backend is a different story, of course), with uniform API across platforms.
The way I see it - hidraw mode has simpler and more alike API for HIDAPI to be used as is, when uhid requires additional tracking of current operational mode and handling report IDs in some cases.
Do I miss something about uhid worth mentioning in this scope?
They are comparable but not compatible.
uhid API may be used with old uhid(4) driver.
hidraw API is simpler for implementation and may reuse existing Linux support code.
FreeBSD hidraw(4) supports both. Choose one you prefer but do not mix them.
Now after switching to hidraw mode, it is better to replace all remaining HIDRAW_* ioctls with HIDIOC* ones.
The only exception may be HIDRAW_GET_DEVICEINFO as it provides device serial number which is unavailable through hidraw API
Ooops. FreeBSD hidraw API is outdated. It misses HIDIOCSOUTPUT and HIDIOCGINPUT ioctls.
Although it is easy to implement them, they won`t hit the tree until FreeBSD 14.3 or even 14.4.
So, the uhid API is the only option for 14.2 and earlier.
Hmm, what about FreeBSD 15.0-Current? Does it have the two IOCTLs you mentioned?
@aokblast is indeed using FreeBSD 15.0-Current for testing.
Not yet. I made a patch with both ioctls(). It is only compile tested. I'll commit after one has tested it.
hidraw.patch.txt
The IOCTLs have been added to FreeBSD on 27-April-2025.
github.com/freebsd/freebsd-src@fd6690e2d5Can I do it seperately? I think it needs some version check code to enable it.
BTW, thought I don't buy the chip you have, I found 1 stm32f103 in my bedroom yesterday. Then I try to reproduce your environment.
I have the following questions:
Is the wMaxPacket under 64bytes with multiple transport of blocks or wMaxPacket > 64?
Is your condition as following?
If so, I can reproduce it throught stm32f103 as I set the Input Descriptor to 1023 bytes.
Or
Also, they have been merged to 14-STABLE today.
Yes. That can be another follow-up PR.
Yes, STM32 MCU is a good one to use.
No matter the wMaxPacket number, but rather the HID report length (Input report or Output report in my test, not so sure about Feature report).
BTW, my device is a high speed USB device (Cypress EZ-USB FX2LP). But it does not matter.
HID report length greater than 64 bytes will cause issus to this PR. The current libusb backend also got the issue.
I am using hidapitester to carry out the test so it is not that easy to differentiate the two cases you mentioned.
In any case, it is good that you can at least reproduce the issue (first case). You can also try to change 1023 to something like 80, 128 or 512 to see if the issue still exist.
Then you can try to debug the issue to see if it is related to FreeBSD hidraw implementation or your PR.
Oops, I thought you are using FULL speed device (64byte packets) with hid descriptor larger than 64byte. That is why I ask you what is the value of wMaxPakcet. Because I though you are using an device unable to configure from stm32cubemx(If you type you want to configure packet size higher than 64, you needs to be the HIGH speed device)
So you are using the HIGH speed? If so, I needs extra hardware to test it. HIGH speed needs MCU have clock higher than 120Mhz. It is impossible for stm32f103. I am trying to find an available stm32f405 to test it.
In the current modification, I support HIDIOC family ioctl for all and use ifdef to provide backward support, you can test it with the new 14-STABLE or 15-CURRENT but I thought they will have the same result.
Besides, I make hidtest compiles hidtest_hidraw and hidtest_libusb.
My FW is based on this one, with Cypress EZ-USB FX2LP.
http://janaxelson.com/hidpage.htm
http://janaxelson.com/files/fx2hid.zip
USB Descriptors
Full source codes and binaries:
fx2hid_128bytes_report.zip
Using FreeBSD 15 Current snapshot 1-May-2025.
So we can see that the hidraw backend does not work from this PR. But at least it does not have regression on the libusb backend since the problem is the same as current hidapi git in terms of libusb backend.
@aokblast
Now I am clean of the fault, it is the same as what you see. No timeout, immediately exit.
Ok, I see. I should take some time to get a device able to afford USB HIGH speed
Are you saying that you no longer have issuses with your own full speed STM32 MCU implementation if the HID Input/Output report length are larger than 64 Bytes? Or you still have the issue?
If possible, please post the USB descriptors of your device and the test results. Thanks.
More about the test device.
Forcing the device to run in Full Speed mode and now this PR works.
@aokblast
Now this PR is much better -- at least it works for USB Full Speed device under FreeBSD 15 Current. I will test under FreeBSD 14.2 Release later.
@wulf7
Just wondering if you have some inputs in the test results. Thanks. Just wonddering if you have some tests with regard to High Speed USB HID devices? Thanks.
Yes, hid full speed with larger than 64 byte report works.
Code and result:
usbconfig -d0.3 dump_all_desc:
Report Descriptor:
@aokblast
If you can, please get the FX2LP break-out board from Taobao/AliExpress/Amazon/etc. It is pretty cheap.

FW binary and source codes are here.
It is a quick minor modification of Jan Axelson's FX2HID example from here.
http://janaxelson.com/hidpage.htm
http://janaxelson.com/files/fx2hid.zip
There may be a bit of challenge if you want to rebuild the source code as it may require a full version of Keil C51 compiler. I happen to have access to a pretty old version of Keil C51 compiler at work. I am not so sure about the efforts to port the code to use the free sdcc toolchain. It may be possible because of the nice sdcc based libraries.
Jan's HID page has some other FW as well, for example, for Microchip USB PIC18. I was able to use that as a base for my other HIDAPI testing but I have not figured out how to increase the HID report size above 64 bytes with that FW. I have the PIC18F87J50 USB PIM (free tool from Microchip many years ago).
More testing device discussions:
Update with the main git branch to trigger another CI run.
@cederom and @dl8dtl
Since you two are the FreeBSD power user I know of, please help to check if you can give this PR a try. You need to use FreeBSD 14 Stable or 15 Current. Thanks.
This has something to do with avrdude as well. For example, if it works, it is a potential workaround for Issue #274.
FreeBSD HIDAPI is now based on libusb, so it is affected by the Issue #274.
@mcuee builds okay, could you please provide test steps, its a long thread and I am quite short on time sorry :-P
Great.
Test steps: make sure you use the hidraw driver.
Test with your normal generic USB HID device using hidapi's built-in hidtest and hidapitester. This should be okay.
https://github.com/todbot/hidapitester
Test with USB Full Speed HID device with >64 Bytes HID report size. This should be okay.
Test with USB High Speed HID device with >64 Bytes HID report side. This somehow failed for my test device.
I have mentioned my test device in the comments above.
I just ordered one. Let's seen when it arrives.
I am in Canada right now. I get the USB3320 and try to setup the experiment environment with my stm32h750. I will test with it later after my experiment environment is setup with other patches you have mentioned.
@aokblast
That will be great. It will be good to test this PR with different test devices.
I tend to believe my modification FW may not be totally correct (interrupt transfer for the IN/OUT endpoint may be correct; Control Transfer to the IN/OUT endpoint may need to be checked). I am not a progammer myself and my main contributions for the Open Source projects (eg: libusb, libusb-win32, libusbK, avrdude, pyusb, libusbdotnet, libftdi and OpenOCD) are mainly on the testing and technical side.
STM32 is a popular ARM Cortex MCU family and STM32H750 is a powerful one, very good for libusb and hidapi related testing.
If you need Super Speed USB testing device (probably not needed for hidapi but more for libusb project), I will highly recomemend EZ-USB FX3 board, CYUSB3KIT-003 EZ-USB™ FX3 SuperSpeed explorer kit, at US$$45.93 plus shipment.
https://www.infineon.com/cms/en/product/evaluation-boards/cyusb3kit-003/
Example test FW used in libusbK project, based on Cypress (now part of Infineon) FW examples.
https://github.com/mcuee/libusbk/tree/master/BmFW/CYPRESS_FX3
@aokblast
Just wondering if you have any updates on this PR. Thanks.
Just update the branch to trigger a new build.
It will be good to move this PR forward. May need more testing and reviews.
I am on FreeBSD 14.4-RELEASE AMD64 just in case :-)
@Youw
Just wondering if it is worth asking Github Copilot to review this PR.
Sorry that I was super busy in previous 6 months. I am back now and will start to setup the hardware for usb development on next monday.
Pull request overview
This PR adds a new FreeBSD HIDRAW backend to HIDAPI so FreeBSD (13.0+) can enumerate and access HID devices via
/dev/hidraw*, while still leveraging libusb for USB-specific metadata (e.g., manufacturer string).Changes:
freebsd/backend implementation (hid.c) and integrate it into both CMake and Autotools builds.hidrawandlibusbvariants on FreeBSD (hidtest + testgui).-libusbconvention.Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 18 comments.
Show a summary per file
freebsdhidraw andlibusbbackends.freebsd/.*-libusbnaming.libhidapi-libusb.la.hidtest-hidrawandhidtest-libusbon FreeBSD.hidtest_hidrawon FreeBSD whenhidapi::hidrawexists.freebsdhidraw library.freebsd/.freebsdand add FreeBSD Makefile/config vars.freebsd/subdir and install FreeBSD pkg-config files for hidraw+libusb.Comments suppressed due to low confidence (1)
configure.ac:249
pc/hidapi-hidraw.pcandpc/hidapi-libusb.pcwhenos == linux, but the top-levelMakefile.amnow installs those pc files for FreeBSD as well. This will breakmake/make installon FreeBSD because the.pcfiles won't be configured/generated. Update this conditional to include FreeBSD (or generate the correct pc files based onOS_FREEBSD).💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
@ -0,0 +1,46 @@cmake_minimum_required(VERSION 3.6.3...3.25 FATAL_ERROR)pkg_check_modules(libusb-1.0 ...)uses a prefix containing a hyphen, which is not a valid CMake identifier and typically breaksFindPkgConfig(it tries to create variables/targets likelibusb-1.0_*). Follow the pattern inlibusb/CMakeLists.txtand use a valid prefix (e.g.libusb) and linkPkgConfig::libusb.@ -0,0 +1,1356 @@#include <dev/evdev/input.h>In the
BUS_USBbranch, the return value ofhid_get_udev_location_from_hidraw_idx()is ignored, butbus/addrare then used even if the lookup failed (they're uninitialized). Also, onlibusb_get_device_descriptor()failure the handle is closed but the code continues and useshandlerafterward. Check both errors and bail out before usingbus/addror a closed handle.libusb_get_string_descriptor_ascii()returns a negative libusb error code on failure, not0. The currentlen == 0check will miss errors. Also,mbstowcs(..., sizeof(namebuffer))passes a byte count instead of the number ofwchar_telements and can overflownamebuffer. Validatelen > 0and pass the correct element count (and ensure null-termination) beforewcsdup().templateis allocated withmalloc()and then partially initialized. Any fields not explicitly set (e.g.,usage_page,usage,bus_type, etc.) remain uninitialized and may be copied later. Prefercalloc()(ormemset) and check for allocation failures before dereferencingtemplate.Both
mbstowcs(namebuffer, ..., sizeof(namebuffer))calls pass a byte size instead of the number ofwchar_telements. This can overflownamebuffer(256 elements) becausesizeof(namebuffer)is typically 1024 bytes. Usesizeof(namebuffer)/sizeof(namebuffer[0])(and handle truncation / ensure termination) beforewcsdup().hid_get_report_descriptor()returnsbuf_size(asize_t) from a function returningint. This can trigger warnings and truncation on large descriptors. Follow the pattern used by other backends: clamp toINT_MAXif needed and return(int)buf_sizeafter copying.Typo in comment: "Semilar" should be "Similar".
hid_create_device_info_by_hidraw_idx()always freestemplateatend:but returnscur. Ifget_next_hid_usage()never yields a usage (loop not entered),curis stilltemplate, so this returns a pointer to freed memory. Rework the list construction/cleanup so the returned node is never freed (and consider avoiding the circular-list hack).hid_get_device_info()ignores the return value ofrealpath()and the result ofsscanf(). Ifrealpath()fails or the path doesn't match/dev/hidraw%d,idxwill be uninitialized and passed intohid_create_device_info_by_hidraw_idx(). Check both calls and register an error on failure.The VID/PID filter is incorrect:
(vendor_id != tmp->vendor_id && product_id != tmp->product_id)will keep devices when either VID or PID matches. It should filter each field independently (like the Linux backend). Also, when the device is filtered out,tmp(and its linked list) is leaked because the codecontinues without freeing it.freebsd/hid_find_device_handle_by_bus_and_port()passeserrnotolibusb_strerror(), butlibusb_get_device_list()returns a libusb error code inerror. This can produce a misleading message (anderrnomay be unrelated). Use the libusb return code when formatting the error.libusb_free_device_list(list, 0)does not unref the devices in the list and can leak references. The rest of the codebase useslibusb_free_device_list(..., 1)after enumeration; do the same here.hid_get_udev_location_from_hidraw_idx()writesbuff[len] = '\0'aftersysctlbyname(). If the returnedlenequalssizeof(buff), this writes 1 byte past the buffer. Guardlen(or ensure null termination by reserving a byte / clamping).When a
serial_numberis provided,wcscmp(serial_number, cur_dev->serial_number)will crash ifcur_dev->serial_numberisNULL(which can happen whenhdi_uniqis empty). Add a null check before callingwcscmp()and only compare when a serial is present.@ -0,0 +19,4 @@#include <sys/param.h>#include <sys/sysctl.h>#include <sys/user.h>#include <unistd.h>This file calls
ioctl()but does not include<sys/ioctl.h>. On some toolchains this will fail to compile (implicit declaration is an error with modern C standards / -Werror). Add the proper include near the other system headers.@ -0,0 +525,4 @@buff[len] = '\0';return sscanf(buff, "bus=%d hubaddr=%d port=%d devaddr=%d interface=%d",bus, &hub_addr, &port, addr, inf) == 5;}After the second
sysctlbyname(),buff[len] = '\0'has the same potential off-by-one overflow iflen == sizeof(buff). Additionally, thesscanf()parses 5 fields but passes the sameaddrpointer for multiple outputs and then checks== 4, so the parsed location values will be wrong. Guardlenand parse into distinct variables with the correct expected conversion count.@ -0,0 +746,4 @@libusb_exit(global_usb_context);global_usb_context = NULL;}return 0;hid_init()callslibusb_init(&global_usb_context)unconditionally andhid_open_path()callshid_init()each time. This can reinitialize libusb repeatedly, overwriteglobal_usb_context, and leak previous contexts. Mirror the libusb backend pattern: only calllibusb_init()once when the context is NULL, and inhid_exit()setglobal_usb_context = NULLafterlibusb_exit().@ -0,0 +754,4 @@struct hid_device_info *root;struct hid_device_info *head;struct hid_sysctl_iter iter;hid_enumerate()doesn't callhid_init(), but the enumeration path can call into libusb (viahid_device_handle_bus_dependent()->hid_find_device_handle_by_bus_and_port()). Without initializing libusb first,libusb_get_device_list()may fail/behave unexpectedly. Callhid_init()early inhid_enumerate()(as other backends do) and handle/init errors appropriately.Although some reluctance it seems to provide reasonable and constructive review at least there will be some hints :-)
I don't see any huge change over behavior. The comments from AI are just missing boundary checks.
Hi. I just take a look at this again. Could you please try to make your payload 128bytes?
@aokblast
Yes, I will try to carry out some tests over the weekend and report the results from FreeBSD 15.0 release.
Here are the latest test results under FreeBSD 15.0 release.
Summary of the above test for the EZ-USB FX2LP modified Generic HID example with 128 Bytes report size (high speed USB device).
Sanity check under Windows, with latest hidapi git.
Does output of payload less than 128 bytes work? FreeBSD check if the device can handle the report by checking the size in report descriptor. You report descriptor shows that we can only handle 128 bytes.
usbhid allocates internal buffers based on report size. They are 128 bytes long in that case. 129 bytes wont fit them.
There is a difference between input and output unnumbered reports.
In Linux and hidraw after than leading byte of output unnumbered report is stripped so it becomes a 128 byte. But input reports still go AS IS.
This is under Linux.
Linux hidraw backend does not work if I send 64 bytes payload.
Linux libusb backend does work if I send 64 bytes payload.
Ouch. It seems that input is really 128 bytes no 129.
That should be the correct one.
The report ID 00 for the output report is not really on the wire. It is more needed because of Windows native HID API.
The report ID 00 is also not on the wire.
Strange. I have just tested FreeBSD hidraw on MBP8,1 with USB touchpad. Touching of surface with all 10 fingers gave me 338bytes packets successfully received.
Good one. Do you have any High Speed USB HID device?
As I mentioned before, "forcing the device to run in Full Speed mode and now this PR works". So your device is most likely a Full Speed USB device.
Latest version of VirtualBox does not seem to allow me to disable EHCI support so I can not carry out the test. I am not so sure if I still have working USB 1.1 Hub to try.
On the other hand, High Speed USB HID device is probably rare. In that case, we may still want to merge this PR first and then debug the issue later.
Maybe it has nothing to do with this PR but rather the hidraw (usbhid driver) of FreeBSD.
It is Full Speed device.
man ehcitells us abouthw.usb.ehci.no_hsloader tunable that disables High Speed.Try to add
hw.usb.ehci.no_hs="1"to/boot/loader.confand reboot after thanGoing back to original FX2HID example from Jan Axelson, this PR still does not work.
http://janaxelson.com/hidpage.htm
http://janaxelson.com/files/fx2hid.zip
fx2hid.zip
No issues under Windows.
No issues under FreeBSD with the libusb backend.
This PR still does not work.
Thanks for the tip. I will try this soon.
Somehow this does not work. The device is still enumerated as a high speed USB device.
The following command seems to disable EHCI driver completely, but then somehow I cannot attach the FX2LP USB HID device. Only a generic Atmel STK600 can be attached.
Okay, this seems to work.
Now it seems to work.
Going back to the device with HID Input/Output report size of 128 bytes.
It seems to this PR will work fine as well.
Good thing -- PR #728 also works fine.
@aokblast @wulf7 and @cederom
So basically this PR works with Full Speed USB HID device, but somehow it does not work with High Speed USB HID device. It may not be an issue with this PR, but rather the hidraw driver issue under FreeBSD.
@Youw
I am still in favour of merging this PR after your review. The reason is that High Speed USB HID devices are not that common. But you can decide.
It is definitely FreeBSD usbhid issue or may be bad interaction between FreeBSD and VBox.
I will test with a physical machine tomorrow.
I will do a quick reviw from the AI comment again and do rebasing tomorrow.
Ah yes. Sorry for missing this.
I just rebase and clean up the commit. All AI's feedback is fixed.
Preparing to test with a physical machine, an Chuwi mini PC with Intel J4125 CPU.
Test log.
Edit: this test is not using the latest push today but previous version. I will test that later.
Interestingly it works every other time. Looks like there may be a data toggle related issues.
Supposedly EZ-USB FX2LP can handle data toggle bit automatically.
The above is not the issue of this PR though. libusb backend has the same issue. So does PR #728.
Edit: this test is not using the latest push today but previous version. I will test that later.
Using the latest git push of this PR #730.
As expected, no changing of the test results.
Now I will continue the 128bytes FX2HID mod firmware testing.
Unfortunately this PR does not work.
PR #728 also does not seems to work either. Strange.
Interestingly hidapi git libusb backend (same as PR#730 libusb backend works a bit better and returns 64 bytes of data. But there is an offset of 64 bytes.
Unfortunately I am not so sure how to force it to Full Speed mode using the physical machine.
I already applied the changes to /boot/loader.conf and reboot the machine.
The following bootloader.conf does not work either even after the reboot.
This looks like a firmware bug, right?
Not really in this particular case.
More like a FreeBSD USB bug to me since other Operating Systems have no issues.
Also EZ-USB FX2LP is supposed to handle data toggle correctly from HW side.
BTW, this original FW comes from Jan Axelson, no modification from my side.
If possible, please get the cheap EZ-FX2LP board from online store and try yourself.
For anyone interested in High Speed USB development and testing, EZ-USB FX2LP is highly recommended. The board is pretty cheap to get from 3rd party vendors (cheap clone of CY3689 EZ-USB FX2LP Discovery Kit)
https://www.infineon.com/assets/row/public/documents/24/44/infineon-cy3689-ez-usb-fx2lp-discovery-kit-quick-start-guide-usermanual-en.pdf
For anyone interested in Super Speed USB development and testing, EZ-USB FX3 is highly recommended. The board is not that cheap but still manageable. It used to be at around US$50 but now it is at US$90.15.
https://www.infineon.com/evaluation-board/cyusb3kit-003
I am stilll using VirtualBox VM under Windows 11 for this test, but I have switched the VM back to the default USB configuration (OHCI + EHCI).
Then I use my trusted modified Generic PIC USB HID example (modified from the Lakeview Research Generic HID example to add Input/Output/Feature report IDs). It is a Full Speed USB device.
It was mentioned in the following discussion.
https://github.com/libusb/hidapi/discussions/590
FW source code and old libusb test codes are here.
https://github.com/mcuee/picusb/tree/master/lvr_genhid_mod
The device works well under Windows.
It also works fine with this PR under FreeBSD VM.
Just buy a EZ-USB FX2LP. I spend two days on configuring stm32h750 + usb3320 and it fails. I think there are some design flaws on stm32h750 as some pin output doesn't follow the ulpi standard.
See: https://community.st.com/t5/stm32-mcus-embedded-software/stm32h750-usb3300-no-signals-on-ulpi/td-p/225293?fbclid=IwY2xjawRdSk5leHRuA2FlbQIxMABicmlkETF1eVg0M2d2OENpV1lWdnpjc3J0YwZhcHBfaWQQMjIyMDM5MTc4ODIwMDg5MgABHr4fjotlcri4aRfLeR3qxxa3_rOWLG8XdiaZHQXLlSejiReV3U-u7F052oj-_aem_DLqIO7VIk_LDjl6YhWkqEw
Hi,
I received the EXUSB FX2 last week. I spent the weekend setting up the toolchain, since the SDK is very outdated and Infineon no longer maintains or provides the download link. I’ve fixed the firmware now.
The issue turned out to be quite simple: you forgot to arm EP1OUT the first time. To fix it, add:
EP1OUTBC = anynumber;
at the end of TD_Init().
@mcuee I also did some experiments. FX2 is packet-based, which means if you set MPS = 64 and the report size = 128, it will not work correctly when the device wants to send a short packet (< 64 bytes). The reason is the following:
xHCI assumes there will be 2 packets (128 / 64), so it sends the following sequence to the device:
IN token with size = 64
Device replies with 64 bytes
Host ACK
Another IN token with size = 64
Device replies with another 64 bytes
Host ACK
This completes a full cycle for receiving a 128-byte report from the device.
However, if the device sends a short packet, the sequence becomes:
IN token with size = 64
Device replies with a short packet (== 64 bytes)
Host ACK
Another IN token with size = 64
Device never replies, so xHCI never completes the transfer
As a result, the receive operation eventually hangs and fails.
@aokblast
Thanks a lot for the updates. Let me digest and check again.
You are absolute right here. I have seen strange issues previously with random data for the initial run. I am not the author of the origina FX2HID code. The original auther is Jan Axelson (author of the book "USB Complete").
I am not so sure about this one. Different OS may be different as well. Let me check.
@aokblast
I have some modified EZ-USB FX2HID firmware as well. I am not a programmer myself, please check as well. Thanks.
Modified version of the fx2hid firmware mods (with bug fixes in
TD_Initfunction)fx2hid_64bytes.zip
fx2hid_128bytes_report.zip
fx2hid_512bytes_packet.zip
fx2hid_512bytes_report.zip
fx2hid_1024bytes_packet.zip
Common files from Cypress
Target.zip
@aokblast
Infineon/Cypress CY3689 and CY3684 download links (you need to register). The clones are mostly copy of CY3689.
https://www.infineon.com/products/universal-serial-bus/usb-2-0-peripheral-controllers/ez-usb-fx2lp-fx2g2-usb-2-0
@aokblast
BTW, EZ-USB FX2LP is a High Speed USB device, do you mean to say EHCI and not xHCI?
Another thing, I have tested different firmwares. So you may get confused here.
https://github.com/mcuee/picusb/tree/master/lvr_genhid_mod
I will carry out tests under FreeBSD over the weekend.
USB standard is a little bit confusing. You actually attached a USB 2.0 device to xHCI. But since the xHCI controller is a xHCI controller + eHCI controller internally, so...
I found a bug in the FreeBSD xHCI implementation that cause the data only receive bi-transfer in <= 64 byte case. Please also apply this patch while you are testing. https://reviews.freebsd.org/D57146.
I have tried send 64 bytes (report size is 64), send 63 bytes (report size is 64), send 128 bytes (report size is 128), send 63 bytes (report size is 128).
Send 64 bytes (report size is 128) can not be resolved as the problem I have explain previously. There is a flag in libusb call LIBUSB_TRANSFER_ADD_ZERO_PACKET that can solve this problem.
@mcuee 3 bytes also work in both 64 and 128 bytes report. 2 bytes won't work as it is a hard limit in FreeBSD hidraw interface. If you need a ISO image to test, I can build one for you with my patch.
@aokblast
An ISO image (x86_64) will be great. Thanks.
Ok, will build one later. I just merge my patch upstream and need times to build world and kernel.
Hi, I just send a link to your email. Please take a look.
@aokblast
Great, now this PR works perfectly under your FreeBSD 16.0 Current build (tested with VirtualBox VM first).
PR #728 also works fine and hidapi git has the issue with #274.
Indeed 2 bytes will not work with FreeBSD hidraw backend. libusb backend works fine (git or PR #728)
I will carry out more testing later today and tomorrow.
Thanks! Hope we can merge this patch ASAP:).
Going back to the Generic HID PIC FW example (Full Speed USB device), there are no issues.
Going to the original Generic PIC FW (unmodified, from Jan Axelson, Full Speed USB device) with two bytes reoort, it also works.
@aokblast
I have approved this PR.
@Youw
Please review and I think this is a good addition to hidapi under FreeBSD. Since this is a new backend, it does not affect much other codes. Issues specific to this backend can be fixed within this backend.
@wulf7
Please re-review as well. Thanks.
@aokblast
BTW, somehow your ISO image only works under VirtualBox VMs, I could not install it under an Intel N100 mini PC, not so sure about the reason (kernel panic). Therefore I cannot test it under physical machine as of now.
Just FYI only.
Now I am lazy to build FreeBSD using source code. I only did that a few times when HPS was developing the new FreeBSD USB Stack many years ago.
Hi, is there any crash log?
LGTM
Let me capture the crash log over the weekend. I will also compare with FreeBSD 16.0-Current Snapshot.
https://download.freebsd.org/ftp/snapshots/amd64/amd64/ISO-IMAGES/16.0/
I have a few Chuwi Herobox mini PCs running Linux and BSDs. All of them have 8GB RAM. Each has the original 256GB SSD and one more SATA SSD (128GB or 256GB).
Intel N4500 Mini PC -- OpenBSD 7.8 (will upgrade to 7.9 later) and NetBSD 10.1
Intel J4125 Mini PC -- Debian 13 and FreeBSD 15 Release
Intel N100 Mini PC -- Ubuntu 26.04 + Fedora 44 on the main SSD, CachyOS on the secondary SSD
Intel N100 Mini PC -- Ubuntu 26.04 + Fedora 44 Silverblue on the main SSD, EndeavourOS on the secondary SSD.
I will kill the two Arch Based Linux distros (not really using them much) and install FreeBSD/OpenBSD.
For quick testing I recommend VENTOY [1] it provides USB BOOT menu supporting MBR/GPT/BIOS/UEFI where you can choose ISO from the same pendrive to boot. So you can have multiple images on the same bootable pendrive.. and you can use it for storage as well :-)
Please let me know if there is anything to test on FreeBSD 14 :-) I can also boot of 15 or 16 if needed :-)
[1] https://www.ventoy.net/en/index.html
There is a known hardware bug in Alder Lake processors. See https://lists.freebsd.org/archives/freebsd-current/2025-January/006984.html
Sorry I made a mistake, it is not kernel panic, rather the system does not recognize the USB Flash Disk as bootable at all.
I tried the latest snapshot (FreeBSD-16.0-CURRENT-amd64-20260525-490c53e9353f-286096-disc1.iso) and the issue is the same, tested with two USB Flash disks.
Then I tested OpenBSD 7.9 release and it is able to boot (but then it does not recognize the wired and wireless network adapter).
Interesting.
Is it possible to choose EFI file from your UEFI?
Using Ventoy and then I can do that.
Interesting findings -- now FreeBSD 15.0 Release and OpenBSD 7.9 can boot and I have installed them to the second SATA SSDs of the two Intel N100 Mini PCs. Somehow I need to use HTTP install.
For the FreeBSD 16.0-Current images (your version or the snapshot version), both will fail to boot.
All in all, looks like the issue is related to file system corruption.
https://lists.freebsd.org/archives/freebsd-current/2025-January/006984.html
Screen photo taken from my mobile phone.
I've used gpt5.6-sol and found a number of issues with this implementation.
I'll run it to fix those issues and push here, instead of posting review comments
Codex updated the PR branch and pushed
a186873:518fbd1) and resolved the Autotools/build-system conflicts.Validation completed locally across Autotools, CMake shared/static, Meson, pkg-config, and installed export consumers. All PR checks are now green, including the native FreeBSD job and AppVeyor.
Related to #274. Fixes #543.
Generated by Codex (GPT-5).
Now someone could test and tell if there anything else left to fix - that would be helpful to move this forward.
Yes I will test over the weekend.
@aokblast and @cederom
Please carry out the test on your FreeBSD setup as well. Thanks.
Sorry I was busy. I will try to do it this weekend or next week.
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.