• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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