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

@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

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

mcuee commented Jun 16, 2025

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

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

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

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

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.

6 participants