pub use crate::register;
pub use resource::Resource;
+use register::LocatedRegister;
+
/// Physical address type.
///
/// This is a type alias to either `u32` or `u64` depending on the config option
Ok(())
}
+ /// Generic fallible write of a fully-located register value.
+ ///
+ /// # Examples
+ ///
+ /// Tuples carrying a location and a value can be used with this method:
+ ///
+ /// ```no_run
+ /// use kernel::io::{
+ /// register,
+ /// Io,
+ /// Mmio,
+ /// };
+ ///
+ /// register! {
+ /// VERSION(u32) @ 0x100 {
+ /// 15:8 major;
+ /// 7:0 minor;
+ /// }
+ /// }
+ ///
+ /// impl VERSION {
+ /// fn new(major: u8, minor: u8) -> Self {
+ /// VERSION::zeroed().with_major(major).with_minor(minor)
+ /// }
+ /// }
+ ///
+ /// fn do_write_reg(io: &Mmio) -> Result {
+ ///
+ /// io.try_write_reg(VERSION::new(1, 0))
+ /// }
+ /// ```
+ #[inline(always)]
+ fn try_write_reg<T, L, V>(&self, value: V) -> Result
+ where
+ L: IoLoc<T>,
+ V: LocatedRegister<Location = L, Value = T>,
+ Self: IoCapable<L::IoType>,
+ {
+ let (location, value) = value.into_io_op();
+
+ self.try_write(location, value)
+ }
+
/// Generic fallible update with runtime bounds check.
///
/// Note: this does not perform any synchronization. The caller is responsible for ensuring
unsafe { self.io_write(io_value, address) }
}
+ /// Generic infallible write of a fully-located register value.
+ ///
+ /// # Examples
+ ///
+ /// Tuples carrying a location and a value can be used with this method:
+ ///
+ /// ```no_run
+ /// use kernel::io::{
+ /// register,
+ /// Io,
+ /// Mmio,
+ /// };
+ ///
+ /// register! {
+ /// VERSION(u32) @ 0x100 {
+ /// 15:8 major;
+ /// 7:0 minor;
+ /// }
+ /// }
+ ///
+ /// impl VERSION {
+ /// fn new(major: u8, minor: u8) -> Self {
+ /// VERSION::zeroed().with_major(major).with_minor(minor)
+ /// }
+ /// }
+ ///
+ /// fn do_write_reg(io: &Mmio<0x1000>) {
+ /// io.write_reg(VERSION::new(1, 0));
+ /// }
+ /// ```
+ #[inline(always)]
+ fn write_reg<T, L, V>(&self, value: V)
+ where
+ L: IoLoc<T>,
+ V: LocatedRegister<Location = L, Value = T>,
+ Self: IoKnownSize + IoCapable<L::IoType>,
+ {
+ let (location, value) = value.into_io_op();
+
+ self.write(location, value)
+ }
+
/// Generic infallible update with compile-time bounds check.
///
/// Note: this does not perform any synchronization. The caller is responsible for ensuring
//! .with_const_minor_revision::<10>()
//! // Runtime value.
//! .with_vendor_id(obtain_vendor_id());
-//! io.write((), new_boot0);
+//! io.write_reg(new_boot0);
//!
//! // Or, build a new value from zero and write it:
-//! io.write((), BOOT_0::zeroed()
+//! io.write_reg(BOOT_0::zeroed()
//! .with_const_major_revision::<3>()
//! .with_const_minor_revision::<10>()
//! .with_vendor_id(obtain_vendor_id())
}
}
+/// Trait implemented by items that contain both a register value and the absolute I/O location at
+/// which to write it.
+///
+/// Implementors can be used with [`Io::write_reg`](super::Io::write_reg).
+pub trait LocatedRegister {
+ /// Register value to write.
+ type Value: Register;
+ /// Full location information at which to write the value.
+ type Location: IoLoc<Self::Value>;
+
+ /// Consumes `self` and returns a `(location, value)` tuple describing a valid I/O write
+ /// operation.
+ fn into_io_op(self) -> (Self::Location, Self::Value);
+}
+
+impl<T> LocatedRegister for T
+where
+ T: FixedRegister,
+{
+ type Location = FixedRegisterLoc<Self::Value>;
+ type Value = T;
+
+ #[inline(always)]
+ fn into_io_op(self) -> (FixedRegisterLoc<T>, T) {
+ (FixedRegisterLoc::new(), self)
+ }
+}
+
/// Defines a dedicated type for a register, including getter and setter methods for its fields and
/// methods to read and write it from an [`Io`](kernel::io::Io) region.
///
/// // The location of fixed offset registers is already contained in their type. Thus, the
/// // `location` argument of `Io::write` is technically redundant and can be replaced by `()`.
/// io.write((), val2);
+///
+/// // Or, the single-argument `Io::write_reg` can be used.
+/// io.write_reg(val2);
/// # }
///
/// ```