use std::sync::Arc;
use anyhow::Context;
use base::error;
use sync::Mutex;
use usb_util::TransferStatus;
use crate::usb::backend::device::BackendDeviceType;
use crate::usb::backend::error::Error;
use crate::usb::backend::error::Result;
use crate::usb::xhci::xhci_transfer::XhciTransfer;
use crate::usb::xhci::xhci_transfer::XhciTransferState;
use crate::utils::EventHandler;
#[macro_export]
macro_rules! multi_dispatch {
($self:ident, $enum:ident, $($types:ident )+, $func:ident) => {
match $self {
$(
$enum::$types(device) => device.$func(),
)+
}
};
($self:ident, $enum:ident, $($types:ident )+, $func:ident, $param:expr) => {
match $self {
$(
$enum::$types(device) => device.$func($param),
)+
}
};
($self:ident, $enum:ident, $($types:ident )+, $func:ident, $param1:expr, $param2: expr) => {
match $self {
$(
$enum::$types(device) => device.$func($param1, $param2),
)+
}
};
($self:ident, $enum:ident, $($types:ident )+, $func:ident, $param1:expr, $param2: expr, $param3: expr) => {
match $self {
$(
$enum::$types(device) => device.$func($param1, $param2, $param3),
)+
}
};
}
pub(crate) use multi_dispatch;
pub struct UsbUtilEventHandler {
pub device: Arc<Mutex<BackendDeviceType>>,
}
impl EventHandler for UsbUtilEventHandler {
fn on_event(&self) -> anyhow::Result<()> {
match &mut *self.device.lock() {
BackendDeviceType::HostDevice(host_device) => host_device
.device
.lock()
.poll_transfers()
.context("UsbUtilEventHandler poll_transfers failed"),
BackendDeviceType::FidoDevice(fido_device) => fido_device
.read_hidraw_file()
.context("FidoDeviceEventHandler failed to read hidraw device"),
}
}
}
pub fn update_transfer_state(
xhci_transfer: &Arc<XhciTransfer>,
status: TransferStatus,
) -> Result<()> {
let mut state = xhci_transfer.state().lock();
if status == TransferStatus::Cancelled {
*state = XhciTransferState::Cancelled;
return Ok(());
}
match *state {
XhciTransferState::Cancelling => {
*state = XhciTransferState::Cancelled;
}
XhciTransferState::Submitted { .. } => {
*state = XhciTransferState::Completed;
}
_ => {
error!("xhci trasfer state is invalid");
*state = XhciTransferState::Completed;
return Err(Error::BadXhciTransferState);
}
}
Ok(())
}