diff --git a/libs/kaptan-dma/Cargo.toml b/libs/kaptan-dma/Cargo.toml new file mode 100644 index 0000000..d7f1568 --- /dev/null +++ b/libs/kaptan-dma/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "kaptan-dma" +edition.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true +version.workspace = true + +[lints] +workspace = true diff --git a/libs/kaptan-dma/src/lib.rs b/libs/kaptan-dma/src/lib.rs new file mode 100644 index 0000000..8757bc8 --- /dev/null +++ b/libs/kaptan-dma/src/lib.rs @@ -0,0 +1,73 @@ +//! DMA memory ownership and non-blocking transfer contracts. +//! +//! Board/HAL code proves the memory region, cache policy, and peripheral route. +//! Runtime code sees only prepared immutable TX ranges and terminal outcomes. + +#![no_std] + +/// A borrowed byte range prepared for a device-to-read DMA transfer. +/// +/// This is a capability rather than a general byte-slice wrapper. It exists +/// only after a board-selected policy proves DMA reachability and CPU-to-device +/// visibility for the selected controller. +pub struct DmaReadableBuffer<'a> { + bytes: &'a [u8], +} + +impl<'a> DmaReadableBuffer<'a> { + /// Creates a DMA-read capability after platform-specific validation. + /// + /// # Safety + /// + /// - `bytes` is reachable by the selected DMA engine. + /// - CPU writes to `bytes` are visible before transfer begins. + /// - `bytes` remains addressable, immovable, and immutable until a terminal + /// completion or a documented route-halt outcome releases ownership. + pub const unsafe fn new_unchecked(bytes: &'a [u8]) -> Self { + Self { bytes } + } + + /// Returns the DMA-visible byte range. + pub const fn bytes(&self) -> &'a [u8] { + self.bytes + } +} + +/// Prepares CPU-owned bytes for a DMA transmit handoff. +/// +/// A cache-disabled board validates the RAM range. A cached board must clean +/// the exact range and issue the required ordering barrier before returning. +pub trait DmaTxBufferFactory { + /// Platform-specific preparation failure. + type Error; + + /// Validates and prepares a frame for device DMA reads. + fn prepare<'a>(&mut self, bytes: &'a [u8]) -> Result, Self::Error>; +} + +/// Terminal result reported by a DMA transmit interrupt handler. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum TxCompletion { + /// The selected engine has no terminal event pending. + NotPending, + /// DMA reached the peripheral data-register endpoint. + /// + /// This does not prove that the final UART stop bit left the wire. + Complete, + /// The engine reported a terminal transfer fault. + TransferFault, + /// The route entered a halted state and requires explicit reinitialization. + Halted, +} + +/// Owns one non-blocking DMA-backed transmit route. +/// +/// The caller retains the prepared range until a terminal completion or fault. +/// Implementations must not poll for a hardware state transition from this API. +pub trait DmaTxEngine { + /// Start-operation failure. + type StartError; + + /// Starts one DMA transfer from a prepared readable buffer. + fn start(&mut self, buffer: DmaReadableBuffer<'_>) -> Result<(), Self::StartError>; +}