Import 'libusb1-sys' crate
Request Document: go/android-rust-importing-crates
For CL Reviewers: go/android3p#cl-review
For Build Team: go/ab-third-party-imports
Bug: 376649133
Test: m liblibusb1-sys
Change-Id: I41f6c1d5b2163e06690d7ac1b90fab3a3f4559dc
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..ce59553
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,63 @@
+package {
+ default_applicable_licenses: ["external_rust_crates_libusb1-sys_license"],
+ default_team: "trendy_team_android_rust",
+}
+
+license {
+ name: "external_rust_crates_libusb1-sys_license",
+ visibility: [":__subpackages__"],
+ license_kinds: ["SPDX-license-identifier-MIT"],
+ license_text: ["LICENSE"],
+}
+
+rust_library {
+ name: "liblibusb1_sys",
+ host_supported: true,
+ crate_name: "libusb1_sys",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.7.0",
+ crate_root: "src/lib.rs",
+ edition: "2018",
+ rustlibs: ["liblibc"],
+ shared_libs: ["libusb"],
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
+ vendor_available: true,
+}
+
+rust_test {
+ name: "libusb1-sys_test_src_lib",
+ host_supported: true,
+ crate_name: "libusb1_sys",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.7.0",
+ crate_root: "src/lib.rs",
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ test_options: {
+ unit_test: true,
+ },
+ edition: "2018",
+ rustlibs: ["liblibc"],
+}
+
+rust_test {
+ name: "libusb1-sys_test_tests_test",
+ host_supported: true,
+ crate_name: "test",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.7.0",
+ crate_root: "tests/test.rs",
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ test_options: {
+ unit_test: true,
+ },
+ edition: "2018",
+ rustlibs: [
+ "liblibc",
+ "liblibusb1_sys",
+ ],
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..8f1acf6
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,54 @@
+# Changes
+
+## 0.7.0
+
+* fix: Add missing fields to libusb_bos_descriptor and libusb_bos_dev_capability_descriptor [#161]
+* Bump libusb to 1.0.27 [#201]
+* Remove unneeded mut [#204]
+
+[#161]: https://github.com/a1ien/rusb/pull/161
+[#201]: https://github.com/a1ien/rusb/pull/201
+[#204]: https://github.com/a1ien/rusb/pull/204
+
+## 0.6.5
+* Support pkg_config for MSVC. [#191]
+* Fix package detection and build when cross-compiling from MSVC to GNU [#180]
+* libusb_set_iso_packet_lengths panics on debug builds in newest nightly (2024-03-27) [#199]
+* Added libusb_free_pollfds() in the available FFI methods. [#203]
+
+[#191]: https://github.com/a1ien/rusb/pull/191
+[#180]: https://github.com/a1ien/rusb/pull/180
+[#199]: https://github.com/a1ien/rusb/pull/199
+[#203]: https://github.com/a1ien/rusb/pull/203
+
+## 0.6.3-0.6.4
+* Patch for macOS Big Sur and newer allowing to link statically [#133]
+* Add libudev include paths as specified by pkg-config [#140]
+
+[#133]: https://github.com/a1ien/rusb/pull/133
+[#140]: https://github.com/a1ien/rusb/pull/140
+
+
+## 0.6.2
+* Rename compiled library when vendored libusb is used [#130]
+
+[#130]: https://github.com/a1ien/rusb/pull/130
+
+## 0.6.1
+* Add LIBUSB_OPTION_NO_DEVICE_DISCOVERY constant
+* Bump vendored libusb version from 1.0.24 to 1.0.25 [#119]
+
+[#119]: https://github.com/a1ien/rusb/pull/119
+
+## 0.6.0
+* Allow null function pointers for libusb_set_log_cb() [#74]
+* Allow null function pointers for libusb_set_pollfd_notifiers() [#71]
+* Fix building of recent libusb on macOS [#108]
+* Ignore vendored feature on FreeBSD [#109]
+* Update definitions [#112]
+
+[#74]: https://github.com/a1ien/rusb/pull/74
+[#71]: https://github.com/a1ien/rusb/pull/71
+[#108]: https://github.com/a1ien/rusb/pull/108
+[#109]: https://github.com/a1ien/rusb/pull/109
+[#112]: https://github.com/a1ien/rusb/pull/112
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..7743a4b
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,37 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cc"
+version = "1.0.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"
+
+[[package]]
+name = "libc"
+version = "0.2.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
+
+[[package]]
+name = "libusb1-sys"
+version = "0.7.0"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..67ecedb
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,64 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+name = "libusb1-sys"
+version = "0.7.0"
+authors = [
+ "David Cuddeback <[email protected]>",
+ "Ilya Averyanov <[email protected]>",
+]
+build = "build.rs"
+links = "usb-1.0"
+include = [
+ "/exaples",
+ "/libusb/libusb",
+ "/libusb/msvc",
+ "/src/*",
+ "/tests",
+ "build.rs",
+ "Cargo.toml",
+ "LICENSE",
+ "README.md",
+ "CHANGELOG.md",
+ "COPYING",
+ "AUTHORS",
+]
+description = "FFI bindings for libusb."
+homepage = "https://github.com/a1ien/rusb"
+readme = "README.md"
+keywords = [
+ "usb",
+ "libusb",
+ "hardware",
+ "bindings",
+]
+license = "MIT"
+repository = "https://github.com/a1ien/rusb.git"
+
+[dependencies.libc]
+version = "0.2"
+
+[build-dependencies.cc]
+version = "1.0"
+
+[build-dependencies.pkg-config]
+version = "0.3"
+
+[features]
+vendored = []
+
+[target."cfg(target_os = \"windows\")".build-dependencies.vcpkg]
+version = "0.2"
+
+[badges.travis-ci]
+repository = "a1ien/libusb1-sys"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..c4d4fb7
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,47 @@
+[package]
+
+name = "libusb1-sys"
+version = "0.7.0"
+authors = ["David Cuddeback <[email protected]>",
+ "Ilya Averyanov <[email protected]>"]
+description = "FFI bindings for libusb."
+license = "MIT"
+homepage = "https://github.com/a1ien/rusb"
+repository = "https://github.com/a1ien/rusb.git"
+readme = "README.md"
+keywords = ["usb", "libusb", "hardware", "bindings"]
+edition = "2018"
+links = "usb-1.0" # Required for metadata passing to work
+
+include = [
+ "/exaples",
+ "/libusb/libusb",
+ "/libusb/msvc",
+ "/src/*",
+ "/tests",
+ "build.rs",
+ "Cargo.toml",
+ "LICENSE",
+ "README.md",
+ "CHANGELOG.md",
+ "COPYING",
+ "AUTHORS",
+]
+
+build = "build.rs"
+
+[badges]
+travis-ci = { repository = "a1ien/libusb1-sys" }
+
+[features]
+vendored = []
+
+[dependencies]
+libc = "0.2"
+
+[target.'cfg(target_os = "windows")'.build-dependencies]
+vcpkg = "0.2"
+
+[build-dependencies]
+cc = "1.0"
+pkg-config = "0.3"
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..cf8ea43
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+Copyright (c) 2015 David Cuddeback
+ 2019 Ilya Averyanov
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..3f30ab2
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,20 @@
+name: "libusb1-sys"
+description: "FFI bindings for libusb."
+third_party {
+ identifier {
+ type: "crates.io"
+ value: "libusb1-sys"
+ }
+ identifier {
+ type: "Archive"
+ value: "https://static.crates.io/crates/libusb1-sys/libusb1-sys-0.7.0.crate"
+ primary_source: true
+ }
+ version: "0.7.0"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2024
+ month: 11
+ day: 8
+ }
+}
diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_MIT
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..4455493
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 688011
+include platform/prebuilts/rust:main:/OWNERS
[email protected]
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..bc4f2c6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,92 @@
+# Libusb Rust Bindings
+
+The `libusb1-sys` crate provides declarations and linkage for the `libusb` C library. Following the
+`*-sys` package conventions, the `libusb1-sys` crate does not define higher-level abstractions over
+the native `libusb` library functions.
+
+## Dependencies
+In order to use the `libusb1-sys` crate, you must have the `libusb` library installed where it can be
+found by `pkg-config`.
+
+All systems supported by `libusb` are also supported by the `libusb1-sys` crate. It's been tested on
+Linux, OS X, and Windows.
+
+### Cross-Compiling
+To link to a cross-compiled version of the native `libusb` library, it's necessary to set several
+environment variables to configure `pkg-config` to work with a cross-compiler's sysroot. [Autotools
+Mythbuster](https://autotools.io/) has a good explanation of [supporting
+cross-compilation](https://autotools.io/pkgconfig/cross-compiling.html) with `pkg-config`.
+
+However, Rust's [`pkg-config` build helper](https://github.com/alexcrichton/pkg-config-rs) doesn't
+support calling a `$CHOST`-prefixed `pkg-config`. It will always call `pkg-config` without a prefix.
+To cross-compile `libusb1-sys` with the `pkg-config` build helper, one must define the environment
+variables `PKG_CONFIG_DIR`, `PKG_CONFIG_LIBDIR`, and `PKG_CONFIG_SYSROOT_DIR` for the *default*
+`pkg-config`. It's also necessary to set `PKG_CONFIG_ALLOW_CROSS` to tell Rust's `pkg-config` helper
+that it's okay to proceed with a cross-compile.
+
+To adapt the `pkg-config` wrapper in the Autotools Mythbuster guide so that it works with Rust, one
+will end up with a script similar to the following:
+
+```sh
+#!/bin/sh
+
+SYSROOT=/build/root
+
+export PKG_CONFIG_DIR=
+export PKG_CONFIG_LIBDIR=${SYSROOT}/usr/lib/pkgconfig:${SYSROOT}/usr/share/pkgconfig
+export PKG_CONFIG_SYSROOT_DIR=${SYSROOT}
+export PKG_CONFIG_ALLOW_CROSS=1
+
+cargo build
+```
+
+## Usage
+Add `libusb1-sys` as a dependency in `Cargo.toml`:
+
+```toml
+[dependencies]
+libusb1-sys = "0.6"
+```
+
+Import the `libusb1_sys` crate and use the functions as they're defined in the native `libusb`
+library. See the [`libusb` 1.0 API documention](http://libusb.sourceforge.net/api-1.0/) for more
+usage information.
+
+```rust
+extern crate libusb1_sys as ffi;
+
+fn main() {
+ let version = unsafe { ffi::libusb_get_version() };
+
+ println!("libusb v{}.{}.{}.{}", version.major, version.minor, version.micro, version.nano);
+}
+```
+
+### Native dependencies
+
+`libusb1-sys` exports [metadata] so that dependent crates can find the correct `libusb.h` header
+and compile native code that depends on `libusb`. If a crate has a direct dependency on `libusb1-sys`,
+its build script has access to the following environment variables:
+
+* `DEP_USB_1.0_INCLUDE` contains the include path with the correct `libusb.h`
+* `DEP_USB_1.0_VENDORED` is set with a value of `1` if `libusb1-sys` compiled and linked to
+its vendored copy of `libusb`
+* `DEP_USB_1.0_STATIC` is set with a value of `1` if static linkage has been used instead of
+dynamic.
+
+[metadata]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key
+
+### Finding Help
+Since `libusb1-sys` is no more than a wrapper around the native `libusb` library, the best source for
+help is the information already available for `libusb`:
+
+* [Home Page](http://libusb.info/)
+* [API Documentation](http://libusb.sourceforge.net/api-1.0/)
+* [Source](https://github.com/libusb/libusb)
+
+
+## License
+Distributed under the [MIT License](LICENSE).
+
+### License note.
+If you link native `libusb` library statically then you must follow [GNU LGPL](https://github.com/libusb/libusb/blob/master/COPYING) from libusb.
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..bd1f43b
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,224 @@
+use std::{env, fs, path::PathBuf};
+
+static VERSION: &str = "1.0.27";
+
+fn link(name: &str, bundled: bool) {
+ use std::env::var;
+ let target = var("TARGET").unwrap();
+ let target: Vec<_> = target.split('-').collect();
+ if target.get(2) == Some(&"windows") {
+ println!("cargo:rustc-link-lib=dylib={}", name);
+ if bundled && target.get(3) == Some(&"gnu") {
+ let dir = var("CARGO_MANIFEST_DIR").unwrap();
+ println!("cargo:rustc-link-search=native={}/{}", dir, target[0]);
+ }
+ }
+}
+
+pub fn link_framework(name: &str) {
+ println!("cargo:rustc-link-lib=framework={}", name);
+}
+
+fn get_macos_major_version() -> Option<usize> {
+ if !cfg!(target_os = "macos") {
+ return None;
+ }
+
+ let output = std::process::Command::new("sw_vers")
+ .args(["-productVersion"])
+ .output()
+ .unwrap();
+ let version = std::str::from_utf8(&output.stdout).unwrap().trim_end();
+ let components: Vec<&str> = version.split('.').collect();
+ let major: usize = components[0].parse().unwrap();
+ Some(major)
+}
+
+fn find_libusb_pkg(statik: bool) -> bool {
+ if std::env::var("CARGO_CFG_TARGET_ENV") == Ok("msvc".into()) {
+ #[cfg(target_os = "windows")]
+ return match vcpkg::Config::new().find_package("libusb") {
+ Ok(_) => true,
+ Err(e) => {
+ if pkg_config::probe_library("libusb-1.0").is_ok() {
+ true
+ } else {
+ println!("Can't find libusb pkg: {:?}", e);
+ false
+ }
+ }
+ };
+ }
+ // https://github.com/rust-lang/rust/issues/96943
+ let needs_rustc_issue_96943_workaround: bool = get_macos_major_version()
+ .map(|major| major >= 11)
+ .unwrap_or_default();
+
+ match pkg_config::Config::new().statik(statik).probe("libusb-1.0") {
+ Ok(l) => {
+ for lib in l.libs {
+ if statik {
+ if needs_rustc_issue_96943_workaround && lib == "objc" {
+ continue;
+ }
+ println!("cargo:rustc-link-lib=static={}", lib);
+ }
+ }
+ // Provide metadata and include directory for dependencies
+ if statik {
+ println!("cargo:static=1");
+ }
+ assert!(l.include_paths.len() <= 1); // Cannot have multiple env vars with same name
+ for path in l.include_paths {
+ println!("cargo:include={}", path.to_str().unwrap());
+ }
+ println!("cargo:version_number={}", l.version);
+ true
+ }
+ Err(e) => {
+ println!("Can't find libusb pkg: {:?}", e);
+ false
+ }
+ }
+}
+
+fn make_source() {
+ let libusb_source = PathBuf::from("libusb");
+
+ /*
+ Example environment variables and values:
+
+ CARGO_CFG_TARGET_ARCH: aarch64
+ CARGO_CFG_TARGET_ENDIAN: little
+ CARGO_CFG_TARGET_ENV:
+ CARGO_CFG_TARGET_FAMILY: unix
+ CARGO_CFG_TARGET_OS: android
+ CARGO_CFG_TARGET_POINTER_WIDTH: 64
+ CARGO_CFG_TARGET_VENDOR: unknown
+ CARGO_CFG_UNIX:
+ */
+
+ // Provide metadata and include directory for dependencies
+ println!("cargo:vendored=1");
+ println!("cargo:static=1");
+ let include_dir = PathBuf::from(env::var("OUT_DIR").unwrap()).join("include");
+ fs::create_dir_all(&include_dir).unwrap();
+ fs::copy(
+ libusb_source.join("libusb/libusb.h"),
+ include_dir.join("libusb.h"),
+ )
+ .unwrap();
+ println!("cargo:include={}", include_dir.to_str().unwrap());
+
+ fs::File::create(format!("{}/{}", include_dir.display(), "config.h")).unwrap();
+ let mut base_config = cc::Build::new();
+ base_config.include(&include_dir);
+ base_config.include(libusb_source.join("libusb"));
+
+ base_config.define("PRINTF_FORMAT(a, b)", Some(""));
+ base_config.define("ENABLE_LOGGING", Some("1"));
+
+ if std::env::var("CARGO_CFG_TARGET_ENV") == Ok("msvc".into()) {
+ fs::copy(
+ libusb_source.join("msvc/config.h"),
+ include_dir.join("config.h"),
+ )
+ .unwrap();
+ }
+
+ if std::env::var("CARGO_CFG_TARGET_OS") == Ok("macos".into()) {
+ base_config.define("OS_DARWIN", Some("1"));
+ base_config.define("TARGET_OS_OSX", Some("1"));
+ base_config.file(libusb_source.join("libusb/os/darwin_usb.c"));
+ link_framework("CoreFoundation");
+ link_framework("IOKit");
+ link_framework("Security");
+ link("objc", false);
+ }
+
+ if std::env::var("CARGO_CFG_TARGET_OS") == Ok("linux".into())
+ || std::env::var("CARGO_CFG_TARGET_OS") == Ok("android".into())
+ {
+ base_config.define("OS_LINUX", Some("1"));
+ base_config.define("HAVE_ASM_TYPES_H", Some("1"));
+ base_config.define("_GNU_SOURCE", Some("1"));
+ base_config.define("HAVE_TIMERFD", Some("1"));
+ base_config.define("HAVE_EVENTFD", Some("1"));
+ base_config.file(libusb_source.join("libusb/os/linux_netlink.c"));
+ base_config.file(libusb_source.join("libusb/os/linux_usbfs.c"));
+ }
+
+ if std::env::var("CARGO_CFG_TARGET_FAMILY") == Ok("unix".into()) {
+ base_config.define("HAVE_SYS_TIME_H", Some("1"));
+ base_config.define("HAVE_NFDS_T", Some("1"));
+ base_config.define("PLATFORM_POSIX", Some("1"));
+ base_config.define("HAVE_CLOCK_GETTIME", Some("1"));
+ base_config.define(
+ "DEFAULT_VISIBILITY",
+ Some("__attribute__((visibility(\"default\")))"),
+ );
+
+ if let Ok(lib) = pkg_config::probe_library("libudev") {
+ base_config.define("USE_UDEV", Some("1"));
+ base_config.define("HAVE_LIBUDEV", Some("1"));
+ base_config.file(libusb_source.join("libusb/os/linux_udev.c"));
+ for path in lib.include_paths {
+ base_config.include(path.to_str().unwrap());
+ }
+ };
+
+ println!("Including posix!");
+ base_config.file(libusb_source.join("libusb/os/events_posix.c"));
+ base_config.file(libusb_source.join("libusb/os/threads_posix.c"));
+ }
+
+ if std::env::var("CARGO_CFG_TARGET_OS") == Ok("windows".into()) {
+ if std::env::var("CARGO_CFG_TARGET_ENV") == Ok("msvc".into()) {
+ base_config.flag("/source-charset:utf-8");
+ }
+
+ base_config.warnings(false);
+ base_config.define("OS_WINDOWS", Some("1"));
+ base_config.file(libusb_source.join("libusb/os/events_windows.c"));
+ base_config.file(libusb_source.join("libusb/os/threads_windows.c"));
+ base_config.file(libusb_source.join("libusb/os/windows_common.c"));
+ base_config.file(libusb_source.join("libusb/os/windows_usbdk.c"));
+ base_config.file(libusb_source.join("libusb/os/windows_winusb.c"));
+
+ base_config.define("DEFAULT_VISIBILITY", Some(""));
+ base_config.define("PLATFORM_WINDOWS", Some("1"));
+ link("user32", false);
+ }
+
+ base_config.file(libusb_source.join("libusb/core.c"));
+ base_config.file(libusb_source.join("libusb/descriptor.c"));
+ base_config.file(libusb_source.join("libusb/hotplug.c"));
+ base_config.file(libusb_source.join("libusb/io.c"));
+ base_config.file(libusb_source.join("libusb/strerror.c"));
+ base_config.file(libusb_source.join("libusb/sync.c"));
+
+ base_config.compile("usb-vendored");
+ println!("cargo:version_number={}", VERSION);
+}
+
+fn main() {
+ println!("cargo:rerun-if-env-changed=LIBUSB_STATIC");
+ let statik = {
+ if cfg!(target_os = "macos") {
+ match std::env::var("LIBUSB_STATIC").unwrap_or_default().as_ref() {
+ "" | "0" => false,
+ _ => true,
+ }
+ } else {
+ std::env::var("CARGO_CFG_TARGET_FEATURE")
+ .map(|s| s.contains("crt-static"))
+ .unwrap_or_default()
+ }
+ };
+
+ let is_freebsd = std::env::var("CARGO_CFG_TARGET_OS") == Ok("freebsd".into());
+
+ if (!is_freebsd && cfg!(feature = "vendored")) || !find_libusb_pkg(statik) {
+ make_source();
+ }
+}
diff --git a/src/constants.rs b/src/constants.rs
new file mode 100644
index 0000000..a1d9551
--- /dev/null
+++ b/src/constants.rs
@@ -0,0 +1,160 @@
+use crate::*;
+use libc::c_int;
+
+// libusb_error
+pub const LIBUSB_SUCCESS: c_int = 0;
+pub const LIBUSB_ERROR_IO: c_int = -1;
+pub const LIBUSB_ERROR_INVALID_PARAM: c_int = -2;
+pub const LIBUSB_ERROR_ACCESS: c_int = -3;
+pub const LIBUSB_ERROR_NO_DEVICE: c_int = -4;
+pub const LIBUSB_ERROR_NOT_FOUND: c_int = -5;
+pub const LIBUSB_ERROR_BUSY: c_int = -6;
+pub const LIBUSB_ERROR_TIMEOUT: c_int = -7;
+pub const LIBUSB_ERROR_OVERFLOW: c_int = -8;
+pub const LIBUSB_ERROR_PIPE: c_int = -9;
+pub const LIBUSB_ERROR_INTERRUPTED: c_int = -10;
+pub const LIBUSB_ERROR_NO_MEM: c_int = -11;
+pub const LIBUSB_ERROR_NOT_SUPPORTED: c_int = -12;
+pub const LIBUSB_ERROR_OTHER: c_int = -99;
+
+// libusb_transfer_status
+pub const LIBUSB_TRANSFER_COMPLETED: c_int = 0;
+pub const LIBUSB_TRANSFER_ERROR: c_int = 1;
+pub const LIBUSB_TRANSFER_TIMED_OUT: c_int = 2;
+pub const LIBUSB_TRANSFER_CANCELLED: c_int = 3;
+pub const LIBUSB_TRANSFER_STALL: c_int = 4;
+pub const LIBUSB_TRANSFER_NO_DEVICE: c_int = 5;
+pub const LIBUSB_TRANSFER_OVERFLOW: c_int = 6;
+
+pub const LIBUSB_TRANSFER_SHORT_NOT_OK: u8 = 1 << 0;
+pub const LIBUSB_TRANSFER_FREE_BUFFER: u8 = 1 << 1;
+pub const LIBUSB_TRANSFER_FREE_TRANSFER: u8 = 1 << 2;
+pub const LIBUSB_TRANSFER_ADD_ZERO_PACKET: u8 = 1 << 3;
+
+// libusb_capability
+pub const LIBUSB_CAP_HAS_CAPABILITY: u32 = 0x0000;
+pub const LIBUSB_CAP_HAS_HOTPLUG: u32 = 0x0001;
+pub const LIBUSB_CAP_HAS_HID_ACCESS: u32 = 0x0100;
+pub const LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER: u32 = 0x0101;
+
+//// libusb_log_level
+pub const LIBUSB_LOG_LEVEL_NONE: c_int = 0;
+pub const LIBUSB_LOG_LEVEL_ERROR: c_int = 1;
+pub const LIBUSB_LOG_LEVEL_WARNING: c_int = 2;
+pub const LIBUSB_LOG_LEVEL_INFO: c_int = 3;
+pub const LIBUSB_LOG_LEVEL_DEBUG: c_int = 4;
+
+// libusb_class_code
+pub const LIBUSB_CLASS_PER_INTERFACE: u8 = 0;
+pub const LIBUSB_CLASS_AUDIO: u8 = 1;
+pub const LIBUSB_CLASS_COMM: u8 = 2;
+pub const LIBUSB_CLASS_HID: u8 = 3;
+pub const LIBUSB_CLASS_PHYSICAL: u8 = 5;
+pub const LIBUSB_CLASS_PRINTER: u8 = 7;
+pub const LIBUSB_CLASS_IMAGE: u8 = 6;
+pub const LIBUSB_CLASS_MASS_STORAGE: u8 = 8;
+pub const LIBUSB_CLASS_HUB: u8 = 9;
+pub const LIBUSB_CLASS_DATA: u8 = 10;
+pub const LIBUSB_CLASS_SMART_CARD: u8 = 0x0B;
+pub const LIBUSB_CLASS_CONTENT_SECURITY: u8 = 0x0D;
+pub const LIBUSB_CLASS_VIDEO: u8 = 0x0E;
+pub const LIBUSB_CLASS_PERSONAL_HEALTHCARE: u8 = 0x0F;
+pub const LIBUSB_CLASS_DIAGNOSTIC_DEVICE: u8 = 0xDC;
+pub const LIBUSB_CLASS_WIRELESS: u8 = 0xE0;
+pub const LIBUSB_CLASS_APPLICATION: u8 = 0xFE;
+pub const LIBUSB_CLASS_VENDOR_SPEC: u8 = 0xFF;
+
+// libusb_speed
+pub const LIBUSB_SPEED_UNKNOWN: c_int = 0;
+pub const LIBUSB_SPEED_LOW: c_int = 1;
+pub const LIBUSB_SPEED_FULL: c_int = 2;
+pub const LIBUSB_SPEED_HIGH: c_int = 3;
+pub const LIBUSB_SPEED_SUPER: c_int = 4;
+pub const LIBUSB_SPEED_SUPER_PLUS: c_int = 5;
+
+// libusb_descriptor_type
+pub const LIBUSB_DT_DEVICE: u8 = 0x01;
+pub const LIBUSB_DT_CONFIG: u8 = 0x02;
+pub const LIBUSB_DT_STRING: u8 = 0x03;
+pub const LIBUSB_DT_INTERFACE: u8 = 0x04;
+pub const LIBUSB_DT_ENDPOINT: u8 = 0x05;
+pub const LIBUSB_DT_BOS: u8 = 0x0F;
+pub const LIBUSB_DT_DEVICE_CAPABILITY: u8 = 0x10;
+pub const LIBUSB_DT_HID: u8 = 0x21;
+pub const LIBUSB_DT_REPORT: u8 = 0x22;
+pub const LIBUSB_DT_PHYSICAL: u8 = 0x23;
+pub const LIBUSB_DT_HUB: u8 = 0x29;
+pub const LIBUSB_DT_SUPERSPEED_HUB: u8 = 0x2A;
+pub const LIBUSB_DT_SS_ENDPOINT_COMPANION: u8 = 0x30;
+
+// libusb_endpoint_direction
+pub const LIBUSB_ENDPOINT_ADDRESS_MASK: u8 = 0x0F;
+pub const LIBUSB_ENDPOINT_DIR_MASK: u8 = 0x80;
+pub const LIBUSB_ENDPOINT_IN: u8 = 0x80;
+pub const LIBUSB_ENDPOINT_OUT: u8 = 0x00;
+
+// libusb_transfer_type
+pub const LIBUSB_TRANSFER_TYPE_MASK: u8 = 0x03;
+pub const LIBUSB_TRANSFER_TYPE_CONTROL: u8 = 0;
+pub const LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: u8 = 1;
+pub const LIBUSB_TRANSFER_TYPE_BULK: u8 = 2;
+pub const LIBUSB_TRANSFER_TYPE_INTERRUPT: u8 = 3;
+pub const LIBUSB_TRANSFER_TYPE_BULK_STREAM: u8 = 4;
+
+// libusb_iso_sync_type
+pub const LIBUSB_ISO_SYNC_TYPE_MASK: u8 = 0x0C;
+pub const LIBUSB_ISO_SYNC_TYPE_NONE: u8 = 0;
+pub const LIBUSB_ISO_SYNC_TYPE_ASYNC: u8 = 1;
+pub const LIBUSB_ISO_SYNC_TYPE_ADAPTIVE: u8 = 2;
+pub const LIBUSB_ISO_SYNC_TYPE_SYNC: u8 = 3;
+
+// libusb_iso_usage_type
+pub const LIBUSB_ISO_USAGE_TYPE_MASK: u8 = 0x30;
+pub const LIBUSB_ISO_USAGE_TYPE_DATA: u8 = 0;
+pub const LIBUSB_ISO_USAGE_TYPE_FEEDBACK: u8 = 1;
+pub const LIBUSB_ISO_USAGE_TYPE_IMPLICIT: u8 = 2;
+
+// libusb_request_type
+pub const LIBUSB_REQUEST_TYPE_STANDARD: u8 = 0x00 << 5;
+pub const LIBUSB_REQUEST_TYPE_CLASS: u8 = 0x01 << 5;
+pub const LIBUSB_REQUEST_TYPE_VENDOR: u8 = 0x02 << 5;
+pub const LIBUSB_REQUEST_TYPE_RESERVED: u8 = 0x03 << 5;
+
+// libusb_request_recipient
+pub const LIBUSB_RECIPIENT_DEVICE: u8 = 0x00;
+pub const LIBUSB_RECIPIENT_INTERFACE: u8 = 0x01;
+pub const LIBUSB_RECIPIENT_ENDPOINT: u8 = 0x02;
+pub const LIBUSB_RECIPIENT_OTHER: u8 = 0x03;
+
+// libusb_standard_request
+pub const LIBUSB_REQUEST_GET_STATUS: u8 = 0x00;
+pub const LIBUSB_REQUEST_CLEAR_FEATURE: u8 = 0x01;
+pub const LIBUSB_REQUEST_SET_FEATURE: u8 = 0x03;
+pub const LIBUSB_REQUEST_SET_ADDRESS: u8 = 0x05;
+pub const LIBUSB_REQUEST_GET_DESCRIPTOR: u8 = 0x06;
+pub const LIBUSB_REQUEST_SET_DESCRIPTOR: u8 = 0x07;
+pub const LIBUSB_REQUEST_GET_CONFIGURATION: u8 = 0x08;
+pub const LIBUSB_REQUEST_SET_CONFIGURATION: u8 = 0x09;
+pub const LIBUSB_REQUEST_GET_INTERFACE: u8 = 0x0A;
+pub const LIBUSB_REQUEST_SET_INTERFACE: u8 = 0x0B;
+pub const LIBUSB_REQUEST_SYNCH_FRAME: u8 = 0x0C;
+pub const LIBUSB_REQUEST_SET_SEL: u8 = 0x30;
+pub const LIBUSB_SET_ISOCH_DELAY: u8 = 0x31;
+
+// libusb_hotplug
+pub const LIBUSB_HOTPLUG_NO_FLAGS: c_int = 0;
+pub const LIBUSB_HOTPLUG_ENUMERATE: c_int = 1 << 0;
+pub const LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: c_int = 0x01;
+pub const LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: c_int = 0x02;
+pub const LIBUSB_HOTPLUG_MATCH_ANY: c_int = -1;
+
+pub const LIBUSB_OPTION_LOG_LEVEL: u32 = 0x00;
+pub const LIBUSB_OPTION_USE_USBDK: u32 = 0x01;
+pub const LIBUSB_OPTION_WEAK_AUTHORITY: u32 = 0x02;
+pub const LIBUSB_OPTION_NO_DEVICE_DISCOVERY: u32 = 0x02;
+
+// libusb_log_cb_mode
+pub const LIBUSB_LOG_CB_GLOBAL: libusb_log_cb_mode = 1 << 0;
+pub const LIBUSB_LOG_CB_CONTEXT: libusb_log_cb_mode = 1 << 1;
+
+pub const LIBUSB_CONTROL_SETUP_SIZE: usize = std::mem::size_of::<libusb_control_setup>();
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..b0ac87d
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,696 @@
+#![allow(non_camel_case_types)]
+
+pub mod constants;
+
+use self::constants::*;
+use libc::{c_char, c_int, c_short, c_uchar, c_uint, c_void, ssize_t, timeval};
+
+#[repr(C)]
+pub struct libusb_context {
+ __private: c_void,
+}
+
+#[repr(C)]
+pub struct libusb_device {
+ __private: c_void,
+}
+
+#[repr(C)]
+pub struct libusb_device_handle {
+ __private: c_void,
+}
+
+#[repr(C)]
+pub struct libusb_version {
+ pub major: u16,
+ pub minor: u16,
+ pub micro: u16,
+ pub nano: u16,
+ pub rc: *const c_char,
+ pub describe: *const c_char,
+}
+
+#[allow(non_snake_case)]
+#[repr(C)]
+pub struct libusb_device_descriptor {
+ pub bLength: u8,
+ pub bDescriptorType: u8,
+ pub bcdUSB: u16,
+ pub bDeviceClass: u8,
+ pub bDeviceSubClass: u8,
+ pub bDeviceProtocol: u8,
+ pub bMaxPacketSize0: u8,
+ pub idVendor: u16,
+ pub idProduct: u16,
+ pub bcdDevice: u16,
+ pub iManufacturer: u8,
+ pub iProduct: u8,
+ pub iSerialNumber: u8,
+ pub bNumConfigurations: u8,
+}
+
+#[allow(non_snake_case)]
+#[repr(C)]
+pub struct libusb_config_descriptor {
+ pub bLength: u8,
+ pub bDescriptorType: u8,
+ pub wTotalLength: u16,
+ pub bNumInterfaces: u8,
+ pub bConfigurationValue: u8,
+ pub iConfiguration: u8,
+ pub bmAttributes: u8,
+ pub bMaxPower: u8,
+ pub interface: *const libusb_interface,
+ pub extra: *const c_uchar,
+ pub extra_length: c_int,
+}
+
+#[repr(C)]
+pub struct libusb_interface {
+ pub altsetting: *const libusb_interface_descriptor,
+ pub num_altsetting: c_int,
+}
+
+#[allow(non_snake_case)]
+#[repr(C)]
+pub struct libusb_interface_descriptor {
+ pub bLength: u8,
+ pub bDescriptorType: u8,
+ pub bInterfaceNumber: u8,
+ pub bAlternateSetting: u8,
+ pub bNumEndpoints: u8,
+ pub bInterfaceClass: u8,
+ pub bInterfaceSubClass: u8,
+ pub bInterfaceProtocol: u8,
+ pub iInterface: u8,
+ pub endpoint: *const libusb_endpoint_descriptor,
+ pub extra: *const c_uchar,
+ pub extra_length: c_int,
+}
+
+#[allow(non_snake_case)]
+#[repr(C)]
+pub struct libusb_endpoint_descriptor {
+ pub bLength: u8,
+ pub bDescriptorType: u8,
+ pub bEndpointAddress: u8,
+ pub bmAttributes: u8,
+ pub wMaxPacketSize: u16,
+ pub bInterval: u8,
+ pub bRefresh: u8,
+ pub bSynchAddress: u8,
+ pub extra: *const c_uchar,
+ pub extra_length: c_int,
+}
+
+#[repr(C)]
+pub struct libusb_iso_packet_descriptor {
+ pub length: c_uint,
+ pub actual_length: c_uint,
+ pub status: c_int,
+}
+
+#[allow(non_snake_case)]
+#[repr(C)]
+pub struct libusb_ss_endpoint_companion_descriptor {
+ pub bLength: u8,
+ pub bDescriptorType: u8,
+ pub bMaxBurst: u8,
+ pub bmAttributes: u8,
+ pub wBytesPerInterval: u16,
+}
+
+#[allow(non_snake_case)]
+#[repr(C)]
+pub struct libusb_bos_dev_capability_descriptor {
+ pub bLength: u8,
+ pub bDescriptorType: u8,
+ pub bDevCapabilityType: u8,
+ pub dev_capability_data: [u8; 0],
+}
+
+#[allow(non_snake_case)]
+#[repr(C)]
+pub struct libusb_bos_descriptor {
+ pub bLength: u8,
+ pub bDescriptorType: u8,
+ pub wTotalLength: u16,
+ pub bNumDeviceCaps: u8,
+ pub dev_capability: [libusb_bos_dev_capability_descriptor; 0],
+}
+
+#[allow(non_snake_case)]
+#[repr(C)]
+pub struct libusb_usb_2_0_extension_descriptor {
+ pub bLength: u8,
+ pub bDescriptorType: u8,
+ pub bDevCapabilityType: u8,
+ pub bmAttributes: u32,
+}
+
+#[allow(non_snake_case)]
+#[repr(C)]
+pub struct libusb_ss_usb_device_capability_descriptor {
+ pub bLength: u8,
+ pub bDescriptorType: u8,
+ pub bDevCapabilityType: u8,
+ pub bmAttributes: u8,
+ pub wSpeedSupported: u16,
+ pub bFunctionalitySupport: u8,
+ pub bU1DevExitLat: u8,
+ pub bU2DevExitLat: u8,
+}
+
+#[allow(non_snake_case)]
+#[repr(C)]
+pub struct libusb_container_id_descriptor {
+ pub bLength: u8,
+ pub bDescriptorType: u8,
+ pub bDevCapabilityType: u8,
+ pub bReserved: u8,
+ pub ContainerId: [u8; 16],
+}
+
+#[allow(non_snake_case)]
+#[repr(C, packed)]
+pub struct libusb_control_setup {
+ pub bmRequestType: u8,
+ pub bRequest: u8,
+ pub wValue: u16,
+ pub wIndex: u16,
+ pub wLength: u16,
+}
+
+#[repr(C)]
+pub struct libusb_transfer {
+ pub dev_handle: *mut libusb_device_handle,
+ pub flags: u8,
+ pub endpoint: c_uchar,
+ pub transfer_type: c_uchar,
+ pub timeout: c_uint,
+ pub status: c_int,
+ pub length: c_int,
+ pub actual_length: c_int,
+ pub callback: libusb_transfer_cb_fn,
+ pub user_data: *mut c_void,
+ pub buffer: *mut c_uchar,
+ pub num_iso_packets: c_int,
+ pub iso_packet_desc: [libusb_iso_packet_descriptor; 0],
+}
+
+#[repr(C)]
+pub struct libusb_pollfd {
+ pub fd: c_int,
+ pub events: c_short,
+}
+
+pub type libusb_hotplug_callback_handle = c_int;
+pub type libusb_hotplug_flag = c_int;
+pub type libusb_hotplug_event = c_int;
+
+pub type libusb_log_cb_mode = c_int;
+
+pub type libusb_transfer_cb_fn = extern "system" fn(*mut libusb_transfer);
+pub type libusb_pollfd_added_cb = extern "system" fn(c_int, c_short, *mut c_void);
+pub type libusb_pollfd_removed_cb = extern "system" fn(c_int, *mut c_void);
+pub type libusb_hotplug_callback_fn = extern "system" fn(
+ ctx: *mut libusb_context,
+ device: *mut libusb_device,
+ event: libusb_hotplug_event,
+ user_data: *mut c_void,
+) -> c_int;
+
+pub type libusb_log_cb = extern "system" fn(context: *mut libusb_context, c_int, *mut c_void);
+
+extern "system" {
+ pub fn libusb_get_version() -> *const libusb_version;
+ pub fn libusb_has_capability(capability: u32) -> c_int;
+ pub fn libusb_error_name(errcode: c_int) -> *const c_char;
+ pub fn libusb_setlocale(locale: *const c_char) -> c_int;
+ pub fn libusb_strerror(errcode: c_int) -> *const c_char;
+
+ pub fn libusb_init(context: *mut *mut libusb_context) -> c_int;
+ pub fn libusb_exit(context: *mut libusb_context);
+ pub fn libusb_set_debug(context: *mut libusb_context, level: c_int);
+ pub fn libusb_set_log_cb(context: *mut libusb_context, cb: Option<libusb_log_cb>, mode: c_int);
+
+ pub fn libusb_get_device_list(
+ context: *mut libusb_context,
+ list: *mut *const *mut libusb_device,
+ ) -> ssize_t;
+ pub fn libusb_free_device_list(list: *const *mut libusb_device, unref_devices: c_int);
+ pub fn libusb_get_parent(dev: *mut libusb_device) -> *mut libusb_device;
+ pub fn libusb_get_device(dev_handle: *mut libusb_device_handle) -> *mut libusb_device;
+
+ pub fn libusb_ref_device(dev: *mut libusb_device) -> *mut libusb_device;
+ pub fn libusb_unref_device(dev: *mut libusb_device);
+
+ pub fn libusb_get_device_descriptor(
+ dev: *const libusb_device,
+ desc: *mut libusb_device_descriptor,
+ ) -> c_int;
+ pub fn libusb_get_config_descriptor(
+ dev: *const libusb_device,
+ index: u8,
+ config: *mut *const libusb_config_descriptor,
+ ) -> c_int;
+ pub fn libusb_get_active_config_descriptor(
+ dev: *const libusb_device,
+ config: *mut *const libusb_config_descriptor,
+ ) -> c_int;
+ pub fn libusb_get_config_descriptor_by_value(
+ dev: *const libusb_device,
+ bConfigurationValue: u8,
+ config: *mut *const libusb_config_descriptor,
+ ) -> c_int;
+ pub fn libusb_free_config_descriptor(config: *const libusb_config_descriptor);
+
+ pub fn libusb_get_bus_number(dev: *const libusb_device) -> u8;
+ pub fn libusb_get_port_number(dev: *mut libusb_device) -> u8;
+ pub fn libusb_get_port_numbers(
+ dev: *mut libusb_device,
+ port_numbers: *mut u8,
+ port_numbers_len: c_int,
+ ) -> c_int;
+ pub fn libusb_get_device_address(dev: *const libusb_device) -> u8;
+ pub fn libusb_get_device_speed(dev: *const libusb_device) -> c_int;
+ pub fn libusb_get_max_packet_size(dev: *const libusb_device, endpoint: c_uchar) -> c_int;
+ pub fn libusb_get_max_iso_packet_size(dev: *const libusb_device, endpoint: c_uchar) -> c_int;
+
+ pub fn libusb_wrap_sys_device(
+ context: *mut libusb_context,
+ sys_dev: *mut c_int,
+ handle: *mut *mut libusb_device_handle,
+ ) -> c_int;
+ pub fn libusb_open(dev: *const libusb_device, handle: *mut *mut libusb_device_handle) -> c_int;
+ pub fn libusb_close(dev_handle: *mut libusb_device_handle);
+ pub fn libusb_open_device_with_vid_pid(
+ context: *mut libusb_context,
+ vendor_id: u16,
+ product_id: u16,
+ ) -> *mut libusb_device_handle;
+ pub fn libusb_reset_device(dev_handle: *mut libusb_device_handle) -> c_int;
+ pub fn libusb_clear_halt(dev_handle: *mut libusb_device_handle, endpoint: c_uchar) -> c_int;
+ pub fn libusb_alloc_streams(
+ dev_handle: *mut libusb_device_handle,
+ num_streams: u32,
+ endpoints: *mut c_uchar,
+ num_endpoints: c_int,
+ ) -> c_int;
+ pub fn libusb_free_streams(
+ dev_handle: *mut libusb_device_handle,
+ endpoints: *mut c_uchar,
+ num_endpoints: c_int,
+ ) -> c_int;
+ pub fn libusb_get_string_descriptor_ascii(
+ dev_handle: *mut libusb_device_handle,
+ desc_index: u8,
+ data: *mut c_uchar,
+ length: c_int,
+ ) -> c_int;
+
+ pub fn libusb_get_configuration(
+ dev_handle: *mut libusb_device_handle,
+ config: *mut c_int,
+ ) -> c_int;
+ pub fn libusb_set_configuration(dev_handle: *mut libusb_device_handle, config: c_int) -> c_int;
+
+ pub fn libusb_get_ss_endpoint_companion_descriptor(
+ context: *mut libusb_context,
+ endpoint: *const libusb_endpoint_descriptor,
+ ep_comp: *mut *const libusb_ss_endpoint_companion_descriptor,
+ ) -> c_int;
+ pub fn libusb_free_ss_endpoint_companion_descriptor(
+ ep_comp: *mut libusb_ss_endpoint_companion_descriptor,
+ );
+ pub fn libusb_get_bos_descriptor(
+ dev_handle: *mut libusb_device_handle,
+ bos: *mut *const libusb_bos_descriptor,
+ ) -> c_int;
+ pub fn libusb_free_bos_descriptor(bos: *mut libusb_bos_descriptor);
+ pub fn libusb_get_usb_2_0_extension_descriptor(
+ context: *mut libusb_context,
+ dev_cap: *mut libusb_bos_dev_capability_descriptor,
+ usb_2_0_extension: *mut *const libusb_usb_2_0_extension_descriptor,
+ ) -> c_int;
+ pub fn libusb_free_usb_2_0_extension_descriptor(
+ usb_2_0_extension: *mut libusb_usb_2_0_extension_descriptor,
+ );
+ pub fn libusb_get_ss_usb_device_capability_descriptor(
+ context: *mut libusb_context,
+ dev_cap: *mut libusb_bos_dev_capability_descriptor,
+ ss_usb_device_cap: *mut *const libusb_ss_usb_device_capability_descriptor,
+ ) -> c_int;
+ pub fn libusb_free_ss_usb_device_capability_descriptor(
+ ss_usb_device_cap: *mut libusb_ss_usb_device_capability_descriptor,
+ );
+ pub fn libusb_get_container_id_descriptor(
+ context: *mut libusb_context,
+ dev_cap: *mut libusb_bos_dev_capability_descriptor,
+ container_id: *mut *const libusb_container_id_descriptor,
+ ) -> c_int;
+ pub fn libusb_free_container_id_descriptor(container_id: *mut libusb_container_id_descriptor);
+
+ pub fn libusb_set_auto_detach_kernel_driver(
+ dev_handle: *mut libusb_device_handle,
+ enable: c_int,
+ ) -> c_int;
+ pub fn libusb_kernel_driver_active(
+ dev_handle: *mut libusb_device_handle,
+ interface_number: c_int,
+ ) -> c_int;
+ pub fn libusb_detach_kernel_driver(
+ dev_handle: *mut libusb_device_handle,
+ interface_number: c_int,
+ ) -> c_int;
+ pub fn libusb_attach_kernel_driver(
+ dev_handle: *mut libusb_device_handle,
+ interface_number: c_int,
+ ) -> c_int;
+
+ pub fn libusb_claim_interface(
+ dev_handle: *mut libusb_device_handle,
+ interface_number: c_int,
+ ) -> c_int;
+ pub fn libusb_release_interface(
+ dev_handle: *mut libusb_device_handle,
+ interface_number: c_int,
+ ) -> c_int;
+ pub fn libusb_set_interface_alt_setting(
+ dev_handle: *mut libusb_device_handle,
+ interface_number: c_int,
+ alternate_setting: c_int,
+ ) -> c_int;
+
+ pub fn libusb_interrupt_transfer(
+ dev_handle: *mut libusb_device_handle,
+ endpoint: c_uchar,
+ data: *mut c_uchar,
+ length: c_int,
+ transferred: *mut c_int,
+ timeout: c_uint,
+ ) -> c_int;
+ pub fn libusb_bulk_transfer(
+ dev_handle: *mut libusb_device_handle,
+ endpoint: c_uchar,
+ data: *mut c_uchar,
+ length: c_int,
+ transferred: *mut c_int,
+ timeout: c_uint,
+ ) -> c_int;
+ pub fn libusb_control_transfer(
+ dev_handle: *mut libusb_device_handle,
+ request_type: u8,
+ request: u8,
+ value: u16,
+ index: u16,
+ data: *mut c_uchar,
+ length: u16,
+ timeout: c_uint,
+ ) -> c_int;
+
+ pub fn libusb_alloc_transfer(iso_packets: c_int) -> *mut libusb_transfer;
+ pub fn libusb_submit_transfer(transfer: *mut libusb_transfer) -> c_int;
+ pub fn libusb_cancel_transfer(transfer: *mut libusb_transfer) -> c_int;
+ pub fn libusb_free_transfer(transfer: *mut libusb_transfer);
+ pub fn libusb_transfer_set_stream_id(transfer: *mut libusb_transfer, stream_id: u32);
+ pub fn libusb_transfer_get_stream_id(transfer: *mut libusb_transfer) -> u32;
+
+ pub fn libusb_handle_events(context: *mut libusb_context) -> c_int;
+ pub fn libusb_handle_events_timeout(context: *mut libusb_context, tv: *const timeval) -> c_int;
+ pub fn libusb_handle_events_completed(
+ context: *mut libusb_context,
+ completed: *mut c_int,
+ ) -> c_int;
+ pub fn libusb_handle_events_timeout_completed(
+ context: *mut libusb_context,
+ tv: *const timeval,
+ completed: *mut c_int,
+ ) -> c_int;
+ pub fn libusb_handle_events_locked(context: *mut libusb_context, tv: *const timeval) -> c_int;
+ pub fn libusb_interrupt_event_handler(context: *mut libusb_context);
+
+ pub fn libusb_try_lock_events(context: *mut libusb_context) -> c_int;
+ pub fn libusb_lock_events(context: *mut libusb_context);
+ pub fn libusb_unlock_events(context: *mut libusb_context);
+ pub fn libusb_event_handling_ok(context: *mut libusb_context) -> c_int;
+ pub fn libusb_event_handler_active(context: *mut libusb_context) -> c_int;
+ pub fn libusb_lock_event_waiters(context: *mut libusb_context);
+ pub fn libusb_unlock_event_waiters(context: *mut libusb_context);
+ pub fn libusb_wait_for_event(context: *mut libusb_context, tv: *const timeval) -> c_int;
+
+ pub fn libusb_pollfds_handle_timeouts(context: *mut libusb_context) -> c_int;
+ pub fn libusb_get_next_timeout(context: *mut libusb_context, tv: *mut timeval) -> c_int;
+ pub fn libusb_get_pollfds(context: *mut libusb_context) -> *const *mut libusb_pollfd;
+ pub fn libusb_set_pollfd_notifiers(
+ context: *mut libusb_context,
+ added_cb: Option<libusb_pollfd_added_cb>,
+ removed_cb: Option<libusb_pollfd_removed_cb>,
+ user_data: *mut c_void,
+ );
+ pub fn libusb_free_pollfds(pollfds: *const *mut libusb_pollfd);
+ pub fn libusb_hotplug_register_callback(
+ ctx: *mut libusb_context,
+ events: c_int,
+ flags: c_int,
+ vendor_id: c_int,
+ product_id: c_int,
+ dev_class: c_int,
+ cb_fn: libusb_hotplug_callback_fn,
+ user_data: *mut c_void,
+ callback_handle: *mut libusb_hotplug_callback_handle,
+ ) -> c_int;
+ pub fn libusb_hotplug_deregister_callback(
+ ctx: *mut libusb_context,
+ callback_handle: libusb_hotplug_callback_handle,
+ );
+
+ pub fn libusb_hotplug_get_user_data(
+ ctx: *mut libusb_context,
+ callback_handle: libusb_hotplug_callback_handle,
+ ) -> *mut c_void;
+}
+
+// As libusb_set_option is a variatic function, it must use "C"
+// calling conventions
+extern "C" {
+ pub fn libusb_set_option(ctx: *mut libusb_context, option: u32, ...) -> c_int;
+}
+
+// defined as static inline in libusb.h
+#[inline]
+pub unsafe fn libusb_get_string_descriptor(
+ dev_handle: *mut libusb_device_handle,
+ desc_index: u8,
+ langid: u16,
+ data: *mut c_uchar,
+ length: c_int,
+) -> c_int {
+ libusb_control_transfer(
+ dev_handle,
+ LIBUSB_ENDPOINT_IN,
+ LIBUSB_REQUEST_GET_DESCRIPTOR,
+ u16::from(LIBUSB_DT_STRING) << 8 | u16::from(desc_index),
+ langid,
+ data,
+ length as u16,
+ 1000,
+ )
+}
+
+// defined as static inline in libusb.h
+#[inline]
+pub unsafe fn libusb_get_descriptor(
+ dev_handle: *mut libusb_device_handle,
+ desc_type: u8,
+ desc_index: u8,
+ langid: u16,
+ data: *mut c_uchar,
+ length: c_int,
+) -> c_int {
+ libusb_control_transfer(
+ dev_handle,
+ LIBUSB_ENDPOINT_IN,
+ LIBUSB_REQUEST_GET_DESCRIPTOR,
+ u16::from(desc_type) << 8 | u16::from(desc_index),
+ langid,
+ data,
+ length as u16,
+ 1000,
+ )
+}
+
+#[inline]
+pub unsafe fn libusb_control_transfer_get_data(transfer: *mut libusb_transfer) -> *mut c_uchar {
+ (*transfer).buffer.add(constants::LIBUSB_CONTROL_SETUP_SIZE)
+}
+
+#[inline]
+pub unsafe fn libusb_control_transfer_get_setup(
+ transfer: *mut libusb_transfer,
+) -> *mut libusb_control_setup {
+ (*transfer).buffer as *mut _
+}
+
+#[allow(non_snake_case)]
+#[inline]
+pub unsafe fn libusb_fill_control_setup(
+ buffer: *mut c_uchar,
+ bmRequestType: u8,
+ bRequest: u8,
+ wValue: u16,
+ wIndex: u16,
+ wLength: u16,
+) {
+ let setup: *mut libusb_control_setup = buffer as *mut _;
+ (*setup).bmRequestType = bmRequestType;
+ (*setup).bRequest = bRequest;
+ (*setup).wValue = wValue.to_le();
+ (*setup).wIndex = wIndex.to_le();
+ (*setup).wLength = wLength.to_le();
+}
+
+#[inline]
+pub unsafe fn libusb_fill_control_transfer(
+ transfer: *mut libusb_transfer,
+ dev_handle: *mut libusb_device_handle,
+ buffer: *mut u8,
+ callback: libusb_transfer_cb_fn,
+ user_data: *mut c_void,
+ timeout: c_uint,
+) {
+ let setup: *mut libusb_control_setup = buffer as *mut c_void as *mut libusb_control_setup;
+
+ (*transfer).dev_handle = dev_handle;
+ (*transfer).endpoint = 0;
+ (*transfer).transfer_type = LIBUSB_TRANSFER_TYPE_CONTROL;
+ (*transfer).timeout = timeout;
+ (*transfer).buffer = buffer;
+ if !buffer.is_null() {
+ (*transfer).length =
+ (constants::LIBUSB_CONTROL_SETUP_SIZE as u16 + u16::from_le((*setup).wLength)).into();
+ }
+ (*transfer).user_data = user_data;
+ (*transfer).callback = callback;
+}
+
+#[inline]
+pub unsafe fn libusb_fill_bulk_transfer(
+ transfer: *mut libusb_transfer,
+ dev_handle: *mut libusb_device_handle,
+ endpoint: u8,
+ buffer: *mut u8,
+ length: c_int,
+ callback: libusb_transfer_cb_fn,
+ user_data: *mut c_void,
+ timeout: c_uint,
+) {
+ (*transfer).dev_handle = dev_handle;
+ (*transfer).endpoint = endpoint;
+ (*transfer).transfer_type = LIBUSB_TRANSFER_TYPE_BULK;
+ (*transfer).timeout = timeout;
+ (*transfer).buffer = buffer;
+ (*transfer).length = length;
+ (*transfer).user_data = user_data;
+ (*transfer).callback = callback;
+}
+
+#[inline]
+pub unsafe fn libusb_fill_bulk_stream_transfer(
+ transfer: *mut libusb_transfer,
+ dev_handle: *mut libusb_device_handle,
+ endpoint: u8,
+ stream_id: u32,
+ buffer: *mut u8,
+ length: c_int,
+ callback: libusb_transfer_cb_fn,
+ user_data: *mut c_void,
+ timeout: c_uint,
+) {
+ libusb_fill_bulk_transfer(
+ transfer, dev_handle, endpoint, buffer, length, callback, user_data, timeout,
+ );
+ (*transfer).transfer_type = LIBUSB_TRANSFER_TYPE_BULK_STREAM;
+ libusb_transfer_set_stream_id(transfer, stream_id);
+}
+
+#[inline]
+pub unsafe fn libusb_fill_interrupt_transfer(
+ transfer: *mut libusb_transfer,
+ dev_handle: *mut libusb_device_handle,
+ endpoint: u8,
+ buffer: *mut u8,
+ length: c_int,
+ callback: libusb_transfer_cb_fn,
+ user_data: *mut c_void,
+ timeout: c_uint,
+) {
+ (*transfer).dev_handle = dev_handle;
+ (*transfer).endpoint = endpoint;
+ (*transfer).transfer_type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
+ (*transfer).timeout = timeout;
+ (*transfer).buffer = buffer;
+ (*transfer).length = length;
+ (*transfer).user_data = user_data;
+ (*transfer).callback = callback;
+}
+
+#[inline]
+pub unsafe fn libusb_fill_iso_transfer(
+ transfer: *mut libusb_transfer,
+ dev_handle: *mut libusb_device_handle,
+ endpoint: u8,
+ buffer: *mut u8,
+ length: c_int,
+ num_iso_packets: c_int,
+ callback: libusb_transfer_cb_fn,
+ user_data: *mut c_void,
+ timeout: c_uint,
+) {
+ (*transfer).dev_handle = dev_handle;
+ (*transfer).endpoint = endpoint;
+ (*transfer).transfer_type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
+ (*transfer).timeout = timeout;
+ (*transfer).buffer = buffer;
+ (*transfer).length = length;
+ (*transfer).num_iso_packets = num_iso_packets;
+ (*transfer).user_data = user_data;
+ (*transfer).callback = callback;
+}
+
+#[inline]
+pub unsafe fn libusb_set_iso_packet_lengths(transfer: *mut libusb_transfer, length: c_uint) {
+ for i in 0..(*transfer).num_iso_packets {
+ (*(*transfer).iso_packet_desc.as_mut_ptr().add(i as usize)).length = length;
+ }
+}
+
+#[inline]
+pub unsafe fn libusb_get_iso_packet_buffer(
+ transfer: *mut libusb_transfer,
+ packet: c_uint,
+) -> *mut c_uchar {
+ if packet as c_int >= (*transfer).num_iso_packets {
+ return std::ptr::null_mut();
+ }
+ let mut offset = 0;
+ for i in 0..packet {
+ offset += (*(*transfer).iso_packet_desc.as_mut_ptr().add(i as usize)).length;
+ }
+
+ (*transfer).buffer.add(offset as usize)
+}
+
+#[inline]
+pub unsafe fn libusb_get_iso_packet_buffer_simple(
+ transfer: *mut libusb_transfer,
+ packet: c_uint,
+) -> *mut c_uchar {
+ if packet as c_int >= (*transfer).num_iso_packets {
+ return std::ptr::null_mut();
+ }
+
+ (*transfer)
+ .buffer
+ .add(((*(*transfer).iso_packet_desc.as_mut_ptr().add(0)).length * packet) as usize)
+}
diff --git a/tests/test.rs b/tests/test.rs
new file mode 100644
index 0000000..42cd5a0
--- /dev/null
+++ b/tests/test.rs
@@ -0,0 +1,160 @@
+use libusb1_sys as ffi;
+
+#[test]
+fn test_version() {
+ use std::{ffi::CStr, str};
+ let version = unsafe { &*ffi::libusb_get_version() };
+ let rc = str::from_utf8(unsafe { CStr::from_ptr(version.rc) }.to_bytes()).unwrap_or("");
+ let describe =
+ str::from_utf8(unsafe { CStr::from_ptr(version.describe) }.to_bytes()).unwrap_or("");
+
+ assert_eq!(version.major, 1);
+ assert_eq!(version.minor, 0);
+ println!(
+ "libusb v{}.{}.{}.{}{} {}",
+ version.major, version.minor, version.micro, version.nano, rc, describe
+ );
+}
+
+#[test]
+fn test_init_and_exit() {
+ let mut context: *mut ffi::libusb_context = std::ptr::null_mut();
+ for i in 0..=100 {
+ match unsafe { ffi::libusb_init(&mut context) } {
+ 0 => (),
+ err => panic!("Failed to init libusb on iteration {}: {}", i, err),
+ }
+ unsafe {
+ ffi::libusb_exit(context);
+ }
+ #[cfg(target_os = "macos")]
+ std::thread::sleep(std::time::Duration::from_millis(1));
+ context = std::ptr::null_mut();
+ }
+}
+
+#[test]
+fn test_get_device_list() {
+ let mut context = std::mem::MaybeUninit::<*mut ffi::libusb_context>::uninit();
+ match unsafe { ffi::libusb_init(context.as_mut_ptr()) } {
+ 0 => (),
+ err => panic!("Failed to init libusb {}", err),
+ }
+ let mut list = std::mem::MaybeUninit::<*const *mut ffi::libusb_device>::uninit();
+ let list_size =
+ unsafe { ffi::libusb_get_device_list(context.assume_init(), list.as_mut_ptr()) };
+ if list_size < 0 || unsafe { list.assume_init().is_null() } {
+ panic!("Failed to get device list {} {:p}", -list_size, unsafe {
+ list.assume_init()
+ });
+ }
+ unsafe {
+ ffi::libusb_free_device_list(list.assume_init(), 1);
+ }
+ unsafe {
+ ffi::libusb_exit(context.assume_init());
+ }
+}
+
+#[test]
+fn test_fill_control_setup() {
+ let mut buf = [0u8; ffi::constants::LIBUSB_CONTROL_SETUP_SIZE + 1];
+ unsafe {
+ ffi::libusb_fill_control_setup(
+ buf.as_mut_ptr(),
+ ffi::constants::LIBUSB_REQUEST_TYPE_VENDOR | ffi::constants::LIBUSB_ENDPOINT_OUT,
+ 0x04,
+ 0x4e,
+ 0,
+ (buf.len() - ffi::constants::LIBUSB_CONTROL_SETUP_SIZE) as u16,
+ );
+ }
+ buf[ffi::constants::LIBUSB_CONTROL_SETUP_SIZE] = 0x01;
+ let setup: *mut ffi::libusb_control_setup = buf.as_mut_ptr() as *mut _;
+
+ assert_eq!(
+ unsafe { (*setup).bmRequestType },
+ ffi::constants::LIBUSB_REQUEST_TYPE_VENDOR | ffi::constants::LIBUSB_ENDPOINT_OUT
+ );
+ assert_eq!(unsafe { (*setup).bRequest }, 0x04);
+ assert_eq!(unsafe { u16::from_le((*setup).wValue) }, 0x4e);
+ assert_eq!(unsafe { u16::from_le((*setup).wIndex) }, 0);
+ assert_eq!(unsafe { u16::from_le((*setup).wLength) }, 1);
+}
+
+#[test]
+fn test_fill_control_transfer() {
+ extern "system" fn callback(_transfer: *mut ffi::libusb_transfer) {}
+
+ let mut buf = [0u8; ffi::constants::LIBUSB_CONTROL_SETUP_SIZE + 1];
+ unsafe {
+ ffi::libusb_fill_control_setup(
+ buf.as_mut_ptr(),
+ ffi::constants::LIBUSB_REQUEST_TYPE_VENDOR | ffi::constants::LIBUSB_ENDPOINT_OUT,
+ 0x04,
+ 0x4e,
+ 0,
+ (buf.len() - ffi::constants::LIBUSB_CONTROL_SETUP_SIZE) as u16,
+ );
+ }
+ buf[ffi::constants::LIBUSB_CONTROL_SETUP_SIZE] = 0x05;
+
+ let mut transfer = std::mem::MaybeUninit::<ffi::libusb_transfer>::uninit();
+
+ unsafe {
+ ffi::libusb_fill_control_transfer(
+ transfer.as_mut_ptr(),
+ std::ptr::null_mut(),
+ buf.as_mut_ptr(),
+ callback,
+ std::ptr::null_mut(),
+ 1000,
+ );
+ }
+ let transfer = unsafe { &mut transfer.assume_init() };
+ assert_eq!(transfer.endpoint, 0);
+ assert_eq!(
+ transfer.length as usize,
+ ffi::constants::LIBUSB_CONTROL_SETUP_SIZE + 1
+ );
+ assert_eq!(transfer.timeout, 1000);
+ assert_eq!(
+ transfer.transfer_type,
+ ffi::constants::LIBUSB_TRANSFER_TYPE_CONTROL
+ );
+ assert_eq!(transfer.buffer, buf.as_mut_ptr());
+
+ let data = unsafe {
+ std::slice::from_raw_parts(ffi::libusb_control_transfer_get_data(transfer as *mut _), 1)
+ };
+ assert_eq!(data[0], 0x05);
+}
+
+#[test]
+fn test_fill_bulk_transfer() {
+ extern "system" fn callback(_transfer: *mut ffi::libusb_transfer) {}
+
+ let mut transfer = std::mem::MaybeUninit::<ffi::libusb_transfer>::uninit();
+ let mut buf = [5u8; 64];
+ unsafe {
+ ffi::libusb_fill_bulk_transfer(
+ transfer.as_mut_ptr(),
+ std::ptr::null_mut(),
+ 0x80,
+ buf.as_mut_ptr(),
+ buf.len() as libc::c_int,
+ callback,
+ std::ptr::null_mut(),
+ 1000,
+ );
+ }
+ let transfer = unsafe { &transfer.assume_init() };
+ assert_eq!(transfer.endpoint, 0x80);
+ assert_eq!(transfer.timeout, 1000);
+ assert_eq!(
+ transfer.transfer_type,
+ ffi::constants::LIBUSB_TRANSFER_TYPE_BULK
+ );
+ assert_eq!(transfer.buffer, buf.as_mut_ptr());
+ assert_eq!(transfer.length, buf.len() as libc::c_int);
+}