devices/usb/backend/
utils.rs

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
5use std::sync::Arc;
6
7use anyhow::Context;
8use base::error;
9use sync::Mutex;
10use usb_util::TransferStatus;
11
12use crate::usb::backend::device::BackendDeviceType;
13use crate::usb::backend::error::Error;
14use crate::usb::backend::error::Result;
15use crate::usb::xhci::xhci_transfer::XhciTransfer;
16use crate::usb::xhci::xhci_transfer::XhciTransferState;
17use 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.
30macro_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
61pub(crate) use multi_dispatch;
62
63pub struct UsbUtilEventHandler {
64    pub device: Arc<Mutex<BackendDeviceType>>,
65}
66
67impl EventHandler for UsbUtilEventHandler {
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.
83pub 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}