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