#![no_std]
#![cfg_attr(doc, feature(doc_cfg))]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "block")]
mod blk;
#[cfg(feature = "gpu")]
mod gpu;
#[cfg(feature = "net")]
mod net;
use axdriver_base::{DevError, DeviceType};
use virtio_drivers::transport::DeviceType as VirtIoDevType;
pub use virtio_drivers::{
BufferDirection, Hal as VirtIoHal, PhysAddr,
transport::{
Transport,
mmio::MmioTransport,
pci::{PciTransport, bus as pci},
},
};
#[cfg(feature = "block")]
pub use self::blk::VirtIoBlkDev;
#[cfg(feature = "gpu")]
pub use self::gpu::VirtIoGpuDev;
#[cfg(feature = "net")]
pub use self::net::VirtIoNetDev;
use self::pci::{ConfigurationAccess, DeviceFunction, DeviceFunctionInfo, PciRoot};
pub fn probe_mmio_device(
reg_base: *mut u8,
reg_size: usize,
) -> Option<(DeviceType, MmioTransport<'static>)> {
use core::ptr::NonNull;
use virtio_drivers::transport::mmio::VirtIOHeader;
let header = NonNull::new(reg_base as *mut VirtIOHeader)?;
let transport = unsafe { MmioTransport::new(header, reg_size) }.ok()?;
let dev_type = as_dev_type(transport.device_type())?;
Some((dev_type, transport))
}
pub fn probe_pci_device<H: VirtIoHal, C: ConfigurationAccess>(
root: &mut PciRoot<C>,
bdf: DeviceFunction,
dev_info: &DeviceFunctionInfo,
) -> Option<(DeviceType, PciTransport)> {
use virtio_drivers::transport::pci::virtio_device_type;
let dev_type = virtio_device_type(dev_info).and_then(as_dev_type)?;
let transport = PciTransport::new::<H, C>(root, bdf).ok()?;
Some((dev_type, transport))
}
const fn as_dev_type(t: VirtIoDevType) -> Option<DeviceType> {
use VirtIoDevType::*;
match t {
Block => Some(DeviceType::Block),
Network => Some(DeviceType::Net),
GPU => Some(DeviceType::Display),
_ => None,
}
}
#[allow(dead_code)]
const fn as_dev_err(e: virtio_drivers::Error) -> DevError {
use virtio_drivers::Error::*;
match e {
QueueFull => DevError::BadState,
NotReady => DevError::Again,
WrongToken => DevError::BadState,
AlreadyUsed => DevError::AlreadyExists,
InvalidParam => DevError::InvalidParam,
DmaError => DevError::NoMemory,
IoError => DevError::Io,
Unsupported => DevError::Unsupported,
ConfigSpaceTooSmall => DevError::BadState,
ConfigSpaceMissing => DevError::BadState,
SocketDeviceError(e) => socket_error_to_dev_error(e),
}
}
#[allow(dead_code)]
const fn socket_error_to_dev_error(e: virtio_drivers::device::socket::SocketError) -> DevError {
use virtio_drivers::device::socket::SocketError::*;
match e {
ConnectionExists => DevError::AlreadyExists,
NotConnected => DevError::BadState,
InvalidOperation | InvalidNumber | UnknownOperation(_) => DevError::InvalidParam,
OutputBufferTooShort(_) | BufferTooShort | BufferTooLong(..) => DevError::InvalidParam,
UnexpectedDataInPacket | PeerSocketShutdown => DevError::Io,
InsufficientBufferSpaceInPeer => DevError::Again,
RecycledWrongBuffer => DevError::BadState,
}
}