Skip to content

Add hidraw backend for FreeBSD #730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

aokblast
Copy link

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
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
Copy link
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
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
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
Member

mcuee commented Mar 28, 2025

Nice. This will address the following issue.

@aokblast
Copy link
Author

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

@Youw
Copy link
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
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
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
Author

Fix it:). Forget to fix the warning.

@mcuee
Copy link
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
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
Member

mcuee commented Apr 13, 2025

Somehow it still does not work.

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.

Device Found
  type: 0925 1234
  path: /dev/hidraw1
  serial_number: (null)
  Manufacturer: CYPRESS
  Product:      CYPRESS EZ-USB FX2 HID USBHIDIO
  Release:      0
  Interface:    0
  Usage (page): 0x1 (0xffa0)
  Bus type: 1 (USB)

  Report Descriptor: (52 bytes)
0x06, 0xa0, 0xff, 0x09, 0x01, 0xa1, 0x01, 0x09, 0x02, 0xa1, 
0x00, 0x06, 0xa1, 0xff, 0x09, 0x03, 0x09, 0x04, 0x15, 0x80, 
0x25, 0x7f, 0x35, 0x00, 0x45, 0xff, 0x75, 0x08, 0x95, 0x80, 
0x81, 0x02, 0x09, 0x05, 0x09, 0x06, 0x15, 0x80, 0x25, 0x7f, 
0x35, 0x00, 0x45, 0xff, 0x75, 0x08, 0x95, 0x80, 0x91, 0x02, 
0xc0, 0xc0, 
Device Found
  type: 04f2 0760
  path: /dev/hidraw0
  serial_number: (null)
  Manufacturer: Chicony
  Product:      Chicony USB Keyboard
  Release:      100
  Interface:    1
  Usage (page): 0x80 (0x1)
  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: 04f2 0760
  path: /dev/hidraw0
  serial_number: (null)
  Manufacturer: Chicony
  Product:      Chicony USB Keyboard
  Release:      100
  Interface:    1
  Usage (page): 0x1 (0xc)
  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: 04f2 0760
  path: /dev/hidraw0
  serial_number: (null)
  Manufacturer: Chicony
  Product:      Chicony USB Keyboard
  Release:      100
  Interface:    1
  Usage (page): 0x1 (0xff00)
  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, 
unable to open device


mcuee@freebsd14:~/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:
 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 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@freebsd14:~/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

return -1;
}

bytes_written = write(dev->device_handle, data, length);
Copy link

Choose a reason for hiding this comment

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

Strip leading zero for unnumbered reports. See write section of FreeBSD hidraw(4) man.
Don't forget to account for this byte in return value.

Copy link

Choose a reason for hiding this comment

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

HIDRAW_GET_REPORT and HIDRAW_SET_REPORT callers should strip leading zero for unnumbered reports too

Copy link
Member

Choose a reason for hiding this comment

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

@wulf7 are you sure?
I believe this entire implementation should be about hidraw, not uhid, and according to https://man.freebsd.org/cgi/man.cgi?hidraw(4)

In the hidraw mode, the first byte should be set to 0 and the report data itself should begin at the second byte.

I.e. - no strip.

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;
Copy link

Choose a reason for hiding this comment

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

you may add "dev.uhid.%d" nodes here too as they are compatible with hidraw(4) in uhid mode on binary level.

@aokblast
Copy link
Author

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.

@wulf7
Copy link

wulf7 commented Apr 14, 2025

uhid mode supports non-USB HID devices too. Both modes are comparable.

@Youw
Copy link
Member

Youw commented Apr 14, 2025

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?

@wulf7
Copy link

wulf7 commented Apr 14, 2025

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.

@wulf7
Copy link

wulf7 commented Apr 14, 2025

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.

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

@wulf7
Copy link

wulf7 commented Apr 14, 2025

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.

@mcuee
Copy link
Member

mcuee commented Apr 14, 2025

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.

@wulf7
Copy link

wulf7 commented Apr 15, 2025

Hmm, what about FreeBSD 15.0-Current? Does it have the two IOCTLs you mentioned?

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

@mcuee
Copy link
Member

mcuee commented Apr 30, 2025

The IOCTLs have been added to FreeBSD on 27-April-2025.

 #define	HIDIOCSINPUT(len)	_IOC(IOC_IN,    'U', 38, len)
 #define	HIDIOCGINPUT(len)	_IOC(IOC_INOUT, 'U', 39, len)
 #define	HIDIOCSOUTPUT(len)	_IOC(IOC_IN,    'U', 40, len)
 #define	HIDIOCGOUTPUT(len)	_IOC(IOC_INOUT, 'U', 41, len)

@aokblast
Copy link
Author

aokblast commented Apr 30, 2025

The IOCTLs have been added to FreeBSD on 27-April-2025.

 #define	HIDIOCSINPUT(len)	_IOC(IOC_IN,    'U', 38, len)
 #define	HIDIOCGINPUT(len)	_IOC(IOC_INOUT, 'U', 39, len)
 #define	HIDIOCSOUTPUT(len)	_IOC(IOC_IN,    'U', 40, len)
 #define	HIDIOCGOUTPUT(len)	_IOC(IOC_INOUT, 'U', 41, len)

Can 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?

  1. Had a device's descriptor larger than 64 byte on full speed device.
  2. Try to send the report
  3. hidapi_read return immediately and the length is 0.

If so, I can reproduce it throught stm32f103 as I set the Input Descriptor to 1023 bytes.

Or

  1. Had a device's descriptor larger than 64 byte on full speed device.
  2. Try to send the report
  3. hidapi_read blocking and never return, returned by timeout.

@wulf7
Copy link

wulf7 commented Apr 30, 2025

The IOCTLs have been added to FreeBSD on 27-April-2025.

Also, they have been merged to 14-STABLE today.

@mcuee
Copy link
Member

mcuee commented May 1, 2025

The IOCTLs have been added to FreeBSD on 27-April-2025.

 #define	HIDIOCSINPUT(len)	_IOC(IOC_IN,    'U', 38, len)
 #define	HIDIOCGINPUT(len)	_IOC(IOC_INOUT, 'U', 39, len)
 #define	HIDIOCSOUTPUT(len)	_IOC(IOC_IN,    'U', 40, len)
 #define	HIDIOCGOUTPUT(len)	_IOC(IOC_INOUT, 'U', 41, len)

Can I do it seperately? I think it needs some version check code to enable it.

Yes. That can be another follow-up PR.

BTW, thought I don't buy the chip you have, I found 1 stm32f103 in my bedroom yesterday.

Yes, STM32 MCU is a good one to use.

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?

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.

Is your condition as following?

  1. Had a device's descriptor larger than 64 byte on full speed device.
  2. Try to send the report
  3. hidapi_read return immediately and the length is 0.

If so, I can reproduce it throught stm32f103 as I set the Input Descriptor to 1023 bytes.

Or

  1. Had a device's descriptor larger than 64 byte on full speed device.
  2. Try to send the report
  3. hidapi_read blocking and never return, returned by timeout.

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.

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
@aokblast
Copy link
Author

aokblast commented May 7, 2025

The IOCTLs have been added to FreeBSD on 27-April-2025.

 #define	HIDIOCSINPUT(len)	_IOC(IOC_IN,    'U', 38, len)
 #define	HIDIOCGINPUT(len)	_IOC(IOC_INOUT, 'U', 39, len)
 #define	HIDIOCSOUTPUT(len)	_IOC(IOC_IN,    'U', 40, len)
 #define	HIDIOCGOUTPUT(len)	_IOC(IOC_INOUT, 'U', 41, len)

Can I do it seperately? I think it needs some version check code to enable it.

Yes. That can be another follow-up PR.

BTW, thought I don't buy the chip you have, I found 1 stm32f103 in my bedroom yesterday.

Yes, STM32 MCU is a good one to use.

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?

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.

Is your condition as following?

  1. Had a device's descriptor larger than 64 byte on full speed device.
  2. Try to send the report
  3. hidapi_read return immediately and the length is 0.

If so, I can reproduce it throught stm32f103 as I set the Input Descriptor to 1023 bytes.
Or

  1. Had a device's descriptor larger than 64 byte on full speed device.
  2. Try to send the report
  3. hidapi_read blocking and never return, returned by timeout.

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.

@mcuee
Copy link
Member

mcuee commented May 7, 2025

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

; dscr.a51
; Contains the Device Descriptor, Configuration(Interface, HID and Endpoint) Descriptor,
; and String descriptors.
;


DSCR_DEVICE   	 equ   1   			;; Descriptor type: Device
DSCR_CONFIG  	 equ   2   			;; Descriptor type: Configuration
DSCR_STRING   	 equ   3  		 	;; Descriptor type: String
DSCR_INTRFC   	 equ   4   			;; Descriptor type: Interface
DSCR_ENDPNT   	 equ   5   			;; Descriptor type: Endpoint
DSCR_DEVQUAL  	 equ   6   			;; Descriptor type: Device Qualifier
DSCR_OTHERSPEED  equ   7 


ET_CONTROL   equ   0   				;; Endpoint type: Control
ET_ISO       equ   1   				;; Endpoint type: Isochronous
ET_BULK      equ   2   				;; Endpoint type: Bulk
ET_INT       equ   3   				;; Endpoint type: Interrupt

public	DeviceDscr,ConfigDscr,StringDscr,HIDDscr,ReportDscr,ReportDscrEnd,StringDscr0, StringDscr1, StringDscr2
public  HighSpeedConfigDscr,FullSpeedConfigDscr,DeviceQualDscr, UserDscr
 
;EZ USB FX2 control panel Vendor ID 0h, product ID 2131h
; Lakeview Research VID is 0925h.   
VID	equ	0925h
PID	equ	1234h
DID 	equ	0000h

;cseg at 0x90
DSCR   SEGMENT   CODE PAGE

;;-----------------------------------------------------------------------------
;; Global Variables
;;-----------------------------------------------------------------------------
      rseg DSCR      ;; locate the descriptor table in on-part memory.

DeviceDscr:	
	db	DeviceDscrEnd - DeviceDscr		; Descriptor length
	db	DSCR_DEVICE			; Descriptor type = DEVICE
	db	00h,02h				; spec version (BCD) is 2.00               
	db	0,0,0				; HID class is defined in the interface descriptor
	db	64				; maxPacketSize
	db	LOW(VID),HIGH(VID)
	db	LOW(PID),HIGH(PID)
	db	LOW(DID),HIGH(DID)
	db  	 1        			; Manufacturer string index
      	db  	 2         			; Product string index
      	db  	 0         			; Serial number string index
      	db  	 1         			; Number of configurations
DeviceDscrEnd:

DeviceQualDscr:
    db  DeviceQualDscrEnd - DeviceQualDscr      ;Descriptor Length
    db  DSCR_DEVQUAL        			;Descriptor Type
    db  00h,02h            			;spec version (BCD) is 2.00
    db  0,0,0               			;Device class, sub-class, and sub-sub-class
    db  04h                 			;Max Packet Size
    db  1                  		 	;Number of configurations
    db  0                   			;Reserved
DeviceQualDscrEnd:

HighSpeedConfigDscr:
ConfigDscr:
	db	ConfigDscrEnd - ConfigDscr	; Descriptor length
        db	DSCR_CONFIG			; Descriptor type = CONFIG
	db	LOW(HS_End-ConfigDscr)		; total length (conf+interface+HID+EP's)
	db	HIGH(HS_End-ConfigDscr)
	db	01h				; number of interfaces
	db	01h				; value to select this interface
	db	03h				; string index to describe this config
	db	10000000b			; b7=1; b6=self-powered; b5=Remote WU
	db	40d				; bus power = 80 ma
ConfigDscrEnd:

IntrfcDscr:		; Interface Descriptor
	db	IntrfcDscrEnd -  IntrfcDscr	; Descriptor length
	db	DSCR_INTRFC			; Descriptor type = INTERFACE
	db	0,0				; Interface 0, Alternate setting 0
	db	02h				; number of endpoints
	db	03h,0,0				; class(03)HID, no subclass or protocol
	db	0h				; string index for this interface
IntrfcDscrEnd:

HIDDscr:
	db	HIDDscrEnd - HIDDscr		; Descriptor length
	db	21h				; Descriptor type - HID
	db	10h,01h				; HID Spec version 1.10
	db	0				; country code(none)
	db	01h				; number of HID class descriptors
	db	22h				; class descriptor type: REPORT
	db	LOW(ReportDscrEnd - ReportDscr)
        db	HIGH(ReportDscrEnd - ReportDscr)
HIDDscrEnd:

EpInDscr:	; I-0, AS-0 first endpoint descriptor (EP1IN)
	db	EpInDscrEnd - EpInDscr		; Descriptor length
	db	DSCR_ENDPNT			; Descriptor type = ENDPOINT
	db	81h				; IN-1
	db	03h				; Type: INTERRUPT
	db	40h,0				; MaxPacketSize = 64
	db	05h				; polling interval is 2^(5-1) x 125us = 2 mSec
EpInDscrEnd:

EpOutDscr:
	db	EpOutDscrEnd - EpOutDscr	; Descriptor length
	db	DSCR_ENDPNT			; Descriptor type = ENDPOINT
	db	01h				; OUT-1
	db	03h				; Type ; INTERRUPT
	db	40h,0				; MaxPacketSize = 64
	db	05h				; polling interval is 2^(5-1) x 125us = 2 mSec
EpOutDscrEnd:	
HS_End:

    db  00h         ; Word alignment

FullSpeedConfigDscr:
	db	FullSpeedConfigDscrEnd - FullSpeedConfigDscr		; Descriptor length
	db	DSCR_OTHERSPEED			; Descriptor type = OTHER SPEED CONFIG
	db	LOW(FS_End-FullSpeedConfigDscr)	; Total length (conf+interface+HID+EP's)
	db	HIGH(FS_End-FullSpeedConfigDscr)
	db	01h				; Number of interfaces
	db	01h				; Value to select this interface
	db	03h				; String index to describe this config
	db	10100000b			; b7=1; b6=self-powered; b5=Remote WU
	db	0d				; bus power = 80 ma
FullSpeedConfigDscrEnd:
 
FullSpeedIntrfcDscr:				; Interface Descriptor
	db	FullSpeedIntrfcDscrEnd -  FullSpeedIntrfcDscr	; Descriptor length
	db	DSCR_INTRFC			; Descriptor type: INTERFACE
	db	0,0				; Interface 0, Alternate setting 0
	db	02h				; Number of endpoints
	db	03h,0,0				; Class(03)HID, no subclass or protocol
	db	0h				; string index for this interface
FullSpeedIntrfcDscrEnd:


FullSpeedHIDDscr:
	db	FullSpeedHIDDscrEnd -FullSpeedHIDDscr	; Descriptor length
	db	21h				; Descriptor type - HID
	db	10h,01h				; HID Spec version 1.10
	db	0				; country code(none)
	db	01h				; number of HID class descriptors
	db	22h				; class descriptor type: REPORT
	db	LOW(ReportDscrEnd - ReportDscr)
	db	HIGH(ReportDscrEnd - ReportDscr)
FullSpeedHIDDscrEnd:

FSEpInDscr:	
	db	FSEpInDscrEnd - FSEpInDscr	; Descriptor length
	db	DSCR_ENDPNT			; Descriptor type : ENDPOINT
	db	81h				; IN-1
	db	ET_INT				; Type: INTERRUPT
	db	40h,0				; maxPacketSize = 64
	db	01h				; polling interval is 50 msec
FSEpInDscrEnd:

FSEpOutDscr:	
	db	FSEpOutDscrEnd - FSEpOutDscr	; Descriptor length
	db	DSCR_ENDPNT			; Descriptor type = ENDPOINT
	db	01h				; OUT-1
	db	ET_INT				; type - INTERRUPT
	db	40h,0				; maxPacketSize = 64
	db	01h				; polling interval is 50 msec
FSEpOutDscrEnd:
FS_End:

    	db  00h         ;Word alignment

;; usbhidio code start
ReportDscr:

	db 06h, 0A0h, 0FFh ;    Usage Page (FFA0h, vendor defined)
	db 09h, 01h     ;       Usage (vendor defined)
	db 0A1h, 01h    ;       Collection (Application)
	db 09h, 02h     ;       Usage (vendor defined)
	db 0A1h, 00h    ;       Collection (Physical)
	db 06h, 0A1h, 0FFh ;    Usage Page (vendor defined)

;; The Input report
	db 09h, 03h     ;       Usage (vendor defined)
	db 09h, 04h     ;       Usage (vendor defined)
	db 15h, 80h	;	Logical minimum (80h or -128)
	db 25h, 7Fh	;	Logical maximum (7Fh or 127)
	db 35h, 00h	;	Physical minimum (0)
	db 45h, 0FFh	;	Physical maximum (255)
	db 75h, 08h	;	Report size (8 bits)
	db 95h, 80h	;	Report count (128 fields)
	db 81h, 02h	;	Input (data, variable, absolute)

;; The Output report
	db 09h, 05h     ;       Usage (vendor defined)
	db 09h, 06h     ;       Usage (vendor defined)
	db 15h, 80h	;	Logical minimum (80h or -128)
	db 25h, 7Fh	;	Logical maximum (7Fh or 127)
	db 35h, 00h	;	Physical minimum (0)
	db 45h, 0FFh	;	Physical maximum (255)
	db 75h, 08h	;	Report size (8 bits)
	db 95h, 80h	;	Report count (128 fields)
	db 91h, 02h	;	Output (data, variable, absolute)

	db 0C0h         ;       End Collection (Physical)
	db 0C0h         ;       End Collection (Application)

ReportDscrEnd:

ReportEnd_word_allignment:
;; Alignment unneeded for usbhidio report because it has an even number of bytes.
;;   	db  00h         ;Force word alignment

;; usbhdio code end

/* Descriptor for Cypress keyboard example (unused by usbhidio)
ReportDscr:
	db 05h, 01h     ; Usage Page (Generic Desktop)
	db 09h, 06h     ; Usage (Keyboard)
	db 0A1h, 01h     ; Collection (Application)
	db 05h, 07h     ;       Usage Page (Key codes)
	db 19h, 0E0h	;	Usage minimum (234)
	db 29h, 0E7h	;	Usage maximum (231)
	db 15h, 00h	;	Logical minimum (0)
	db 25h, 01h	;	Logical maximum (1)
	db 75h, 01h	;	Report size (1)
	db 95h, 08h	;	Report count (8)
	db 81h, 02h	;	Input (data, variable, absolute)
	db 95h, 01h	;	Report count (1)
	db 75h, 08h	;	Report size (8)
	db 81h, 01h	;	Input (constant)
	db 95h, 05h	;	Report count (5)
	db 75h, 01h	;	Report size (1)
	db 05h, 08h	;	Usage Page (LED)
	db 19h, 01h	;	Usage minimum (1)
	db 29h, 05h	;	Usage maximum (5)
	db 91h, 02h	;	Output (data, variable, absolute)
	db 95h, 01h	;	Report count (1)
	db 75h, 03h	;	Report size (3)
	db 91h, 01h	;	Output (constant)
	db 95h, 03h	;	Report count (3)
	db 75h, 08h	;	Report size (8)
	db 15h, 00h	;	Logical minimum (0)
	db 25h, 65h	;	Logical maximum (101)
	db 05h, 07h	;	Usage page (key codes)
	db 19h, 00h	;	Usage minimum (0)
	db 29h, 65h	;	Usage maximum (101)
	db 81h, 00h	;	Input (data, array)
	db 0C0h          ; End Collection
ReportDscrEnd:

ReportEnd_word_allignment:
   	db  00h         ;Force word alignment

*/

StringDscr:
StringDscr0:
		db	StringDscr0End-StringDscr0		;; String descriptor length
		db	DSCR_STRING
		db	09H,04H
StringDscr0End:

StringDscr1:	
		db	StringDscr1End-StringDscr1		;; String descriptor length
		db	DSCR_STRING
		db	'C',00
		db	'Y',00
		db	'P',00
		db	'R',00
		db	'E',00
		db	'S',00
		db	'S',00

StringDscr1End:
StringDscr2:	
		db	StringDscr2End-StringDscr2		;; Descriptor length
		db	DSCR_STRING
		db	'E',00
		db	'Z',00
		db	'-',00
		db	'U',00
		db	'S',00
		db	'B',00
		db	' ',00
		db	'F',00
		db	'X',00
		db	'2',00
		db	' ',00
		db	'H',00
		db	'I',00
		db	'D',00
		db	' ',00
		db	'U',00
		db	'S',00
		db	'B',00
		db	'H',00
		db	'I',00
		db	'D',00
		db	'I',00
		db	'O',00
	
StringDscr2End:
	
UserDscr:		
		dw	0000H
		end

Full source codes and binaries:
fx2hid_128bytes_report.zip

@mcuee
Copy link
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     [email protected]:/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
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
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
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
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
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
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
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

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.

4 participants