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