1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use std::os::raw::{c_int, c_void};
6 use std::sync::Arc;
7
8 use crate::bindings;
9 use crate::libusb_context::LibUsbContextInner;
10 use crate::libusb_device::LibUsbDevice;
11
12 #[derive(PartialEq)]
13 pub enum HotplugEvent {
14 DeviceArrived,
15 DeviceLeft,
16 }
17
18 impl HotplugEvent {
19 /// Create a new HotplugEvent from raw libusb_hotplug_event.
new(event: bindings::libusb_hotplug_event) -> Self20 pub fn new(event: bindings::libusb_hotplug_event) -> Self {
21 match event {
22 bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED => HotplugEvent::DeviceArrived,
23 bindings::LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT => HotplugEvent::DeviceLeft,
24 _ => {
25 // TODO(jkwang) handle this with option.
26 // libusb_hotplug_event is a C enum.
27 panic!("Invaild libusb_hotplug_event");
28 }
29 }
30 }
31 }
32
33 pub trait UsbHotplugHandler: Send + Sync + 'static {
hotplug_event(&self, device: LibUsbDevice, event: HotplugEvent)34 fn hotplug_event(&self, device: LibUsbDevice, event: HotplugEvent);
35 }
36
37 /// UsbHotplugHandlerHolder owns UsbHotplugHandler and LibUsbContext. It will be passed as
38 /// user_data to libusb_hotplug_register_callback.
39 pub struct UsbHotplugHandlerHolder {
40 context: Arc<LibUsbContextInner>,
41 handler: Box<dyn UsbHotplugHandler>,
42 }
43
44 impl UsbHotplugHandlerHolder {
45 /// Create UsbHotplugHandlerHodler from context and handler.
new<H: UsbHotplugHandler>( context: Arc<LibUsbContextInner>, handler: H, ) -> Box<UsbHotplugHandlerHolder>46 pub fn new<H: UsbHotplugHandler>(
47 context: Arc<LibUsbContextInner>,
48 handler: H,
49 ) -> Box<UsbHotplugHandlerHolder> {
50 let holder = UsbHotplugHandlerHolder {
51 context,
52 handler: Box::new(handler),
53 };
54 Box::new(holder)
55 }
56 }
57
58 /// This function is safe when:
59 /// libusb_device is allocated by libusb
60 /// user_data points to valid UsbHotPlugHandlerHolder released from Box.
61 ///
62 /// Do not invoke this function. It should only be used as a callback for
63 /// libusb_hotplug_register_callback.
hotplug_cb( _: *mut bindings::libusb_context, device: *mut bindings::libusb_device, event: bindings::libusb_hotplug_event, user_data: *mut c_void, ) -> c_int64 pub unsafe extern "C" fn hotplug_cb(
65 _: *mut bindings::libusb_context,
66 device: *mut bindings::libusb_device,
67 event: bindings::libusb_hotplug_event,
68 user_data: *mut c_void,
69 ) -> c_int {
70 // Safe because user_data was casted from holder.
71 let holder = &*(user_data as *mut UsbHotplugHandlerHolder);
72 let device = LibUsbDevice::new(holder.context.clone(), device);
73 let event = HotplugEvent::new(event);
74 holder.handler.hotplug_event(device, event);
75 // The handler should always succeed.
76 bindings::LIBUSB_SUCCESS
77 }
78