#![no_std]
#[macro_use]
extern crate alloc;
#[macro_use]
extern crate log;
use core::ptr::NonNull;
pub use fdt_edit::{Fdt, Phandle};
use register::{DriverRegister, ProbeLevel};
use spin::{Mutex, Once};
mod descriptor;
pub mod driver;
pub mod error;
mod id;
mod lock;
mod manager;
mod osal;
pub mod probe;
pub mod register;
pub use descriptor::*;
pub use driver::PlatformDevice;
pub use lock::*;
pub use manager::*;
pub use osal::*;
pub use probe::ProbeError;
pub use rdif_base::{DriverGeneric, KError, irq::IrqId};
pub use rdrive_macros::*;
use crate::{error::DriverError, probe::OnProbeError};
static CONTAINER: Once<Mutex<Manager>> = Once::new();
#[derive(Debug, Clone)]
pub enum Platform {
Static,
Fdt { addr: NonNull<u8> },
Acpi(probe::acpi::AcpiRoot),
}
unsafe impl Send for Platform {}
#[derive(Debug, Clone, Copy)]
pub enum PlatformSource {
Static,
Fdt(NonNull<u8>),
Acpi(probe::acpi::AcpiRoot),
}
unsafe impl Send for PlatformSource {}
pub(crate) fn container() -> &'static Mutex<Manager> {
CONTAINER.get().expect("rdrive not init")
}
pub fn is_initialized() -> bool {
CONTAINER.get().is_some()
}
pub fn init(platform: Platform) -> Result<(), DriverError> {
match platform {
Platform::Static => init_sources(&[PlatformSource::Static])?,
Platform::Fdt { addr } => init_sources(&[PlatformSource::Fdt(addr)])?,
Platform::Acpi(root) => init_sources(&[PlatformSource::Acpi(root)])?,
}
Ok(())
}
pub fn init_sources(sources: &[PlatformSource]) -> Result<(), DriverError> {
for source in sources {
match source {
PlatformSource::Static => {}
PlatformSource::Fdt(addr) => probe::fdt::check_addr(*addr)?,
PlatformSource::Acpi(root) => probe::acpi::check_root(*root)?,
}
}
for source in sources {
match source {
PlatformSource::Static => probe::static_::init()?,
PlatformSource::Fdt(addr) => probe::fdt::init(*addr)?,
PlatformSource::Acpi(root) => probe::acpi::init(*root)?,
}
}
let m = Manager::new()?;
CONTAINER.call_once(|| Mutex::new(m));
Ok(())
}
pub(crate) fn edit<F, T>(f: F) -> T
where
F: FnOnce(&mut Manager) -> T,
{
let mut g = container().lock();
f(&mut g)
}
pub(crate) fn read<F, T>(f: F) -> T
where
F: FnOnce(&Manager) -> T,
{
let g = container().lock();
f(&g)
}
pub fn register_add(register: DriverRegister) {
edit(|manager| manager.registers.add(register));
}
pub fn register_append(registers: &[DriverRegister]) {
edit(|manager| manager.registers.append(registers))
}
pub fn probe_pre_kernel() -> Result<(), ProbeError> {
let unregistered = edit(|manager| manager.unregistered())?;
let ls = unregistered
.iter()
.filter(|one| matches!(one.level, ProbeLevel::PreKernel));
probe_system(ls, true)?;
Ok(())
}
fn probe_system<'a>(
registers: impl Iterator<Item = &'a DriverRegister>,
stop_if_fail: bool,
) -> Result<(), ProbeError> {
for one in registers {
probe_backend(one, probe::static_::try_probe_register(one), stop_if_fail)?;
probe_backend(one, probe::fdt::try_probe_register(one), stop_if_fail)?;
probe_backend(one, probe::acpi::try_probe_register(one), stop_if_fail)?;
}
Ok(())
}
fn probe_backend(
register: &DriverRegister,
results: Option<Result<Vec<Result<(), OnProbeError>>, ProbeError>>,
stop_if_fail: bool,
) -> Result<(), ProbeError> {
let Some(results) = results else {
return Ok(());
};
for r in results? {
match r {
Ok(_) => {}
Err(OnProbeError::NotMatch) => {}
Err(e) => {
if stop_if_fail {
return Err(e.into());
} else {
warn!("Probe failed for [{}]: {}", register.name, e);
}
}
}
}
Ok(())
}
pub fn probe_all(stop_if_fail: bool) -> Result<(), ProbeError> {
let unregistered = edit(|manager| manager.unregistered())?;
probe_system(unregistered.iter(), stop_if_fail)?;
debug!("probe pci devices");
probe::pci::probe_with(&unregistered, stop_if_fail)?;
Ok(())
}
pub fn get_list<T: DriverGeneric>() -> Vec<Device<T>> {
read(|manager| manager.dev_container.devices())
}
pub fn get<T: DriverGeneric>(id: DeviceId) -> Result<Device<T>, GetDeviceError> {
read(|manager| manager.dev_container.get_typed(id))
}
pub fn get_one<T: DriverGeneric>() -> Option<Device<T>> {
read(|manager| manager.dev_container.get_one())
}
pub fn fdt_phandle_to_device_id(phandle: Phandle) -> Option<DeviceId> {
probe::fdt::try_system().and_then(|system| system.phandle_to_device_id(phandle))
}
pub fn with_fdt<T>(f: impl FnOnce(&Fdt) -> T) -> Option<T> {
probe::fdt::try_system().map(|system| f(system.fdt()))
}
#[macro_export]
macro_rules! module_driver {
(
$($i:ident : $t:expr),+,
) => {
#[allow(unused)]
$crate::__mod_maker!{
pub mod some {
use super::*;
use $crate::register::*;
#[unsafe(link_section = ".driver.register")]
#[unsafe(no_mangle)]
#[used(linker)]
pub static DRIVER: DriverRegister = DriverRegister {
$($i : $t),+
};
}
}
};
}