1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
use super::*; /// Represents an MMIO address that can be safely read, but writes are /// dangerous. /// /// Unlike with raw pointers, this type favors unsafe construction and then /// assumes that all usage is safe once the value has been constructed. /// /// The convention is that reading the address will have no side effects. /// However, writing to the address will potentially do something bad if you /// aren't careful, and so writes are possible but `unsafe`. #[repr(transparent)] #[derive(Debug, Clone, Copy)] pub struct DangerWriteVolAddr<T> { addr: NonZeroUsize, _marker: PhantomData<T>, } impl_vol_eq!(DangerWriteVolAddr<T>); impl<T> DangerWriteVolAddr<T> { /// Constructs a new address. /// /// ## Safety /// The input must /// * Not be 0 (or _instant_ UB). /// * Be an actual MMIO location for the data type specified (or /// [`read`](SimpleVolAddr::read) and [`write`](SimpleVolAddr::write) will /// UB). #[must_use] #[inline(always)] pub(crate) const unsafe fn new(addr: usize) -> Self { Self { addr: NonZeroUsize::new_unchecked(addr), _marker: PhantomData } } /// Reads the current value at the address. #[must_use] #[inline(always)] pub fn read(&self) -> T where T: Copy, { unsafe { read_volatile(self.addr.get() as *const T) } } /// Writes a new value to the address. /// /// ## Safety /// * The safety rules depend on what address you're writing to. Each /// dangerous MMIO location has its own rules. #[inline(always)] pub unsafe fn write(&self, t: T) where T: Copy, { write_volatile(self.addr.get() as *mut T, t) } }