mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-06 02:25:23 +00:00
usb_utils: Add hotplug interface
Hotplug callback would be invoked when device attach or detach TEST=run crosvm locally BUG=chromium:831850 CQ-DEPEND=CL:1506826 Change-Id: Ifc1acc00a12c32dd00abbb5467874632e94f60b4 Reviewed-on: https://chromium-review.googlesource.com/1506827 Commit-Ready: Zach Reizner <zachr@chromium.org> Tested-by: Jingkui Wang <jkwang@google.com> Reviewed-by: Zach Reizner <zachr@chromium.org>
This commit is contained in:
parent
b07540c7f9
commit
699170b6b7
3 changed files with 104 additions and 0 deletions
77
usb_util/src/hotplug.rs
Normal file
77
usb_util/src/hotplug.rs
Normal file
|
@ -0,0 +1,77 @@
|
|||
// Copyright 2019 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::sync::Arc;
|
||||
|
||||
use bindings;
|
||||
use libusb_context::LibUsbContextInner;
|
||||
use libusb_device::LibUsbDevice;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum HotplugEvent {
|
||||
DeviceArrived,
|
||||
DeviceLeft,
|
||||
}
|
||||
|
||||
impl HotplugEvent {
|
||||
/// Create a new HotplugEvent from raw libusb_hotplug_event.
|
||||
pub fn new(event: bindings::libusb_hotplug_event) -> Self {
|
||||
match event {
|
||||
bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED => HotplugEvent::DeviceArrived,
|
||||
bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT => HotplugEvent::DeviceLeft,
|
||||
_ => {
|
||||
// TODO(jkwang) handle this with option.
|
||||
// libusb_hotplug_event is a C enum.
|
||||
panic!("Invaild libusb_hotplug_event");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait UsbHotplugHandler: Send + Sync + 'static {
|
||||
fn hotplug_event(&self, device: LibUsbDevice, event: HotplugEvent);
|
||||
}
|
||||
|
||||
/// UsbHotplugHandlerHolder owns UsbHotplugHandler and LibUsbContext. It will be passed as
|
||||
/// user_data to libusb_hotplug_register_callback.
|
||||
pub struct UsbHotplugHandlerHolder {
|
||||
context: Arc<LibUsbContextInner>,
|
||||
handler: Box<UsbHotplugHandler>,
|
||||
}
|
||||
|
||||
impl UsbHotplugHandlerHolder {
|
||||
/// Create UsbHotplugHandlerHodler from context and handler.
|
||||
pub fn new<H: UsbHotplugHandler>(
|
||||
context: Arc<LibUsbContextInner>,
|
||||
handler: H,
|
||||
) -> Box<UsbHotplugHandlerHolder> {
|
||||
let holder = UsbHotplugHandlerHolder {
|
||||
context,
|
||||
handler: Box::new(handler),
|
||||
};
|
||||
Box::new(holder)
|
||||
}
|
||||
}
|
||||
|
||||
/// This function is safe when:
|
||||
/// libusb_device is allocated by libusb
|
||||
/// user_data points to valid UsbHotPlugHandlerHolder released from Box.
|
||||
///
|
||||
/// Do not invoke this function. It should only be used as a callback for
|
||||
/// libusb_hotplug_register_callback.
|
||||
pub unsafe extern "C" fn hotplug_cb(
|
||||
_: *mut bindings::libusb_context,
|
||||
device: *mut bindings::libusb_device,
|
||||
event: bindings::libusb_hotplug_event,
|
||||
user_data: *mut c_void,
|
||||
) -> c_int {
|
||||
// Safe because user_data was casted from holder.
|
||||
let holder = &*(user_data as *mut UsbHotplugHandlerHolder);
|
||||
let device = LibUsbDevice::new(holder.context.clone(), device);
|
||||
let event = HotplugEvent::new(event);
|
||||
holder.handler.hotplug_event(device, event);
|
||||
// The handler should always succeed.
|
||||
bindings::LIBUSB_SUCCESS
|
||||
}
|
|
@ -19,6 +19,7 @@ pub mod error;
|
|||
pub mod config_descriptor;
|
||||
pub mod device_handle;
|
||||
pub mod endpoint_descriptor;
|
||||
pub mod hotplug;
|
||||
pub mod interface_descriptor;
|
||||
pub mod libusb_context;
|
||||
pub mod libusb_device;
|
||||
|
|
|
@ -8,6 +8,7 @@ use std::os::unix::io::RawFd;
|
|||
|
||||
use bindings;
|
||||
use error::{Error, Result};
|
||||
use hotplug::{hotplug_cb, UsbHotplugHandler, UsbHotplugHandlerHolder};
|
||||
use libusb_device::LibUsbDevice;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -160,6 +161,31 @@ impl LibUsbContext {
|
|||
pub fn remove_pollfd_notifiers(&self) {
|
||||
self.inner.remove_pollfd_notifiers();
|
||||
}
|
||||
|
||||
/// Set a callback that could handle hotplug events. Currently, this function listen to hotplug
|
||||
/// event of all devices.
|
||||
pub fn set_hotplug_cb<H: UsbHotplugHandler + Sized>(&self, handler: H) -> Result<()> {
|
||||
let event = bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED
|
||||
| bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT;
|
||||
let holder = UsbHotplugHandlerHolder::new(self.inner.clone(), handler);
|
||||
let raw_holder = Box::into_raw(holder);
|
||||
// Safe becuase hotpulg cb is a vaild c function and raw_holder points to memory for that
|
||||
// function argument.
|
||||
try_libusb!(unsafe {
|
||||
bindings::libusb_hotplug_register_callback(
|
||||
self.inner.context,
|
||||
event,
|
||||
bindings::LIBUSB_HOTPLUG_NO_FLAGS,
|
||||
bindings::LIBUSB_HOTPLUG_MATCH_ANY,
|
||||
bindings::LIBUSB_HOTPLUG_MATCH_ANY,
|
||||
bindings::LIBUSB_HOTPLUG_MATCH_ANY,
|
||||
Some(hotplug_cb),
|
||||
raw_holder as *mut c_void,
|
||||
std::ptr::null_mut(),
|
||||
)
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator for device list.
|
||||
|
|
Loading…
Reference in a new issue