usbvfiod 0.2.0

A vfio-user server for USB pass-through.
Documentation
use tokio_util::sync::CancellationToken;

use crate::device::xhci::real_endpoint_handle::{
    RealControlEndpointHandle, RealInEndpointHandle, RealOutEndpointHandle,
};

use std::fmt::{self, Debug};

#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Speed {
    Full = 1,
    Low = 2,
    High = 3,
    Super = 4,
    SuperPlus = 5,
}

impl Speed {
    pub const fn is_usb2_speed(self) -> bool {
        self as u8 <= 3
    }
}

impl fmt::Display for Speed {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let name = match self {
            Self::Low => "Low Speed (1.5 Mbps)",
            Self::Full => "Full Speed (12 Mbps)",
            Self::High => "High Speed (480 Mbps)",
            Self::Super => "SuperSpeed (5 Gbps)",
            Self::SuperPlus => "SuperSpeed+ (10/20 Gbps)",
        };
        write!(f, "{name}")
    }
}

pub trait RealDevice: Debug + Send + Sync + 'static {
    type RCEH: RealControlEndpointHandle;
    type RBIEH: RealInEndpointHandle;
    type RBOEH: RealOutEndpointHandle;
    type RIIEH: RealInEndpointHandle;
    type RIOEH: RealOutEndpointHandle;

    fn speed(&self) -> Option<Speed>;
    fn control_endpoint_handle(&self) -> Self::RCEH;
    fn bulk_in_endpoint_handle(&self, endpoint_id: u8) -> Self::RBIEH;
    fn bulk_out_endpoint_handle(&self, endpoint_id: u8) -> Self::RBOEH;
    fn interrupt_in_endpoint_handle(&self, endpoint_id: u8) -> Self::RIIEH;
    fn interrupt_out_endpoint_handle(&self, endpoint_id: u8) -> Self::RIOEH;
}

pub trait Identifier: Debug + Copy + Eq + Send + Sync + 'static {}

impl Identifier for (u8, u8) {}

// A RealDevice trait coupled with an identifier and cancellation token for detach notification.
//
// A real device alone might not be able to identify itself. For example, a
// nusb device can only query information from the device; if the device has
// no unique serial number, then fields such as vendor id and product id are
// the best bet for identification. However, with two identical devices, the
// approach fails to uniquely identify the devices. Complete real device allows
// distinction of devices by storing an externally-decided, unique identifier.
// Host bus-/device-number is an option,// but so are randomly chosen (but unique
// numbers or strings.
//
// A CompleteRealDevice must also provide a CancellationToken that can be used
// by the potentially multiple references to the real device (endpoint handles
// must have some kind of reference to talk to the endpoint of the real device)
// to synchronously drop to release the real device upon detach.
pub trait CompleteRealDevice: Debug + Send + Sync + 'static {
    type RD: RealDevice;
    type ID: Identifier;

    fn identifier(&self) -> Self::ID;
    fn realdevice_ref(&self) -> &Self::RD;
    fn detach_token(&self) -> CancellationToken;
}

#[derive(Debug)]
pub struct CompleteRealDeviceImpl<RD: RealDevice, ID: Identifier> {
    pub identifier: ID,
    pub real_device: RD,
    pub cancel: CancellationToken,
}

impl<RD: RealDevice, ID: Identifier> CompleteRealDeviceImpl<RD, ID> {
    pub fn new(identifier: ID, real_device: RD) -> Self {
        Self {
            identifier,
            real_device,
            cancel: CancellationToken::new(),
        }
    }
}

impl<RD: RealDevice, ID: Identifier> CompleteRealDevice for CompleteRealDeviceImpl<RD, ID> {
    type RD = RD;
    type ID = ID;

    fn identifier(&self) -> Self::ID {
        self.identifier
    }

    fn realdevice_ref(&self) -> &Self::RD {
        &self.real_device
    }

    fn detach_token(&self) -> CancellationToken {
        self.cancel.clone()
    }
}