A dynamic driver management framework for embedded systems written in Rust.
Hardware abstraction interface crates with Any for dynamic dispatch:
rdif-base: Core driver traits and error typesrdif-intc: Interrupt controller interfacerdif-clk: Clock management interfacerdif-serial: Serial communication interfacerdif-timer: Timer/counter interfacerdif-block: Block device interfacerdif-power: Power management interfacerdif-systick: System tick interfacerdif-net: Network interface
Procedural macros to simplify driver registration and module generation.
The main driver container responsible for:
- Driver registration and discovery
- Device probing and initialization
- Device lifecycle management
- Type-safe device access
Devices are managed through a long-term borrowing model using Device<T> wrappers. Unlike Mutex<T>, when a task borrows a device, it gains exclusive ownership. Other tasks attempting to borrow will receive an error with the owner's task ID, enabling forced task termination if needed.
Key features:
- Lock-free operations once ownership is acquired
- Weak pointer support for interrupt handlers
- Cloning
Device<T>creates weak references for fast indexing
Drivers can be registered from different crates using the module_driver! macro:
use rdrive::{
module_driver,
register::{ProbeKind,ProbeLevel,ProbePriority,FdtInfo},
probe::OnProbeError,PlatformDevice,DriverGeneric,};structGicV3Driver{// Driver implementation}implDriverGenericforGicV3Driver{fnopen(&mutself) -> Result<(), rdrive::KError>{// Initialize hardwareOk(())}fnclose(&mutself) -> Result<(), rdrive::KError>{// Cleanup hardwareOk(())}}impl rdrive::driver::intc::InterfaceforGicV3Driver{// Implement interrupt controller interfacefnenable_irq(&mutself,irq: rdrive::IrqId) -> Result<(), rdrive::driver::intc::IntcError>{// Enable interrupt implementationOk(())}// ... other required methods}fnprobe_gicv3(fdt:FdtInfo<'_>,dev:PlatformDevice) -> Result<(),OnProbeError>{let node = fdt.node;letmut reg = node.reg().ok_or("No reg property")?;let gicd_reg = reg.next().ok_or("Missing GICD register")?;let gicr_reg = reg.next().ok_or("Missing GICR register")?;let driver = GicV3Driver::new(
gicd_reg.addressasusize,
gicr_reg.addressasusize,);
dev.register(driver);Ok(())}module_driver!{
name:"GICv3",
level:ProbeLevel::PreKernel,
priority:ProbePriority::INTC,
probe_kinds:&[ProbeKind::Fdt{
compatibles:&["arm,gic-v3"],
on_probe: probe_gicv3,}],}Add the following section to your linker script:
.driver.register : ALIGN(4K) {
_sdriver = .;
*(.driver.register .driver.register.*)
_edriver = .;
. = ALIGN(4K);
}use rdrive::register::DriverRegisterSlice;fndriver_registers() -> &'static[u8]{unsafeextern"C"{fn_sdriver();fn_edriver();}unsafe{ core::slice::from_raw_parts(
_sdriver as*constu8, _edriver asusize - _sdriver asusize)}}fnget_driver_registers() -> DriverRegisterSlice{DriverRegisterSlice::from_raw(driver_registers())}use rdrive::{Platform, probe_pre_kernel, probe_all};use core::ptr::NonNull;fninit_drivers(){// Initialize with device treelet fdt_addr = /* device tree address */;let platform = Platform::Fdt{addr:NonNull::new(fdt_addr).unwrap(),};// Initialize the driver framework
rdrive::init(platform).unwrap();// Register all discovered drivers
rdrive::register_append(get_driver_registers().as_slice());// Probe critical drivers first (interrupt controllers, etc.)
rdrive::probe_pre_kernel().unwrap();// Initialize interrupt system// irq::init_main_cpu();// Probe remaining drivers
rdrive::probe_all(false).unwrap();// false = don't stop on failures}use rdrive::{get_list, get_one, driver::Intc};fnuse_devices(){// Get all interrupt controllerslet intc_list = get_list::<Intc>();for intc in intc_list {println!("Found INTC: {:?}", intc.descriptor());}// Get the first available interrupt controllerifletSome(intc) = get_one::<Intc>(){// Use the device - this gives exclusive accessmatch intc.try_lock(){Ok(mut locked_intc) => {// Safe to use locked_intc without additional synchronization
locked_intc.enable_irq(42.into()).unwrap();}Err(owner_id) => {println!("Device busy, owned by task: {:?}", owner_id);}}}}- Device Tree (FDT): Automatic device discovery from device tree
- Static Configuration: Manual device registration (planned)
See the examples/ directory for complete usage examples:
examples/enumerate/: Basic driver enumeration and device tree parsing
For complete integration examples, see: