tegra_rcm/hotplug/
unix.rs

1use std::sync::mpsc::Sender;
2
3use log::{error, info};
4use rusb::{has_hotplug, Context, Device, Hotplug, HotplugBuilder, UsbContext};
5
6use super::{HotplugError, HotplugHandler};
7use crate::device::{SwitchDevice, RCM_PID, RCM_VID};
8use crate::switch::Switch;
9use crate::SwitchError;
10
11impl Hotplug<Context> for HotplugHandler {
12    /// Gets called whenever a new usb device arrives
13    fn device_arrived(&mut self, device: Device<Context>) {
14        let device = SwitchDevice::new(device);
15        let switch = Switch::new(device);
16
17        if let Err(e) = self.sender.send(Ok(switch)) {
18            error!("device arrive event {e}");
19        }
20
21        info!("rcm device arrived");
22
23        if let Some(callback) = &self.callback {
24            callback();
25        }
26    }
27
28    /// Gets called whenever a usb device leaves
29    fn device_left(&mut self, _device: Device<Context>) {
30        if let Err(e) = self.sender.send(Err(crate::SwitchError::SwitchNotFound)) {
31            error!("device left event {e}");
32        }
33
34        info!("rcm device left");
35
36        if let Some(callback) = &self.callback {
37            callback();
38        }
39    }
40}
41
42/// create a hotplug setup, this blocks
43pub fn create_hotplug(
44    tx: Sender<Result<Switch, SwitchError>>,
45    callback: Option<impl Fn() + Send + Sync + 'static>,
46) -> Result<(), HotplugError> {
47    cfg_if::cfg_if! {
48        if #[cfg(all(feature = "notify", target_os = "linux"))] {
49            super::notify::watcher_hotplug(tx, callback)
50                .map_err(|_| HotplugError::Watcher)
51        } else {
52            libusb_hotplug(tx, callback)
53        }
54    }
55}
56
57pub fn libusb_hotplug(
58    tx: Sender<Result<Switch, SwitchError>>,
59    callback: Option<impl Fn() + Send + Sync + 'static>,
60) -> Result<(), HotplugError> {
61    if !has_hotplug() {
62        return Err(HotplugError::NotSupported);
63    }
64
65    let mut callback = callback;
66    let context = Context::new().unwrap();
67
68    let hotplug_handler = match callback.take() {
69        Some(callback) => HotplugHandler {
70            sender: tx,
71            callback: Some(Box::new(callback)),
72        },
73        None => HotplugHandler {
74            sender: tx,
75            callback: None,
76        },
77    };
78
79    let _hotplug = HotplugBuilder::new()
80        .vendor_id(RCM_VID)
81        .product_id(RCM_PID)
82        .enumerate(true)
83        .register(context.clone(), Box::new(hotplug_handler))
84        .expect("We where able to successfully wrap the context");
85
86    loop {
87        // blocks thread
88        context
89            .handle_events(None)
90            .expect("We are able to handle USB hotplug events");
91    }
92}