dev: pass DeviceInitContext into Device::init()

This commit is contained in:
Mark Poliakov 2025-02-06 12:24:03 +02:00
parent 7348232aa9
commit 8cbde8389f
24 changed files with 122 additions and 75 deletions

View File

@ -8,7 +8,7 @@ use alloc::{format, sync::Arc, vec::Vec};
use bytemuck::Zeroable; use bytemuck::Zeroable;
use data::ReceivedFis; use data::ReceivedFis;
use device_api::{ use device_api::{
device::Device, device::{Device, DeviceInitContext},
interrupt::{InterruptAffinity, InterruptHandler, IrqVector}, interrupt::{InterruptAffinity, InterruptHandler, IrqVector},
}; };
use error::AhciError; use error::AhciError;
@ -181,7 +181,9 @@ impl InterruptHandler for AhciController {
} }
impl Device for AhciController { impl Device for AhciController {
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, cx: DeviceInitContext) -> Result<(), Error> {
// TODO use DmaAllocator instead of PageBox
let _ = cx;
// Do the init in background // Do the init in background
runtime::spawn(self.late_init())?; runtime::spawn(self.late_init())?;
Ok(()) Ok(())

View File

@ -15,7 +15,7 @@ use core::{
use alloc::{collections::BTreeMap, format, sync::Arc, vec::Vec}; use alloc::{collections::BTreeMap, format, sync::Arc, vec::Vec};
use command::{IdentifyActiveNamespaceIdListRequest, IdentifyControllerRequest}; use command::{IdentifyActiveNamespaceIdListRequest, IdentifyControllerRequest};
use device_api::{ use device_api::{
device::Device, device::{Device, DeviceInitContext},
interrupt::{InterruptAffinity, InterruptHandler, IrqVector}, interrupt::{InterruptAffinity, InterruptHandler, IrqVector},
}; };
use drive::NvmeNamespace; use drive::NvmeNamespace;
@ -345,7 +345,10 @@ impl InterruptHandler for NvmeController {
} }
impl Device for NvmeController { impl Device for NvmeController {
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, cx: DeviceInitContext) -> Result<(), Error> {
// TODO use DmaAllocator instead of PageBox
let _ = cx;
let regs = self.regs.lock(); let regs = self.regs.lock();
let timeout = Duration::from_millis(regs.CAP.read(CAP::TO) * 500); let timeout = Duration::from_millis(regs.CAP.read(CAP::TO) * 500);

View File

@ -13,8 +13,12 @@ use alloc::{format, sync::Arc, vec::Vec};
use bitflags::bitflags; use bitflags::bitflags;
use device::{PciBusDevice, PciDeviceInfo}; use device::{PciBusDevice, PciDeviceInfo};
use device_api::device::DeviceInitContext;
use interrupt::{PciInterruptMap, PciMsiMap}; use interrupt::{PciInterruptMap, PciMsiMap};
use libk::fs::sysfs::{self, object::KObject}; use libk::{
dma::DummyDmaAllocator,
fs::sysfs::{self, object::KObject},
};
use libk_mm::address::PhysicalAddress; use libk_mm::address::PhysicalAddress;
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
use space::legacy; use space::legacy;
@ -614,8 +618,11 @@ fn setup_bus_device(device: &mut PciBusDevice) -> Result<(), Error> {
if let Some(driver) = driver::lookup_driver(&device.info) { if let Some(driver) = driver::lookup_driver(&device.info) {
log::info!("{} -> {}", device.info.address, driver.driver_name()); log::info!("{} -> {}", device.info.address, driver.driver_name());
let instance = driver.probe(&device.info)?; let instance = driver.probe(&device.info)?;
let cx = DeviceInitContext {
dma_allocator: Arc::new(DummyDmaAllocator),
};
unsafe { instance.clone().init() }?; unsafe { instance.clone().init(cx) }?;
device.device.replace(instance); device.device.replace(instance);
device.driver_name.replace(driver.driver_name()); device.driver_name.replace(driver.driver_name());

View File

@ -2,7 +2,7 @@ use core::mem::MaybeUninit;
use alloc::sync::Arc; use alloc::sync::Arc;
use device_api::{ use device_api::{
device::Device, device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqVector}, interrupt::{InterruptHandler, IrqVector},
}; };
use libk::error::Error; use libk::error::Error;
@ -342,7 +342,10 @@ impl InterruptHandler for Rtl8139 {
} }
impl Device for Rtl8139 { impl Device for Rtl8139 {
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, cx: DeviceInitContext) -> Result<(), Error> {
// TODO use DmaAllocator instead of PageBox
let _ = cx;
log::info!("Initialize rtl8139 driver"); log::info!("Initialize rtl8139 driver");
log::info!("MAC: {}", self.mac); log::info!("MAC: {}", self.mac);

View File

@ -5,7 +5,7 @@ use core::{
use alloc::{sync::Arc, vec::Vec}; use alloc::{sync::Arc, vec::Vec};
use device_api::{ use device_api::{
device::Device, device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqVector}, interrupt::{InterruptHandler, IrqVector},
}; };
use libk::error::Error; use libk::error::Error;
@ -592,7 +592,9 @@ impl InterruptHandler for Rtl8168 {
} }
impl Device for Rtl8168 { impl Device for Rtl8168 {
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, cx: DeviceInitContext) -> Result<(), Error> {
// TODO use DmaAllocator instead of PageBox
let _ = cx;
log::info!("Initialize rtl8168"); log::info!("Initialize rtl8168");
log::info!("MAC: {}", self.mac); log::info!("MAC: {}", self.mac);

View File

@ -3,7 +3,7 @@ use core::sync::atomic::{AtomicU8, Ordering};
use alloc::{boxed::Box, collections::btree_map::BTreeMap, sync::Arc, vec::Vec}; use alloc::{boxed::Box, collections::btree_map::BTreeMap, sync::Arc, vec::Vec};
use async_trait::async_trait; use async_trait::async_trait;
use device_api::{ use device_api::{
device::Device, device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqVector}, interrupt::{InterruptHandler, IrqVector},
}; };
use libk::{error::Error, task::runtime}; use libk::{error::Error, task::runtime};
@ -443,7 +443,10 @@ impl CommandExecutor for Xhci {
} }
impl Device for Xhci { impl Device for Xhci {
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, cx: DeviceInitContext) -> Result<(), Error> {
// TODO use DmaAllocator instead of PageBox
let _ = cx;
self.regs.hc_reset(10000000)?; self.regs.hc_reset(10000000)?;
log::info!("xHC reset complete"); log::info!("xHC reset complete");

View File

@ -6,7 +6,7 @@ use core::mem::MaybeUninit;
use alloc::{sync::Arc, vec::Vec}; use alloc::{sync::Arc, vec::Vec};
use command::{ControlLock, ScanoutInfo}; use command::{ControlLock, ScanoutInfo};
use device_api::device::Device; use device_api::device::{Device, DeviceInitContext};
use libk::device::{ use libk::device::{
display::{ display::{
DisplayDevice, DisplayMode, DisplayOwner, DriverFlags, FramebufferInfo, PixelFormat, DisplayDevice, DisplayMode, DisplayOwner, DriverFlags, FramebufferInfo, PixelFormat,
@ -253,7 +253,9 @@ impl<T: Transport + 'static> VirtioGpu<T> {
} }
impl<T: Transport + 'static> Device for VirtioGpu<T> { impl<T: Transport + 'static> Device for VirtioGpu<T> {
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, cx: DeviceInitContext) -> Result<(), Error> {
// TODO use DmaAllocator instead of PageBox
let _ = cx;
let status = self.begin_init()?; let status = self.begin_init()?;
self.setup_queues()?; self.setup_queues()?;
self.finish_init(status); self.finish_init(status);

View File

@ -8,7 +8,7 @@ use core::mem::size_of;
use alloc::{collections::BTreeMap, sync::Arc}; use alloc::{collections::BTreeMap, sync::Arc};
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use device_api::{ use device_api::{
device::Device, device::{Device, DeviceInitContext},
interrupt::{InterruptAffinity, InterruptHandler, IrqVector}, interrupt::{InterruptAffinity, InterruptHandler, IrqVector},
}; };
use libk_mm::PageBox; use libk_mm::PageBox;
@ -253,7 +253,9 @@ impl<T: Transport + 'static> Device for VirtioNet<T> {
"VirtIO Network Device" "VirtIO Network Device"
} }
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, cx: DeviceInitContext) -> Result<(), Error> {
// TODO use DmaAllocator instead of PageBox
let _ = cx;
let status = self.begin_init()?; let status = self.begin_init()?;
// TODO multiqueue // TODO multiqueue

View File

@ -1,7 +1,11 @@
use alloc::sync::Arc; use alloc::sync::Arc;
use yggdrasil_abi::error::Error; use yggdrasil_abi::error::Error;
use crate::{bus::Bus, clock::ClockController}; use crate::{bus::Bus, clock::ClockController, dma::DmaAllocator};
pub struct DeviceInitContext {
pub dma_allocator: Arc<dyn DmaAllocator>,
}
pub trait Device: Sync + Send { pub trait Device: Sync + Send {
fn display_name(&self) -> &str; fn display_name(&self) -> &str;
@ -13,7 +17,8 @@ pub trait Device: Sync + Send {
/// # Safety /// # Safety
/// ///
/// The caller must make sure the function is only called once. /// The caller must make sure the function is only called once.
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, cx: DeviceInitContext) -> Result<(), Error> {
let _ = cx;
Ok(()) Ok(())
} }

View File

@ -0,0 +1 @@
pub trait DmaAllocator {}

View File

@ -11,6 +11,8 @@ pub mod interrupt;
pub mod serial; pub mod serial;
pub mod timer; pub mod timer;
pub mod dma;
use device::Device; use device::Device;
use yggdrasil_abi::error::Error; use yggdrasil_abi::error::Error;

View File

@ -8,10 +8,11 @@ use alloc::{
use device_api::{ use device_api::{
bus::Bus, bus::Bus,
clock::ClockController, clock::ClockController,
device::Device, device::{Device, DeviceInitContext},
interrupt::{ExternalInterruptController, FullIrq, MessageInterruptController}, interrupt::{ExternalInterruptController, FullIrq, MessageInterruptController},
}; };
use fdt_rs::spec::Phandle; use fdt_rs::spec::Phandle;
use libk::dma::DummyDmaAllocator;
use libk_mm::address::PhysicalAddress; use libk_mm::address::PhysicalAddress;
use libk_util::OneTimeInit; use libk_util::OneTimeInit;
use yggdrasil_abi::error::Error; use yggdrasil_abi::error::Error;
@ -188,7 +189,8 @@ impl Node {
pub fn lazy_init(self: Arc<Self>) -> Option<Result<(), Error>> { pub fn lazy_init(self: Arc<Self>) -> Option<Result<(), Error>> {
let device = self.clone().probe()?; let device = self.clone().probe()?;
let result = self.init_token.or_try_init_with(|| { let result = self.init_token.or_try_init_with(|| {
unsafe { device.init() }?; let cx = self.make_init_context();
unsafe { device.init(cx) }?;
Ok(()) Ok(())
}); });
match result { match result {
@ -233,12 +235,21 @@ impl Node {
.inspect_err(|_| log::error!("Does not exist: probe({:?})", self.name))?; .inspect_err(|_| log::error!("Does not exist: probe({:?})", self.name))?;
self.init_token.try_init_with_opt(|| { self.init_token.try_init_with_opt(|| {
unsafe { device.init() }?; let cx = self.make_init_context();
unsafe { device.init(cx) }?;
Ok(()) Ok(())
})?; })?;
Ok(()) Ok(())
} }
fn make_init_context(&self) -> DeviceInitContext {
let cx = DeviceInitContext {
dma_allocator: Arc::new(DummyDmaAllocator),
};
cx
}
/// Returns an iterator over the node's children /// Returns an iterator over the node's children
pub fn children(&self) -> impl Iterator<Item = &Arc<Node>> { pub fn children(&self) -> impl Iterator<Item = &Arc<Node>> {
self.children.get().iter() self.children.get().iter()

View File

@ -49,18 +49,6 @@ impl PageProvider for Partition {
} }
impl Device for Partition { impl Device for Partition {
unsafe fn init(self: Arc<Self>) -> Result<(), Error> {
todo!()
}
unsafe fn deinit(&self) -> Result<(), Error> {
todo!()
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
todo!()
}
fn display_name(&self) -> &str { fn display_name(&self) -> &str {
"Partition" "Partition"
} }

View File

@ -162,36 +162,36 @@ impl DeviceRegistry {
}); });
} }
pub fn run_initialization(&self) { // pub fn run_initialization(&self) {
let mut devices = self.pending_initialization.write(); // let mut devices = self.pending_initialization.write();
for pending in devices.iter_mut() { // for pending in devices.iter_mut() {
if pending.irq_only { // if pending.irq_only {
continue; // continue;
} // }
log::debug!("Init device: {:?}", pending.device.display_name()); // log::debug!("Init device: {:?}", pending.device.display_name());
if let Err(error) = unsafe { pending.device.clone().init() } { // if let Err(error) = unsafe { pending.device.clone().init() } {
log::error!("{:?} init error: {error:?}", pending.device.display_name()); // log::error!("{:?} init error: {error:?}", pending.device.display_name());
pending.failed = true; // pending.failed = true;
continue; // continue;
} // }
} // }
for pending in devices.drain(..) { // for pending in devices.drain(..) {
if pending.failed { // if pending.failed {
continue; // continue;
} // }
log::debug!("Init IRQ: {:?}", pending.device.display_name()); // log::debug!("Init IRQ: {:?}", pending.device.display_name());
if let Err(error) = unsafe { pending.device.clone().init_irq() } { // if let Err(error) = unsafe { pending.device.clone().init_irq() } {
log::error!( // log::error!(
"{:?} IRQ init error: {error:?}", // "{:?} IRQ init error: {error:?}",
pending.device.display_name() // pending.device.display_name()
); // );
} // }
} // }
} // }
} }
async fn probe_partition_table( async fn probe_partition_table(

5
kernel/libk/src/dma.rs Normal file
View File

@ -0,0 +1,5 @@
use device_api::dma::DmaAllocator;
pub struct DummyDmaAllocator;
impl DmaAllocator for DummyDmaAllocator {}

View File

@ -44,6 +44,8 @@ pub mod random;
pub mod time; pub mod time;
pub mod vfs; pub mod vfs;
pub mod dma;
#[cfg(any(target_os = "none", rust_analyzer))] #[cfg(any(target_os = "none", rust_analyzer))]
pub mod panic; pub mod panic;

View File

@ -4,7 +4,7 @@ use core::{mem::offset_of, ops::Range};
use abi::error::Error; use abi::error::Error;
use alloc::{sync::Arc, vec::Vec}; use alloc::{sync::Arc, vec::Vec};
use device_api::{ use device_api::{
device::Device, device::{Device, DeviceInitContext},
interrupt::{ interrupt::{
ExternalInterruptController, InterruptAffinity, InterruptHandler, Irq, IrqLevel, ExternalInterruptController, InterruptAffinity, InterruptHandler, Irq, IrqLevel,
IrqOptions, IrqTrigger, IrqVector, MessageInterruptController, MsiInfo, IrqOptions, IrqTrigger, IrqVector, MessageInterruptController, MsiInfo,
@ -83,7 +83,7 @@ pub struct Gicv2m {
} }
impl Device for Gicv2m { impl Device for Gicv2m {
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
let regs = self.regs.lock(); let regs = self.regs.lock();
log::info!("gicv2m: init @ {:#x}", self.base); log::info!("gicv2m: init @ {:#x}", self.base);

View File

@ -6,7 +6,7 @@ use aarch64_cpu::asm::barrier;
use abi::error::Error; use abi::error::Error;
use alloc::sync::Arc; use alloc::sync::Arc;
use device_api::{ use device_api::{
device::Device, device::{Device, DeviceInitContext},
interrupt::{ interrupt::{
ExternalInterruptController, FixedInterruptTable, FullIrq, InterruptHandler, ExternalInterruptController, FixedInterruptTable, FullIrq, InterruptHandler,
InterruptTable, IpiDeliveryTarget, IpiMessage, Irq, IrqLevel, IrqOptions, IrqTrigger, InterruptTable, IpiDeliveryTarget, IpiMessage, Irq, IrqLevel, IrqOptions, IrqTrigger,
@ -58,7 +58,7 @@ impl Device for Gic {
"ARM Generic Interrupt Controller v2" "ARM Generic Interrupt Controller v2"
} }
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
log::debug!( log::debug!(
"Init GIC: gicd={:#x}, gicc={:#x}", "Init GIC: gicd={:#x}, gicc={:#x}",
self.gicd_base, self.gicd_base,

View File

@ -6,7 +6,7 @@ use aarch64_cpu::registers::{CNTFRQ_EL0, CNTPCT_EL0, CNTP_CTL_EL0, CNTP_TVAL_EL0
use abi::{error::Error, time::NANOSECONDS_IN_SECOND}; use abi::{error::Error, time::NANOSECONDS_IN_SECOND};
use alloc::sync::Arc; use alloc::sync::Arc;
use device_api::{ use device_api::{
device::Device, device::{Device, DeviceInitContext},
interrupt::{FullIrq, InterruptHandler, IrqVector}, interrupt::{FullIrq, InterruptHandler, IrqVector},
}; };
use device_tree::driver::{device_tree_driver, Node, ProbeContext}; use device_tree::driver::{device_tree_driver, Node, ProbeContext};
@ -55,7 +55,7 @@ impl Device for ArmTimer {
"ARM Generic Timer" "ARM Generic Timer"
} }
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET);
Ok(()) Ok(())
} }

View File

@ -7,7 +7,10 @@ use core::ops::Range;
use abi::error::Error; use abi::error::Error;
use alloc::{sync::Arc, vec::Vec}; use alloc::{sync::Arc, vec::Vec};
use device_api::{bus::Bus, device::Device}; use device_api::{
bus::Bus,
device::{Device, DeviceInitContext},
};
use device_tree::{ use device_tree::{
driver::{device_tree_driver, Node, ProbeContext}, driver::{device_tree_driver, Node, ProbeContext},
DeviceTreePropertyRead, DeviceTreePropertyRead,
@ -18,7 +21,7 @@ struct SimpleBus {
} }
impl Device for SimpleBus { impl Device for SimpleBus {
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
Ok(()) Ok(())
} }

View File

@ -2,7 +2,10 @@
use aarch64_cpu::registers::ReadWriteable; use aarch64_cpu::registers::ReadWriteable;
use abi::error::Error; use abi::error::Error;
use alloc::sync::Arc; use alloc::sync::Arc;
use device_api::{clock::ClockController, device::Device}; use device_api::{
clock::ClockController,
device::{Device, DeviceInitContext},
};
use device_tree::driver::{device_tree_driver, Node, ProbeContext}; use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo}; use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
@ -52,7 +55,7 @@ impl ClockController for Bcm2835Aux {
} }
impl Device for Bcm2835Aux { impl Device for Bcm2835Aux {
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
let regs = DeviceMemoryIo::map(self.base, Default::default())?; let regs = DeviceMemoryIo::map(self.base, Default::default())?;
self.regs.init(IrqSafeSpinlock::new(regs)); self.regs.init(IrqSafeSpinlock::new(regs));
Ok(()) Ok(())

View File

@ -2,7 +2,10 @@
use abi::error::Error; use abi::error::Error;
use alloc::sync::Arc; use alloc::sync::Arc;
use device_api::{device::Device, CpuBringupDevice, ResetDevice}; use device_api::{
device::{Device, DeviceInitContext},
CpuBringupDevice, ResetDevice,
};
use device_tree::{ use device_tree::{
driver::{device_tree_driver, Node, ProbeContext}, driver::{device_tree_driver, Node, ProbeContext},
DeviceTreePropertyRead, DeviceTreePropertyRead,
@ -31,7 +34,7 @@ impl Device for Psci {
"ARM PSCI" "ARM PSCI"
} }
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
PLATFORM.psci.init(self.clone()); PLATFORM.psci.init(self.clone());
Ok(()) Ok(())
} }

View File

@ -8,7 +8,7 @@ use abi::{
}; };
use alloc::sync::Arc; use alloc::sync::Arc;
use device_api::{ use device_api::{
device::Device, device::{Device, DeviceInitContext},
interrupt::{FullIrq, InterruptHandler, IrqVector}, interrupt::{FullIrq, InterruptHandler, IrqVector},
}; };
use device_tree::{ use device_tree::{
@ -148,7 +148,7 @@ impl InterruptHandler for Bcm2835AuxUart {
} }
impl Device for Bcm2835AuxUart { impl Device for Bcm2835AuxUart {
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
// TODO initialize pinctrl // TODO initialize pinctrl
// NOTE: might as well make it an error if clock cannot be initialized // NOTE: might as well make it an error if clock cannot be initialized

View File

@ -2,7 +2,7 @@
use abi::{error::Error, io::TerminalOptions}; use abi::{error::Error, io::TerminalOptions};
use alloc::sync::Arc; use alloc::sync::Arc;
use device_api::{ use device_api::{
device::Device, device::{Device, DeviceInitContext},
interrupt::{FullIrq, InterruptHandler, IrqVector}, interrupt::{FullIrq, InterruptHandler, IrqVector},
}; };
use device_tree::driver::{device_tree_driver, Node, ProbeContext}; use device_tree::driver::{device_tree_driver, Node, ProbeContext};
@ -139,7 +139,7 @@ impl Device for Pl011 {
"Primecell PL011 UART" "Primecell PL011 UART"
} }
unsafe fn init(self: Arc<Self>) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
let mut io = Io { let mut io = Io {
regs: DeviceMemoryIo::map(self.base, Default::default())?, regs: DeviceMemoryIo::map(self.base, Default::default())?,
}; };