xref: /aosp_15_r20/external/crosvm/devices/src/usb/backend/utils.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2019 The ChromiumOS Authors
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::sync::Arc;
6 
7 use anyhow::Context;
8 use base::error;
9 use sync::Mutex;
10 use usb_util::TransferStatus;
11 
12 use crate::usb::backend::device::BackendDeviceType;
13 use crate::usb::backend::error::Error;
14 use crate::usb::backend::error::Result;
15 use crate::usb::xhci::xhci_transfer::XhciTransfer;
16 use crate::usb::xhci::xhci_transfer::XhciTransferState;
17 use crate::utils::EventHandler;
18 
19 #[macro_export]
20 /// Allows dispatching a function call to all its enum value implementations.
21 /// See `BackendDeviceType` in usb/backend/device.rs for an example usage of it.
22 ///
23 /// # Arguments
24 ///
25 /// * `self` - Replacement for the local `self` reference in the function call.
26 /// * `enum` - Enum name that the macro is matching on.
27 /// * `types` - Space-separated list of value types of the given enum.
28 /// * `func` - Function name that will be called by each match arm.
29 /// * `param` - Optional parameters needed for the given function call.
30 macro_rules! multi_dispatch {
31     ($self:ident, $enum:ident, $($types:ident )+, $func:ident) => {
32         match $self {
33             $(
34                 $enum::$types(device) => device.$func(),
35             )+
36         }
37     };
38     ($self:ident, $enum:ident, $($types:ident )+, $func:ident, $param:expr) => {
39         match $self {
40             $(
41                 $enum::$types(device) => device.$func($param),
42             )+
43         }
44     };
45     ($self:ident, $enum:ident, $($types:ident )+, $func:ident, $param1:expr, $param2: expr) => {
46         match $self {
47             $(
48                 $enum::$types(device) => device.$func($param1, $param2),
49             )+
50         }
51     };
52     ($self:ident, $enum:ident, $($types:ident )+, $func:ident, $param1:expr, $param2: expr, $param3: expr) => {
53         match $self {
54             $(
55                 $enum::$types(device) => device.$func($param1, $param2, $param3),
56             )+
57         }
58     };
59 }
60 
61 pub(crate) use multi_dispatch;
62 
63 pub struct UsbUtilEventHandler {
64     pub device: Arc<Mutex<BackendDeviceType>>,
65 }
66 
67 impl EventHandler for UsbUtilEventHandler {
on_event(&self) -> anyhow::Result<()>68     fn on_event(&self) -> anyhow::Result<()> {
69         match &mut *self.device.lock() {
70             BackendDeviceType::HostDevice(host_device) => host_device
71                 .device
72                 .lock()
73                 .poll_transfers()
74                 .context("UsbUtilEventHandler poll_transfers failed"),
75             BackendDeviceType::FidoDevice(fido_device) => fido_device
76                 .read_hidraw_file()
77                 .context("FidoDeviceEventHandler failed to read hidraw device"),
78         }
79     }
80 }
81 
82 /// Helper function to update xhci_transfer state.
update_transfer_state( xhci_transfer: &Arc<XhciTransfer>, status: TransferStatus, ) -> Result<()>83 pub fn update_transfer_state(
84     xhci_transfer: &Arc<XhciTransfer>,
85     status: TransferStatus,
86 ) -> Result<()> {
87     let mut state = xhci_transfer.state().lock();
88 
89     if status == TransferStatus::Cancelled {
90         *state = XhciTransferState::Cancelled;
91         return Ok(());
92     }
93 
94     match *state {
95         XhciTransferState::Cancelling => {
96             *state = XhciTransferState::Cancelled;
97         }
98         XhciTransferState::Submitted { .. } => {
99             *state = XhciTransferState::Completed;
100         }
101         _ => {
102             error!("xhci trasfer state is invalid");
103             *state = XhciTransferState::Completed;
104             return Err(Error::BadXhciTransferState);
105         }
106     }
107     Ok(())
108 }
109