Skip to content

Commit

Permalink
Merge branch 'a1ien:master' into free_pollfds
Browse files Browse the repository at this point in the history
  • Loading branch information
kurkpitaine committed Mar 21, 2024
2 parents 404b3a2 + 29694b9 commit e63c6c6
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 27 deletions.
2 changes: 1 addition & 1 deletion libusb1-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ vendored = []
[dependencies]
libc = "0.2"

[target.'cfg(target_env = "msvc")'.build-dependencies]
[target.'cfg(target_os = "windows")'.build-dependencies]
vcpkg = "0.2"

[build-dependencies]
Expand Down
35 changes: 17 additions & 18 deletions libusb1-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,6 @@ pub fn link_framework(name: &str) {
println!("cargo:rustc-link-lib=framework={}", name);
}

#[cfg(target_env = "msvc")]
fn find_libusb_pkg(_statik: bool) -> bool {
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
}
}
}
}

fn get_macos_major_version() -> Option<usize> {
if !cfg!(target_os = "macos") {
return None;
Expand All @@ -49,8 +34,21 @@ fn get_macos_major_version() -> Option<usize> {
Some(major)
}

#[cfg(not(target_env = "msvc"))]
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)
Expand Down Expand Up @@ -175,8 +173,9 @@ fn make_source() {
}

if std::env::var("CARGO_CFG_TARGET_OS") == Ok("windows".into()) {
#[cfg(target_env = "msvc")]
base_config.flag("/source-charset:utf-8");
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"));
Expand Down
82 changes: 80 additions & 2 deletions src/context.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use libc::{c_int, timeval};
use libc::{c_char, c_int, c_void, timeval};

use std::{cmp::Ordering, mem, ptr, sync::Arc, sync::Once, time::Duration};
use std::{
cmp::Ordering, ffi::CStr, mem, ptr, sync::Arc, sync::Mutex, sync::Once, sync::OnceLock,
time::Duration,
};

#[cfg(unix)]
use std::os::unix::io::RawFd;
Expand Down Expand Up @@ -45,6 +48,43 @@ impl Drop for ContextInner {
unsafe impl Sync for Context {}
unsafe impl Send for Context {}

type LogCallback = Box<dyn Fn(LogLevel, String)>;

struct LogCallbackMap {
map: std::collections::HashMap<*mut libusb_context, LogCallback>,
}

unsafe impl Sync for LogCallbackMap {}
unsafe impl Send for LogCallbackMap {}

impl LogCallbackMap {
pub fn new() -> Self {
Self {
map: std::collections::HashMap::new(),
}
}
}

static LOG_CALLBACK_MAP: OnceLock<Mutex<LogCallbackMap>> = OnceLock::new();

extern "system" fn static_log_callback(
context: *mut libusb_context,
level: c_int,
text: *mut c_void,
) {
if let Some(log_callback_map) = LOG_CALLBACK_MAP.get() {
if let Ok(locked_table) = log_callback_map.lock() {
if let Some(logger) = locked_table.map.get(&context) {
let c_str: &CStr = unsafe { CStr::from_ptr(text as *const c_char) };
let str_slice: &str = c_str.to_str().unwrap_or("");
let log_message = str_slice.to_owned();

logger(LogLevel::from_c_int(level), log_message);
}
}
}
}

pub trait UsbContext: Clone + Sized + Send + Sync {
/// Get the raw libusb_context pointer, for advanced use in unsafe code.
fn as_raw(&self) -> *mut libusb_context;
Expand Down Expand Up @@ -104,6 +144,17 @@ pub trait UsbContext: Clone + Sized + Send + Sync {
}
}

fn set_log_callback(&mut self, log_callback: LogCallback, mode: LogCallbackMode) {
let log_callback_map = LOG_CALLBACK_MAP.get_or_init(|| Mutex::new(LogCallbackMap::new()));
if let Ok(mut locked_table) = log_callback_map.lock() {
locked_table.map.insert(self.as_raw(), log_callback);
}

unsafe {
libusb_set_log_cb(self.as_raw(), Some(static_log_callback), mode.as_c_int());
}
}

/// Register a callback to be called on hotplug events. The callback's
/// [Hotplug::device_arrived] method is called when a new device is added to
/// the bus, and [Hotplug::device_left] is called when it is removed.
Expand Down Expand Up @@ -292,4 +343,31 @@ impl LogLevel {
LogLevel::Debug => LIBUSB_LOG_LEVEL_DEBUG,
}
}

fn from_c_int(value: c_int) -> LogLevel {
match value {
LIBUSB_LOG_LEVEL_ERROR => LogLevel::Error,
LIBUSB_LOG_LEVEL_WARNING => LogLevel::Warning,
LIBUSB_LOG_LEVEL_INFO => LogLevel::Info,
LIBUSB_LOG_LEVEL_DEBUG => LogLevel::Debug,
_ => LogLevel::None,
}
}
}

pub enum LogCallbackMode {
/// Callback function handling all log messages.
Global,

/// Callback function handling context related log messages.
Context,
}

impl LogCallbackMode {
fn as_c_int(&self) -> c_int {
match *self {
LogCallbackMode::Global => LIBUSB_LOG_CB_GLOBAL,
LogCallbackMode::Context => LIBUSB_LOG_CB_CONTEXT,
}
}
}
8 changes: 3 additions & 5 deletions src/interface_descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,9 @@ impl<'a> InterfaceDescriptor<'a> {

/// Returns an iterator over the interface's endpoint descriptors.
pub fn endpoint_descriptors(&self) -> EndpointDescriptors<'a> {
let endpoints = unsafe {
slice::from_raw_parts(
self.descriptor.endpoint,
self.descriptor.bNumEndpoints as usize,
)
let endpoints = match self.descriptor.bNumEndpoints {
0 => &[],
n => unsafe { slice::from_raw_parts(self.descriptor.endpoint, n as usize) },
};

EndpointDescriptors {
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub use libusb1_sys::constants;
pub use crate::options::disable_device_discovery;
pub use crate::{
config_descriptor::{ConfigDescriptor, Interfaces},
context::{Context, GlobalContext, LogLevel, UsbContext},
context::{Context, GlobalContext, LogCallbackMode, LogLevel, UsbContext},
device::Device,
device_descriptor::DeviceDescriptor,
device_handle::DeviceHandle,
Expand Down

0 comments on commit e63c6c6

Please sign in to comment.