Skip to content

Add hidraw backend for FreeBSD#730

Open
aokblast wants to merge 3 commits intolibusb:masterfrom
aokblast:use_hid_raw
Open

Add hidraw backend for FreeBSD#730
aokblast wants to merge 3 commits intolibusb:masterfrom
aokblast:use_hid_raw

Conversation

@aokblast
Copy link
Copy Markdown

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

@aokblast
Copy link
Copy Markdown
Author

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.

@Youw Youw self-requested a review March 27, 2025 10:33
@Youw Youw added enhancement New feature or request bsd FreeBSD, NetBSD, OpenBSD, etc labels Mar 27, 2025
Comment thread freebsd/Makefile-manual
Comment thread libusb/Makefile.in Outdated
Comment thread src/CMakeLists.txt Outdated
Comment thread freebsd/CMakeLists.txt Outdated
Comment thread freebsd/hid.c Outdated
Comment thread freebsd/hid.c Outdated
Comment thread freebsd/hid.c Outdated
Copy link
Copy Markdown
Member

@Youw Youw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No more comments

@aokblast aokblast force-pushed the use_hid_raw branch 4 times, most recently from 49a7a62 to 6e7a25a Compare March 27, 2025 14:16
@aokblast
Copy link
Copy Markdown
Author

Thanks for @Youw your review:).

Then, What is your opinion about this?

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.

@Youw
Copy link
Copy Markdown
Member

Youw commented Mar 27, 2025

Thanks for @Youw your review:).

Then, What is your opinion about this?

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.

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.

@mcuee
Copy link
Copy Markdown
Member

mcuee commented Mar 28, 2025

Nice. This will address the following issue.

@aokblast
Copy link
Copy Markdown
Author

Oops. I forget we have udev-devd stuff. Maybe we should use udev also?

@Youw
Copy link
Copy Markdown
Member

Youw commented Mar 28, 2025

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?

@aokblast
Copy link
Copy Markdown
Author

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.

@mcuee
Copy link
Copy Markdown
Member

mcuee commented Mar 30, 2025

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.

mcuee@freebsd14:~/build/hidapi_pr730 $ uname -a
FreeBSD freebsd14 14.1-RELEASE FreeBSD 14.1-RELEASE releng/14.1-n267679-10e31f0946d8 GENERIC amd64

mcuee@freebsd14:~/build/hidapi_pr730 $ cc -v
FreeBSD clang version 18.1.5 (https://github.com/llvm/llvm-project.git llvmorg-18.1.5-0-g617a15a9eac9)
Target: x86_64-unknown-freebsd14.1
Thread model: posix
InstalledDir: /usr/bin

mcuee@freebsd14:~/build/hidapi_pr730 $ make
make  all-recursive
Making all in freebsd
  CC       hid.lo
hid.c:396:24: warning: passing 'uint8_t[255]' (aka 'unsigned char[255]') to parameter of type 'const char *' converts between pointers to integer types where one is of the unique plain 'char' type and the other is not [-Wpointer-sign]
  396 |                 mbstowcs(namebuffer, buffer, sizeof(namebuffer));
      |                                      ^~~~~~
/usr/include/stdlib.h:107:64: note: passing argument to parameter here
  107 | size_t   mbstowcs(wchar_t * __restrict , const char * __restrict, size_t);
      |                                                                 ^
hid.c:603:1: warning: non-void function does not return a value [-Wreturn-type]
  603 | }
      | ^
hid.c:937:7: warning: passing 'const char *' to parameter of type 'void *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
  937 |         free(dev->device_path);
      |              ^~~~~~~~~~~~~~~~
/usr/include/stdlib.h:101:18: note: passing argument to parameter here
  101 | void     free(void *);
      |                     ^
3 warnings generated.
  CCLD     libhidapi-hidraw.la
Making all in libusb
  CC       hid.lo
  CCLD     libhidapi-libusb.la
Making all in hidtest
  CC       test.o
  CCLD     hidtest-libusb
  CCLD     hidtest-hidraw

@aokblast
Copy link
Copy Markdown
Author

Fix it:). Forget to fix the warning.

@mcuee
Copy link
Copy Markdown
Member

mcuee commented Mar 30, 2025

Somehow hidtest-hidraw will seg fault with the Microchip Simple HID example.

mcuee@freebsd14:~/build/hidapi_pr730 $ sudo ./hidtest/hidtest-hidraw
hidapi test/example tool. Compiled with hidapi version 0.15.0, runtime version 0.15.0.
Compile-time version matches runtime version of hidapi.

Segmentation fault
mcuee@freebsd14:~/build/hidapi_pr730 $ sudo ./hidtest/hidtest-libusb
hidapi test/example tool. Compiled with hidapi version 0.15.0, runtime version 0.15.0.
Compile-time version matches runtime version of hidapi.

Device Found
  type: 04f2 0760
  path: 0-3:1.0
  serial_number: (null)
  Manufacturer: Chicony
  Product:      USB Keyboard
  Release:      100
  Interface:    0
  Usage (page): 0x0 (0x0)
  Bus type: 1 (USB)

  Report Descriptor: (65 bytes)
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07, 0x19, 0xe0, 
0x29, 0xe7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 
0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x03, 
0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91, 0x02, 
0x95, 0x05, 0x75, 0x01, 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 
0x15, 0x00, 0x26, 0xff, 0x00, 0x05, 0x07, 0x19, 0x00, 0x2a, 
0xff, 0x00, 0x81, 0x00, 0xc0, 
Device Found
  type: 04f2 0760
  path: 0-3:1.1
  serial_number: (null)
  Manufacturer: Chicony
  Product:      USB Keyboard
  Release:      100
  Interface:    1
  Usage (page): 0x0 (0x0)
  Bus type: 1 (USB)

  Report Descriptor: (127 bytes)
0x06, 0x01, 0x00, 0x09, 0x80, 0xa1, 0x01, 0x85, 0x01, 0x19, 
0x81, 0x29, 0x83, 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 
0x01, 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01, 0xc0, 
0x05, 0x0c, 0x09, 0x01, 0xa1, 0x01, 0x85, 0x03, 0x15, 0x00, 
0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x19, 0xb5, 0x29, 0xb8, 
0x09, 0xcd, 0x09, 0xe2, 0x09, 0xe9, 0x09, 0xea, 0x81, 0x02, 
0x0a, 0x83, 0x01, 0x0a, 0x8a, 0x01, 0x0a, 0x92, 0x01, 0x0a, 
0x94, 0x01, 0x0a, 0x21, 0x02, 0x1a, 0x23, 0x02, 0x2a, 0x25, 
0x02, 0x81, 0x02, 0x0a, 0x26, 0x02, 0x0a, 0x27, 0x02, 0x0a, 
0x2a, 0x02, 0x95, 0x03, 0x81, 0x02, 0x95, 0x05, 0x81, 0x01, 
0xc0, 0x06, 0x00, 0xff, 0x09, 0x01, 0xa1, 0x01, 0x85, 0x02, 
0x25, 0x01, 0x15, 0x00, 0x75, 0x01, 0x95, 0x08, 0x1a, 0xf1, 
0x00, 0x2a, 0xf8, 0x00, 0x81, 0x02, 0xc0, 
Device Found
  type: 1ea7 0064
  path: 0-4:1.0
  serial_number: (null)
  Manufacturer: (null)
  Product:      2.4G Mouse
  Release:      200
  Interface:    0
  Usage (page): 0x0 (0x0)
  Bus type: 1 (USB)

  Report Descriptor: (105 bytes)
0x06, 0xb5, 0xff, 0x09, 0x01, 0xa1, 0x01, 0x85, 0xb5, 0x09, 
0x02, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x07, 
0x81, 0x02, 0x09, 0x02, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 
0x08, 0x95, 0x07, 0x91, 0x02, 0xc0, 0x05, 0x01, 0x09, 0x02, 
0xa1, 0x01, 0x85, 0x02, 0x09, 0x01, 0xa1, 0x00, 0x05, 0x09, 
0x19, 0x01, 0x29, 0x08, 0x15, 0x00, 0x25, 0x01, 0x95, 0x08, 
0x75, 0x01, 0x81, 0x02, 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 
0x16, 0x01, 0xf8, 0x26, 0xff, 0x07, 0x75, 0x0c, 0x95, 0x02, 
0x81, 0x06, 0x09, 0x38, 0x15, 0x81, 0x25, 0x7f, 0x75, 0x08, 
0x95, 0x01, 0x81, 0x06, 0x05, 0x0c, 0x0a, 0x38, 0x02, 0x95, 
0x01, 0x81, 0x06, 0xc0, 0xc0, 
Device Found
  type: 04d8 003f
  path: 0-2:1.0
  serial_number: (null)
  Manufacturer: Microchip Technology Inc.
  Product:      Simple HID Device Demo
  Release:      2
  Interface:    0
  Usage (page): 0x0 (0x0)
  Bus type: 1 (USB)

  Report Descriptor: (28 bytes)
0x06, 0x00, 0xff, 0x09, 0x01, 0xa1, 0x01, 0x19, 0x01, 0x29, 
0x40, 0x15, 0x01, 0x25, 0x40, 0x75, 0x08, 0x95, 0x40, 0x81, 
0x00, 0x19, 0x01, 0x29, 0x40, 0x91, 0x00, 0xc0, 
Manufacturer String: Microchip Technology Inc.
Product String: Simple HID Device Demo
Unable to read serial number string
Serial Number String: (0) 
  Report Descriptor: (28 bytes)
0x06, 0x00, 0xff, 0x09, 0x01, 0xa1, 0x01, 0x19, 0x01, 0x29, 
0x40, 0x15, 0x01, 0x25, 0x40, 0x75, 0x08, 0x95, 0x40, 0x81, 
0x00, 0x19, 0x01, 0x29, 0x40, 0x91, 0x00, 0xc0, 
Device Found
  type: 04d8 003f
  path: 0-2:1.0
  serial_number: (null)
  Manufacturer: Microchip Technology Inc.
  Product:      Simple HID Device Demo
  Release:      2
  Interface:    0
  Usage (page): 0x1 (0xff00)
  Bus type: 1 (USB)

Indexed String 1: Microchip Technology Inc.
Unable to send a feature report: hid_error is not implemented yet
Unable to get a feature report: hid_error is not implemented yet
waiting...
waiting...
waiting...
waiting...
waiting...
waiting...
waiting...
waiting...
waiting...
waiting...
read() timeout

@mcuee
Copy link
Copy Markdown
Member

mcuee commented Mar 30, 2025

Fix it:). Forget to fix the warning.

Thanks. The compiler warnings are gone.

The Segfault issue is still there though.

@mcuee
Copy link
Copy Markdown
Member

mcuee commented May 7, 2025

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.

mcuee@freebsd15vboxvm:~ $ cd build/hidapitester/

mcuee@freebsd15vboxvm:~/build/hidapitester $ uname -a
FreeBSD freebsd15vboxvm 15.0-CURRENT FreeBSD 15.0-CURRENT #0 main-n276914-f676c13d4226: Thu May  1 05:11:20 UTC 2025     root@releng3.nyi.freebsd.org:/usr/obj/usr/src/amd64.amd64/sys/GENERIC amd64

mcuee@freebsd15vboxvm:~/build/hidapitester $ sudo sysctl hw.usb.usbhid.enable=1
Password:
hw.usb.usbhid.enable: 0 -> 1

mcuee@freebsd15vboxvm:~/build/hidapitester $ sudo kldunload uhid

mcuee@freebsd15vboxvm:~/build/hidapitester $ sudo kldload hidraw

mcuee@freebsd15vboxvm:~/build/hidapitester $ sudo ./hidapitester_freebsd_libusb_pr730 --vidpid 0925:1234 --open --buflen 256 -l 129 --send-output 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128  --read-input
Opening device, vid/pid: 0x0925/0x1234
Writing output report of 129-bytes...wrote 129 bytes:
 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
 80
Reading up to 129-byte input report, 250 msec timeout...read 64 bytes:
 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20
 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00
Closing device

mcuee@freebsd15vboxvm:~/build/hidapitester $ sudo ./hidapitester_freebsd_hidraw_pr730 --vidpid 0925:1234 --open --buflen 256 -l 129 --send-output 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128  --read-input
Opening device, vid/pid: 0x0925/0x1234
Writing output report of 129-bytes...wrote 129 bytes:
 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
 80
Reading up to 129-byte input report, 250 msec timeout...read 0 bytes:
Closing device

@mcuee
Copy link
Copy Markdown
Member

mcuee commented May 7, 2025

@aokblast

Now I am clean of the fault, it is the same as what you see. No timeout, immediately exit.

hidapi_read return immediately and the length is 0

@aokblast
Copy link
Copy Markdown
Author

aokblast commented May 7, 2025

Ok, I see. I should take some time to get a device able to afford USB HIGH speed

@mcuee
Copy link
Copy Markdown
Member

mcuee commented May 7, 2025

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.

@mcuee
Copy link
Copy Markdown
Member

mcuee commented May 7, 2025

More about the test device.

mcuee@freebsd15vboxvm:~/build/hidapitester $ sudo ./hidapitester_freebsd_libusb_pr730 --list-detail
0925/1234: CYPRESS - EZ-USB FX2 HID USBHIDIO
  vendorId:      0x0925
  productId:     0x1234
  usagePage:     0x0000
  usage:         0x0000
  serial_number: (null) 
  interface:     0 
  path: 1-1:1.0

mcuee@freebsd15vboxvm:~/build/hidapitester $ sudo ./hidapitester_freebsd_hidraw_pr730 --list-detail
0925/1234: (null) - CYPRESS EZ-USB FX2 HID USBHIDIO
  vendorId:      0x0925
  productId:     0x1234
  usagePage:     0xFFA0
  usage:         0x0001
  serial_number: (null) 
  interface:     0 
  path: /dev/hidraw0

mcuee@freebsd15vboxvm:~/build/hidapitester $ sudo usbconfig
ugen1.1: <EHCI root HUB Intel> at usbus1, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA)
ugen0.1: <OHCI root HUB Apple> at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=SAVE (0mA)
ugen1.2: <EZ-USB FX2 HID USBHIDIO Lakeview Research> at usbus1, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (80mA)

mcuee@freebsd15vboxvm:~/build/hidapitester $ sudo lsusb -vvv -d 0925:1234

Bus /dev/usb Device /dev/ugen1.2: ID 0925:1234 Lakeview Research 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x0925 Lakeview Research
  idProduct          0x1234 
  bcdDevice            0.00
  iManufacturer           1 CYPRESS
  iProduct                2 EZ-USB FX2 HID USBHIDIO
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           41
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          3 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower               80mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.10
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      52
          Report Descriptor: (length is 52)
            Item(Global): Usage Page, data= [ 0xa0 0xff ] 65440
                            (null)
            Item(Local ): Usage, data= [ 0x01 ] 1
                            (null)
            Item(Main  ): Collection, data= [ 0x01 ] 1
                            Application
            Item(Local ): Usage, data= [ 0x02 ] 2
                            (null)
            Item(Main  ): Collection, data= [ 0x00 ] 0
                            Physical
            Item(Global): Usage Page, data= [ 0xa1 0xff ] 65441
                            (null)
            Item(Local ): Usage, data= [ 0x03 ] 3
                            (null)
            Item(Local ): Usage, data= [ 0x04 ] 4
                            (null)
            Item(Global): Logical Minimum, data= [ 0x80 ] 128
            Item(Global): Logical Maximum, data= [ 0x7f ] 127
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0xff ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Report Count, data= [ 0x80 ] 128
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x05 ] 5
                            (null)
            Item(Local ): Usage, data= [ 0x06 ] 6
                            (null)
            Item(Global): Logical Minimum, data= [ 0x80 ] 128
            Item(Global): Logical Maximum, data= [ 0x7f ] 127
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0xff ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Report Count, data= [ 0x80 ] 128
            Item(Main  ): Output, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Main  ): End Collection, data=none
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               5
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               5
Device Qualifier (for other device speed):
  bLength                10
  bDescriptorType         6
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         4
  bNumConfigurations      1
can't get debug descriptor: Input/output error
Device Status:     0x0002
  (Bus Powered)
  Remote Wakeup Enabled

@mcuee
Copy link
Copy Markdown
Member

mcuee commented May 7, 2025

Forcing the device to run in Full Speed mode and now this PR works.

mcuee@freebsd15vboxvm:~/build/hidapitester $ sudo usbconfig
ugen0.1: <OHCI root HUB Apple> at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=SAVE (0mA)
ugen0.2: <EZ-USB FX2 HID USBHIDIO Lakeview Research> at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON (80mA)

mcuee@freebsd15vboxvm:~/build/hidapitester $ sudo lsusb
Bus /dev/usb Device /dev/ugen0.2: ID 0925:1234 Lakeview Research 
Bus /dev/usb Device /dev/ugen0.1: ID 0000:0000  

mcuee@freebsd15vboxvm:~/build/hidapitester $ sudo lsusb -vvv -d 0925:1234

Bus /dev/usb Device /dev/ugen0.2: ID 0925:1234 Lakeview Research 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x0925 Lakeview Research
  idProduct          0x1234 
  bcdDevice            0.00
  iManufacturer           1 CYPRESS
  iProduct                2 EZ-USB FX2 HID USBHIDIO
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           41
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          3 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower               80mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.10
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      52
          Report Descriptor: (length is 52)
            Item(Global): Usage Page, data= [ 0xa0 0xff ] 65440
                            (null)
            Item(Local ): Usage, data= [ 0x01 ] 1
                            (null)
            Item(Main  ): Collection, data= [ 0x01 ] 1
                            Application
            Item(Local ): Usage, data= [ 0x02 ] 2
                            (null)
            Item(Main  ): Collection, data= [ 0x00 ] 0
                            Physical
            Item(Global): Usage Page, data= [ 0xa1 0xff ] 65441
                            (null)
            Item(Local ): Usage, data= [ 0x03 ] 3
                            (null)
            Item(Local ): Usage, data= [ 0x04 ] 4
                            (null)
            Item(Global): Logical Minimum, data= [ 0x80 ] 128
            Item(Global): Logical Maximum, data= [ 0x7f ] 127
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0xff ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Report Count, data= [ 0x80 ] 128
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x05 ] 5
                            (null)
            Item(Local ): Usage, data= [ 0x06 ] 6
                            (null)
            Item(Global): Logical Minimum, data= [ 0x80 ] 128
            Item(Global): Logical Maximum, data= [ 0x7f ] 127
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0xff ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Report Count, data= [ 0x80 ] 128
            Item(Main  ): Output, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Main  ): End Collection, data=none
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               5
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               5
Device Status:     0x0002
  (Bus Powered)
  Remote Wakeup Enabled

mcuee@freebsd15vboxvm:~/build/hidapitester $ sudo ./hidapitester_freebsd_libusb_pr730 --vidpid 0925:1234 --open --buflen 256 -l 129 --send-output 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128  --read-input
Opening device, vid/pid: 0x0925/0x1234
Writing output report of 129-bytes...wrote 129 bytes:
 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
 80
Reading up to 129-byte input report, 250 msec timeout...read 64 bytes:
 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20
 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00
Closing device
mcuee@freebsd15vboxvm:~/build/hidapitester $ sudo ./hidapitester_freebsd_hidraw_pr730 --vidpid 0925:1234 --open --buflen 256 -l 129 --send-output 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128  --read-input
Opening device, vid/pid: 0x0925/0x1234
Writing output report of 129-bytes...wrote 129 bytes:
 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
 80
Reading up to 129-byte input report, 250 msec timeout...read 128 bytes:
 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20
 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40
 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60
 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80
 00
Closing device

@mcuee
Copy link
Copy Markdown
Member

mcuee commented May 7, 2025

@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.

@aokblast
Copy link
Copy Markdown
Author

aokblast commented May 8, 2025

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.

Yes, hid full speed with larger than 64 byte report works.

Code and result:

blast@fbsd-dev:~/hid $ cat hid.c
#include <stdint.h>
#include <stdio.h>
#include <assert.h>

#include "hidapi/hidapi.h"

static const char buffer[] = "Hello World\n";

int main() {
  int res;
  hid_device *device, *head;
  struct hid_device_info *devs;
  uint8_t buffer[1024]  = {};
  uint8_t command[] = {0x87, 0x87};
  int sz;

  assert(hid_init() == 0);

  device = hid_open(0x0483, 0x5750, NULL);
  assert(device != NULL);
  assert(hid_write(device, command, sizeof(command)) != -1);
  sz = hid_read(device, buffer, sizeof(buffer));
  printf("%ls\n", hid_error(device));
  printf("%d\n", sz);
  printf("%x\n", (uint32_t)buffer[0]);
  printf("%x\n", (uint32_t)buffer[1]);

  hid_close(device);

  hid_free_enumeration(devs);

  assert(hid_exit() == 0);
}
blast@fbsd-dev:~/hid $ make
blast@fbsd-dev:~/hid $ sudo LD_LIBRARY_PATH=/home/blast/hidapi/build/install/lib/ ./hid
Success
1023
1
2

usbconfig -d0.3 dump_all_desc:

bDescriptorType = 0x0004
      bInterfaceNumber = 0x0000
      bAlternateSetting = 0x0000
      bNumEndpoints = 0x0002
      bInterfaceClass = 0x0003  <HID device>
      bInterfaceSubClass = 0x0000
      bInterfaceProtocol = 0x0000
      iInterface = 0x0000  <no string>

      Additional Descriptor

      bLength = 0x09
      bDescriptorType = 0x21
      bDescriptorSubType = 0x11
       RAW dump:
       0x00 | 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x23,
       0x08 | 0x00

     Endpoint 0
        bLength = 0x0007
        bDescriptorType = 0x0005
        bEndpointAddress = 0x0081  <IN>
        bmAttributes = 0x0003  <INTERRUPT>
        wMaxPacketSize = 0x0040
        bInterval = 0x0005
        bRefresh = 0x0000
        bSynchAddress = 0x0000

     Endpoint 1
        bLength = 0x0007
        bDescriptorType = 0x0005
        bEndpointAddress = 0x0001  <OUT>
        bmAttributes = 0x0003  <INTERRUPT>
        wMaxPacketSize = 0x0040
        bInterval = 0x0005
        bRefresh = 0x0000
        bSynchAddress = 0x0000

Report Descriptor:

image

@mcuee
Copy link
Copy Markdown
Member

mcuee commented Jun 16, 2025

@aokblast

If you can, please get the FX2LP break-out board from Taobao/AliExpress/Amazon/etc. It is pretty cheap.
FX2LP

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.

  1. https://github.com/djmuhlestein/fx2lib
  2. https://github.com/whitequark/libfx2

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:

@mcuee
Copy link
Copy Markdown
Member

mcuee commented Jun 16, 2025

Update with the main git branch to trigger another CI run.

@mcuee
Copy link
Copy Markdown
Member

mcuee commented Jun 17, 2025

@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.

@cederom
Copy link
Copy Markdown

cederom commented Jun 17, 2025

@mcuee builds okay, could you please provide test steps, its a long thread and I am quite short on time sorry :-P

@mcuee
Copy link
Copy Markdown
Member

mcuee commented Jun 17, 2025

@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.

  1. 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

  2. Test with USB Full Speed HID device with >64 Bytes HID report size. This should be okay.

  3. 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.

@dl8dtl
Copy link
Copy Markdown

dl8dtl commented Jun 17, 2025

I have mentioned my test device in the comments above.

I just ordered one. Let's seen when it arrives.

@aokblast
Copy link
Copy Markdown
Author

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.

@mcuee
Copy link
Copy Markdown
Member

mcuee commented Jun 20, 2025

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

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
Sponsored-by: Framework Laptop. Inc
@mcuee
Copy link
Copy Markdown
Member

mcuee commented Dec 30, 2025

@aokblast

Just wondering if you have any updates on this PR. Thanks.

@mcuee
Copy link
Copy Markdown
Member

mcuee commented Mar 20, 2026

Just update the branch to trigger a new build.

It will be good to move this PR forward. May need more testing and reviews.

@cederom
Copy link
Copy Markdown

cederom commented Mar 20, 2026

I am on FreeBSD 14.4-RELEASE AMD64 just in case :-)

@mcuee
Copy link
Copy Markdown
Member

mcuee commented Apr 19, 2026

@Youw

Just wondering if it is worth asking Github Copilot to review this PR.

@aokblast
Copy link
Copy Markdown
Author

@aokblast

Just wondering if you have any updates on this PR. Thanks.

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.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  • Introduce a new freebsd/ backend implementation (hid.c) and integrate it into both CMake and Autotools builds.
  • Update build/test targets to build both hidraw and libusb variants on FreeBSD (hidtest + testgui).
  • Adjust FreeBSD libusb build artifacts naming to match the -libusb convention.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 18 comments.

Show a summary per file
File Description
testgui/Makefile.am Build FreeBSD testgui against both freebsd hidraw and libusb backends.
src/CMakeLists.txt Add FreeBSD platform branch to build/export the hidraw backend from freebsd/.
libusb/Makefile.freebsd Rename manual FreeBSD libusb targets to *-libusb naming.
libusb/Makefile.am Rename FreeBSD libusb Automake library target to libhidapi-libusb.la.
hidtest/Makefile.am Build both hidtest-hidraw and hidtest-libusb on FreeBSD.
hidtest/CMakeLists.txt Enable building hidtest_hidraw on FreeBSD when hidapi::hidraw exists.
freebsd/hid.c New FreeBSD hidraw backend implementation (enumeration, IO, descriptors, strings).
freebsd/Makefile.am Automake build for freebsd hidraw library.
freebsd/Makefile-manual Manual makefile to build the FreeBSD hidraw backend.
freebsd/CMakeLists.txt CMake target for FreeBSD hidraw backend and pkg-config generation.
freebsd/.gitignore Ignore build artifacts under freebsd/.
configure.ac Switch FreeBSD Autotools backend to freebsd and add FreeBSD Makefile/config vars.
Makefile.am Add freebsd/ subdir and install FreeBSD pkg-config files for hidraw+libusb.
CMakeLists.txt Add FreeBSD options for building hidraw and libusb implementations.
Comments suppressed due to low confidence (1)

configure.ac:249

  • Autotools config only generates pc/hidapi-hidraw.pc and pc/hidapi-libusb.pc when os == linux, but the top-level Makefile.am now installs those pc files for FreeBSD as well. This will break make/make install on FreeBSD because the .pc files won't be configured/generated. Update this conditional to include FreeBSD (or generate the correct pc files based on OS_FREEBSD).
if test "x$os" = xlinux; then
	AC_CONFIG_FILES([pc/hidapi-hidraw.pc])
	AC_CONFIG_FILES([pc/hidapi-libusb.pc])
else
	AC_CONFIG_FILES([pc/hidapi.pc])
fi

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread freebsd/hid.c
Comment on lines +506 to +513
hid_get_udev_location_from_hidraw_idx(idx,&bus,
&addr,&info->interface_number);
handler = hid_find_device_handle_by_bus_and_port(bus, addr);
if (!handler)
break;
device = libusb_get_device(handler);
if (libusb_get_device_descriptor(device, &desc)) {
libusb_close(handler);
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the BUS_USB branch, the return value of hid_get_udev_location_from_hidraw_idx() is ignored, but bus/addr are then used even if the lookup failed (they're uninitialized). Also, on libusb_get_device_descriptor() failure the handle is closed but the code continues and uses handler afterward. Check both errors and bail out before using bus/addr or a closed handle.

Suggested change
hid_get_udev_location_from_hidraw_idx(idx,&bus,
&addr,&info->interface_number);
handler = hid_find_device_handle_by_bus_and_port(bus, addr);
if (!handler)
break;
device = libusb_get_device(handler);
if (libusb_get_device_descriptor(device, &desc)) {
libusb_close(handler);
if (hid_get_udev_location_from_hidraw_idx(idx, &bus,
&addr, &info->interface_number) != 0)
break;
handler = hid_find_device_handle_by_bus_and_port(bus, addr);
if (!handler)
break;
device = libusb_get_device(handler);
if (libusb_get_device_descriptor(device, &desc)) {
libusb_close(handler);
break;

Copilot uses AI. Check for mistakes.
Comment thread freebsd/hid.c
Comment on lines +516 to +520
if (len == 0) {
libusb_close(handler);
break;
}
mbstowcs(namebuffer, (char *)buffer, sizeof(namebuffer));
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

libusb_get_string_descriptor_ascii() returns a negative libusb error code on failure, not 0. The current len == 0 check will miss errors. Also, mbstowcs(..., sizeof(namebuffer)) passes a byte count instead of the number of wchar_t elements and can overflow namebuffer. Validate len > 0 and pass the correct element count (and ensure null-termination) before wcsdup().

Suggested change
if (len == 0) {
libusb_close(handler);
break;
}
mbstowcs(namebuffer, (char *)buffer, sizeof(namebuffer));
if (len <= 0) {
libusb_close(handler);
break;
}
if ((size_t) len >= sizeof(buffer))
len = sizeof(buffer) - 1;
buffer[len] = '\0';
{
size_t converted;
size_t namebuffer_len = sizeof(namebuffer) / sizeof(namebuffer[0]);
converted = mbstowcs(namebuffer, (char *)buffer, namebuffer_len - 1);
if (converted == (size_t)-1)
namebuffer[0] = L'\0';
else
namebuffer[converted] = L'\0';
}

Copilot uses AI. Check for mistakes.
Comment thread freebsd/hid.c
Comment on lines +565 to +577
template = malloc(sizeof(struct hid_device_info));
template->path = strdup(devpath);
template->vendor_id = devinfo.hdi_vendor;
template->product_id = devinfo.hdi_product;
mbstowcs(namebuffer, devinfo.hdi_uniq, sizeof(namebuffer));
template->serial_number = strlen(devinfo.hdi_uniq) ? wcsdup(namebuffer) : NULL;
template->release_number = devinfo.hdi_version;
mbstowcs(namebuffer, devinfo.hdi_name, sizeof(namebuffer));
template->product_string = strlen(devinfo.hdi_name) ? wcsdup(namebuffer) : NULL;
template->interface_number = -1;
template->manufacturer_string = NULL;
template->next = NULL;
hid_device_handle_bus_dependent(&devinfo, template, idx);
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

template is allocated with malloc() and then partially initialized. Any fields not explicitly set (e.g., usage_page, usage, bus_type, etc.) remain uninitialized and may be copied later. Prefer calloc() (or memset) and check for allocation failures before dereferencing template.

Copilot uses AI. Check for mistakes.
Comment thread freebsd/hid.c
Comment on lines +569 to +573
mbstowcs(namebuffer, devinfo.hdi_uniq, sizeof(namebuffer));
template->serial_number = strlen(devinfo.hdi_uniq) ? wcsdup(namebuffer) : NULL;
template->release_number = devinfo.hdi_version;
mbstowcs(namebuffer, devinfo.hdi_name, sizeof(namebuffer));
template->product_string = strlen(devinfo.hdi_name) ? wcsdup(namebuffer) : NULL;
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both mbstowcs(namebuffer, ..., sizeof(namebuffer)) calls pass a byte size instead of the number of wchar_t elements. This can overflow namebuffer (256 elements) because sizeof(namebuffer) is typically 1024 bytes. Use sizeof(namebuffer)/sizeof(namebuffer[0]) (and handle truncation / ensure termination) before wcsdup().

Suggested change
mbstowcs(namebuffer, devinfo.hdi_uniq, sizeof(namebuffer));
template->serial_number = strlen(devinfo.hdi_uniq) ? wcsdup(namebuffer) : NULL;
template->release_number = devinfo.hdi_version;
mbstowcs(namebuffer, devinfo.hdi_name, sizeof(namebuffer));
template->product_string = strlen(devinfo.hdi_name) ? wcsdup(namebuffer) : NULL;
if (strlen(devinfo.hdi_uniq)) {
size_t converted = mbstowcs(namebuffer, devinfo.hdi_uniq,
(sizeof(namebuffer) / sizeof(namebuffer[0])) - 1);
if (converted != (size_t)-1) {
namebuffer[converted] = L'\0';
template->serial_number = wcsdup(namebuffer);
} else {
template->serial_number = NULL;
}
} else {
template->serial_number = NULL;
}
template->release_number = devinfo.hdi_version;
if (strlen(devinfo.hdi_name)) {
size_t converted = mbstowcs(namebuffer, devinfo.hdi_name,
(sizeof(namebuffer) / sizeof(namebuffer[0])) - 1);
if (converted != (size_t)-1) {
namebuffer[converted] = L'\0';
template->product_string = wcsdup(namebuffer);
} else {
template->product_string = NULL;
}
} else {
template->product_string = NULL;
}

Copilot uses AI. Check for mistakes.
Comment thread freebsd/hid.c
Comment on lines +1182 to +1187
if (act_len < buf_size)
buf_size = act_len;

memcpy(buf, desc.value, buf_size);
return buf_size;
}
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hid_get_report_descriptor() returns buf_size (a size_t) from a function returning int. This can trigger warnings and truncation on large descriptors. Follow the pattern used by other backends: clamp to INT_MAX if needed and return (int)buf_size after copying.

Copilot uses AI. Check for mistakes.
Comment thread freebsd/hid.c
register_global_error_format("Unable to find the device with bus:%2d and addr:%2d", bus, addr);
}

libusb_free_device_list(list, 0);
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

libusb_free_device_list(list, 0) does not unref the devices in the list and can leak references. The rest of the codebase uses libusb_free_device_list(..., 1) after enumeration; do the same here.

Suggested change
libusb_free_device_list(list, 0);
libusb_free_device_list(list, 1);

Copilot uses AI. Check for mistakes.
Comment thread freebsd/hid.c
Comment on lines +479 to +483
snprintf(buff, sizeof(buff), "dev.hidbus.%d.%%parent", idx);
len = sizeof(buff);
if (sysctlbyname(buff, buff, &len, NULL, 0))
return 0;
buff[len] = '\0';
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hid_get_udev_location_from_hidraw_idx() writes buff[len] = '\0' after sysctlbyname(). If the returned len equals sizeof(buff), this writes 1 byte past the buffer. Guard len (or ensure null termination by reserving a byte / clamping).

Copilot uses AI. Check for mistakes.
Comment thread freebsd/hid.c
int oid[CTL_MAXNAME] = {0};
size_t buf_len, oid_items = CTL_MAXNAME;
struct hid_sysctl_iter iter;

Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hid_enumerate() doesn't call hid_init(), but the enumeration path can call into libusb (via hid_device_handle_bus_dependent() -> hid_find_device_handle_by_bus_and_port()). Without initializing libusb first, libusb_get_device_list() may fail/behave unexpectedly. Call hid_init() early in hid_enumerate() (as other backends do) and handle/init errors appropriately.

Suggested change
if (hid_init() != 0)
return NULL;

Copilot uses AI. Check for mistakes.
Comment thread freebsd/hid.c
if (cur_dev->vendor_id == vendor_id &&
cur_dev->product_id == product_id) {
if (serial_number) {
if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a serial_number is provided, wcscmp(serial_number, cur_dev->serial_number) will crash if cur_dev->serial_number is NULL (which can happen when hdi_uniq is empty). Add a null check before calling wcscmp() and only compare when a serial is present.

Suggested change
if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
if (cur_dev->serial_number &&
wcscmp(serial_number, cur_dev->serial_number) == 0) {

Copilot uses AI. Check for mistakes.
Comment thread freebsd/hid.c
Comment on lines +14 to +21
#include <stdlib.h>
#include <string.h>
#include <sys/fcntl.h>
#include <sys/ioccom.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <unistd.h>
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bsd FreeBSD, NetBSD, OpenBSD, etc enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants