Skip to content

Add hid_set_input_report_buffer_size() API#787

Open
auxcorelabs wants to merge 2 commits intolibusb:masterfrom
auxcorelabs:feature/input-report-buffer-size
Open

Add hid_set_input_report_buffer_size() API#787
auxcorelabs wants to merge 2 commits intolibusb:masterfrom
auxcorelabs:feature/input-report-buffer-size

Conversation

@auxcorelabs
Copy link
Copy Markdown

Exposes a new public function hid_set_input_report_buffer_size(dev, size) to resize the per-device input report queue.

High-throughput HID devices (medical telemetry, high-poll-rate gaming peripherals, data acquisition hardware) can emit bursts of input reports that exceed the current hardcoded queue sizes (30 on macOS and Linux/libusb, 64 on Windows). When a burst exceeds the queue, reports are silently dropped with no error indication to the caller. Observed on hardware emitting ~90 reports in 200 ms bursts: both the macOS and Linux/libusb backends silently drop ~20% of frames.

Per-backend behavior

  • macOS: resizes the userspace IOHIDQueue-fed report queue
  • Linux libusb: resizes the userspace report queue
  • Windows: wraps HidD_SetNumInputBuffers (parity with existing behavior)
  • Linux hidraw / NetBSD: no-op (kernel manages buffering)

Safety

  • Values outside [1, HID_API_MAX_INPUT_REPORT_BUFFER_SIZE] return -1; NULL dev returns -1 with a global error
  • Thread-safe: setter uses the same lock (dev->mutex / dev->thread_state) as the respective report callback

Design notes

  • Backwards compatibility: Purely additive public API. Defaults per backend are unchanged, so existing callers see no behavioral change. hid_device is opaque in hidapi.h, so struct field additions in backend-private files are not an ABI break.
  • Why 1024 cap: Bounds per-device memory to roughly 1 MB on USB high-speed links, preventing memory exhaustion from a caller that passes INT_MAX (malicious or buggy). We've measured bursts up to ~90 reports deep in practice; 1024 leaves room for devices ~10× more demanding. Overridable via -DHID_API_MAX_INPUT_REPORT_BUFFER_SIZE=N at build time for memory-constrained targets.
  • No getter: hidraw and NetBSD back the queue in the kernel with sizes not portably exposed to userspace, so a cross-platform getter couldn't return a meaningful value there.
  • Why not hid_get_input_report() instead? That API issues a host-initiated GET_REPORT request (via the control endpoint or OS equivalent). It does not drain the interrupt-endpoint queue that streaming devices fill, and in practice many devices either don't implement GET_REPORT for input reports or respond incorrectly. The two APIs use different USB transfer mechanisms (interrupt endpoint vs. control endpoint); this PR fixes the interrupt-streaming path.

References

CI equivalent status

All upstream CI equivalents tested locally:

Platform Compiler Flags Result
Linux (libusb + hidraw, shared + static) gcc -Wall -Wextra -pedantic -Werror -Wformat-signedness Pass
Linux with ASAN gcc same + HIDAPI_ENABLE_ASAN=ON Pass
macOS gcc (Xcode) -Wall -Wextra -pedantic -Werror Pass
Windows x64 / x86 MSVC 19.44 /W4 /WX Pass

Zero warnings on all platforms. Symbol verified exported in all built artifacts.

Exposes a new public function to resize the per-device input report
queue. High-throughput HID devices (medical telemetry, high-poll-rate
gaming peripherals, data acquisition hardware) emit bursts of input
reports that exceed the current hardcoded queue sizes (30 on macOS and
the libusb backend, 64 on Windows). When a burst exceeds the queue,
reports are silently dropped with no error indication to the caller.

This adds:
- hid_set_input_report_buffer_size(dev, size) in hidapi.h
- HID_API_MAX_INPUT_REPORT_BUFFER_SIZE (1024) cap to prevent unbounded
  memory growth

Per-backend behavior:
- macOS: resizes the userspace IOHIDQueue-fed report queue
- Linux libusb: resizes the userspace report queue
- Windows: wraps HidD_SetNumInputBuffers (parity with existing behavior)
- Linux hidraw: no-op (kernel manages buffering)
- NetBSD: no-op (kernel manages buffering)

Defaults are unchanged, so existing callers are unaffected. Values
outside [1, HID_API_MAX_INPUT_REPORT_BUFFER_SIZE] are rejected with -1.
Thread-safe on macOS (dev->mutex) and libusb (dev->thread_state),
matching the locks used by the respective report callbacks.

Addresses the same need as closed issue libusb#154 (HidD_SetNumInputBuffers
exposure) and complements libusb#725 (callback-based input API).
@mcuee mcuee added API API change, Version 1 stuff enhancement New feature or request labels Apr 17, 2026
Comment thread linux/hid.c Outdated
Comment on lines +1205 to +1208
if (!dev) {
register_global_error("Device is NULL");
return -1;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

remove this check (from all backends) - device functions do not check for validity of the device handle
the only exception is hid_close

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks. done.

Comment thread linux/hid.c Outdated
Comment on lines +1213 to +1215
/* hidraw: kernel manages the input report buffer, no userspace queue
to resize. Accept the call to preserve a consistent cross-platform
API so callers do not need per-backend conditional code. */
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

too bad we don't have a logging mechanism
this looks like a perfect spot for a warning
making this completely silent might confuse some users

anyway - even though documentation mentiones that there is no user-space queue for linux backend - we should explicitly document that this function for linux and bsd backend is a no-op

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Have updated the comment to explicitly call out no-op. Thanks

Comment thread mac/hid.c Outdated
Comment on lines +1355 to +1358
if (!dev) {
register_global_error("Device is NULL");
return -1;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

remove

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks. done.

Comment thread netbsd/hid.c Outdated
Comment on lines +961 to +964
if (!dev) {
register_global_error("Device is NULL");
return -1;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

remove

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks done.

Comment thread windows/hid.c Outdated
Comment on lines +1263 to +1266
if (!dev) {
register_global_error(L"Device is NULL");
return -1;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

remove

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks. done.

Copy link
Copy Markdown
Member

@Youw Youw left a comment

Choose a reason for hiding this comment

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

refer to comments, otherwise looks good

Per maintainer feedback on PR libusb#787:

- Remove if (!dev) validation from all 5 backends. hidapi convention is that device functions trust the caller to pass a valid handle; only hid_close is permitted to accept NULL.

- Reword the inline comment in linux/hid.c and netbsd/hid.c to lead with "No-op" so the caller-visible behavior is explicit at the implementation site.
@auxcorelabs
Copy link
Copy Markdown
Author

Thanks for reviewing. I have made the changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

API API change, Version 1 stuff enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants