Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .github/workflows/builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt update
sudo apt install libudev-dev libusb-1.0-0-dev python3-pip ninja-build
sudo apt install autoconf automake libudev-dev libusb-1.0-0-dev pkg-config python3-pip ninja-build
sudo -H pip3 install meson
- name: Configure CMake
run: |
Expand All @@ -138,6 +138,15 @@ jobs:
- name: Build CMake Static
working-directory: build/static
run: make install
- name: Check pkg-config package
run: |
autoreconf --install --force hidapisrc/tests/pkg-config
mkdir -p build/pkg-config-test
cd build/pkg-config-test
CFLAGS="${GNU_COMPILE_FLAGS}" \
PKG_CONFIG_PATH="${GITHUB_WORKSPACE}/install/shared/lib/pkgconfig" \
"${GITHUB_WORKSPACE}/hidapisrc/tests/pkg-config/configure"
make V=1
- name: Run virtual-device tests (uhid -> hidraw; raw-gadget self-skips)
working-directory: build/shared
run: |
Expand All @@ -156,6 +165,7 @@ jobs:
with:
files: "install/shared/lib/libhidapi-libusb.so, \
install/shared/lib/libhidapi-hidraw.so, \
install/shared/lib/pkgconfig/hidapi.pc, \
install/shared/include/hidapi/hidapi.h, \
install/shared/include/hidapi/hidapi_libusb.h, \
install/static/lib/libhidapi-libusb.a, \
Expand Down
38 changes: 38 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,41 @@ session itself should be included, as it is not publicly accessible.
When a PR fixes an issue or relates to / replaces another issue, the PR description should
include a reference to the issue number after the main description but before the
`Assisted-by:` attribution, e.g. `Fixes: #123` or `Closes: #124`.

## HIDAPI API usage contract

This is the contract HIDAPI expects of its callers. It governs both code review and code
generation: judge the library's behaviour only against usage that respects it, and only
generate example/test code that respects it. The authoritative reference is
[Multi‐threading Notes](https://github.com/libusb/hidapi/wiki/Multi%E2%80%90threading-Notes).

### Library lifecycle

- Call `hid_init()` before any other HIDAPI function. Implicit lazy initialization exists, but
must not be relied upon when more than one thread may make the first call.
- Call `hid_exit()` last, after every device has been closed. `hid_exit()` deinitializes the
whole library; no HIDAPI function other than a new `hid_init()` may be called after it, and
device handles obtained before it are invalid.
- `hid_init()`/`hid_exit()` must never run concurrently with any other HIDAPI function.

### Concurrency

- HIDAPI v0.x.x is **not thread-safe**. The following must not be called concurrently from
different threads: `hid_init`, `hid_exit`, `hid_enumerate`, `hid_open`, `hid_open_path`,
`hid_close`, `hid_error(NULL)` — the global error string is one reason.
- Functions taking a `hid_device *` are not individually thread-safe, but different devices may
be used from different threads — i.e. a dedicated thread per device.
- `hid_close()` must be serialized against initialization and enumeration calls.
- Since v0.15.0, a dedicated read thread using only `hid_read`, `hid_read_timeout` and
`hid_read_error` is safe alongside other operations on the same device from another thread.
Do not use `hid_error` from such a thread; use `hid_read_error`.
- macOS: `hid_init()` and `hid_exit()` must be called from the same thread, and that thread must
stay alive until all devices are closed and `hid_exit()` has completed.

### For AI agents and reviewers

A finding whose trigger requires violating this contract is application misuse, not a library
defect. Examples: calling `hid_exit()` while other threads still use the API, using device
handles after `hid_exit()`, unsynchronized concurrent first-time initialization. Do not report
such scenarios as bugs, and do not add locking or other synchronization to "fix" them. Hardening
the library against misuse is a maintainer design decision, not a review fix.
33 changes: 29 additions & 4 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,30 @@ else
pkgconfigdir=$(libdir)/pkgconfig
endif

if OS_LINUX
pkgconfig_DATA=pc/hidapi-hidraw.pc pc/hidapi-libusb.pc
else
pkgconfig_DATA=pc/hidapi.pc

if OS_LINUX
pkgconfig_DATA += pc/hidapi-hidraw.pc pc/hidapi-libusb.pc
endif

if OS_DARWIN
pkgconfig_DATA += pc/hidapi-darwin.pc
endif

if OS_FREEBSD
pkgconfig_DATA += pc/hidapi-libusb.pc
endif

if OS_KFREEBSD
pkgconfig_DATA += pc/hidapi-libusb.pc
endif

if OS_HAIKU
pkgconfig_DATA += pc/hidapi-libusb.pc
endif

if OS_WINDOWS
pkgconfig_DATA += pc/hidapi-winapi.pc
endif

SUBDIRS=
Expand Down Expand Up @@ -45,7 +65,12 @@ if BUILD_TESTGUI
SUBDIRS += testgui
endif

EXTRA_DIST = udev doxygen
EXTRA_DIST = \
udev \
doxygen \
tests/pkg-config/configure.ac \
tests/pkg-config/Makefile.am \
tests/pkg-config/test.c

dist_doc_DATA = \
README.md \
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ this is not a problem.
This back-end uses libusb-1.0 to communicate directly to a USB device. This
back-end will of course not work with Bluetooth devices.

Starting with HIDAPI 0.16, this back-end requires libusb 1.0.16 or newer.

### Test GUI

HIDAPI also comes with a Test GUI. The Test GUI is cross-platform and uses
Expand Down
56 changes: 48 additions & 8 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ case $host in

# HIDAPI/libusb libs
AC_CHECK_LIB([rt], [clock_gettime], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -lrt"], [hidapi_lib_error librt])
PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.9], true, [hidapi_lib_error libusb-1.0])
PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.16], true, [hidapi_lib_error libusb-1.0])
LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} $libusb_LIBS"
CFLAGS_LIBUSB="${CFLAGS_LIBUSB} $libusb_CFLAGS"
;;
Expand All @@ -87,7 +87,7 @@ case $host in
CFLAGS="$CFLAGS -I/usr/local/include"
LDFLAGS="$LDFLAGS -L/usr/local/lib"
LIBS="${LIBS}"
PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.9], true, [hidapi_lib_error libusb-1.0])
PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.16], true, [hidapi_lib_error libusb-1.0])
LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} $libusb_LIBS"
CFLAGS_LIBUSB="${CFLAGS_LIBUSB} $libusb_CFLAGS"
AC_CHECK_LIB([iconv], [iconv_open], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -liconv"], [hidapi_lib_error libiconv])
Expand All @@ -100,7 +100,7 @@ case $host in
os="kfreebsd"
threads="pthreads"

PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.9], true, [hidapi_lib_error libusb-1.0])
PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.16], true, [hidapi_lib_error libusb-1.0])
LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} $libusb_LIBS"
CFLAGS_LIBUSB="${CFLAGS_LIBUSB} $libusb_CFLAGS"
;;
Expand All @@ -112,7 +112,7 @@ case $host in
os="haiku"
threads="pthreads"

PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.9], true, [hidapi_lib_error libusb-1.0])
PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.16], true, [hidapi_lib_error libusb-1.0])
LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} $libusb_LIBS"
CFLAGS_LIBUSB="${CFLAGS_LIBUSB} $libusb_CFLAGS"
AC_CHECK_LIB([iconv], [libiconv_open], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -liconv"], [hidapi_lib_error libiconv])
Expand Down Expand Up @@ -237,12 +237,52 @@ AM_CONDITIONAL(OS_WINDOWS, test "x$os" = xwindows)

AC_CONFIG_HEADERS([config.h])

m4_define([HIDAPI_CONFIGURE_BACKEND_PC], [
AC_CONFIG_FILES([$1:pc/hidapi-backend-specific.pc.in], [
sed \
-e "s|@HIDAPI_BACKEND_NAME@|$2|g" \
-e "s|@HIDAPI_BACKEND_DESCRIPTION@|$3|g" \
-e "s|@HIDAPI_BACKEND_LIBRARY_NAME@|$4|g" \
"$1" > "$1.tmp" &&
mv "$1.tmp" "$1"
], [$5])
])

HIDAPI_LIB_NAME=hidapi
HIDAPI_LIBUSB_LIB_NAME=hidapi
if test "x$os" = "xlinux"; then
AC_CONFIG_FILES([pc/hidapi-hidraw.pc])
AC_CONFIG_FILES([pc/hidapi-libusb.pc])
else
AC_CONFIG_FILES([pc/hidapi.pc])
HIDAPI_LIB_NAME=hidapi-hidraw
HIDAPI_LIBUSB_LIB_NAME=hidapi-libusb
HIDAPI_CONFIGURE_BACKEND_PC(
[pc/hidapi-hidraw.pc],
[hidapi-hidraw],
[C Library for USB/Bluetooth HID device access from Linux, Mac OS X, FreeBSD, and Windows. This is the hidraw implementation.],
[hidapi-hidraw])
elif test "x$os" = "xdarwin"; then
HIDAPI_CONFIGURE_BACKEND_PC(
[pc/hidapi-darwin.pc],
[hidapi-darwin],
[C Library for USB/Bluetooth HID device access from Linux, Mac OS X, FreeBSD, and Windows. This is the Darwin implementation.],
[hidapi])
elif test "x$os" = "xwindows"; then
HIDAPI_CONFIGURE_BACKEND_PC(
[pc/hidapi-winapi.pc],
[hidapi-winapi],
[C Library for USB/Bluetooth HID device access from Linux, Mac OS X, FreeBSD, and Windows. This is the WinAPI implementation.],
[hidapi])
fi
if test "x$os" != "xdarwin" && test "x$os" != "xwindows"; then
HIDAPI_CONFIGURE_BACKEND_PC(
[pc/hidapi-libusb.pc],
[hidapi-libusb],
[C Library for USB HID device access from Linux, Mac OS X, FreeBSD, and Windows. This is the libusb implementation.],
[$hidapi_libusb_lib_name],
[hidapi_libusb_lib_name="$HIDAPI_LIBUSB_LIB_NAME"])
fi
m4_undefine([HIDAPI_CONFIGURE_BACKEND_PC])

AC_SUBST([HIDAPI_LIB_NAME])
AC_CONFIG_FILES([pc/hidapi.pc])

AC_SUBST(LTLDFLAGS)

Expand Down
8 changes: 6 additions & 2 deletions libusb/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ if(TARGET usb-1.0)
target_link_libraries(hidapi_libusb PRIVATE usb-1.0)
else()
include(FindPkgConfig)
pkg_check_modules(libusb REQUIRED IMPORTED_TARGET libusb-1.0>=1.0.9)
pkg_check_modules(libusb REQUIRED IMPORTED_TARGET libusb-1.0>=1.0.16)
target_link_libraries(hidapi_libusb PRIVATE PkgConfig::libusb)
endif()

Expand Down Expand Up @@ -105,4 +105,8 @@ if(HIDAPI_INSTALL_TARGETS)
)
endif()

hidapi_configure_pc("${PROJECT_ROOT}/pc/hidapi-libusb.pc.in")
hidapi_configure_pc("${PROJECT_ROOT}/pc/hidapi-backend-specific.pc.in"
OUTPUT_NAME "hidapi-libusb"
LIBRARY_NAME "hidapi-libusb"
DESCRIPTION "C Library for USB HID device access from Linux, Mac OS X, FreeBSD, and Windows. This is the libusb implementation."
)
Loading
Loading