Skip to main content

sdmmc_protocol/
block.rs

1//! Block request state shared by SD/MMC host controller backends.
2//!
3//! The protocol crate intentionally does not know about `rd-block` or any
4//! executor. These types describe the portable queue contract that host
5//! drivers expose upward: submit one block transfer, advance it by polling or
6//! IRQ wakeups, and keep the concrete FIFO/DMA engine visible.
7
8use core::num::NonZeroUsize;
9
10/// Stable identifier returned by a host block queue after submission.
11#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct BlockRequestId(usize);
13
14impl BlockRequestId {
15    pub const fn new(id: usize) -> Self {
16        Self(id)
17    }
18}
19
20impl From<BlockRequestId> for usize {
21    fn from(value: BlockRequestId) -> Self {
22        value.0
23    }
24}
25
26/// Data engine used by an in-flight block request.
27#[derive(Clone, Copy, Debug, PartialEq, Eq)]
28pub enum BlockTransferMode {
29    /// Controller FIFO/data-port engine.
30    Fifo,
31    /// Host-controller DMA engine (SDHCI ADMA2, DW_mshc IDMAC, etc.).
32    Dma,
33}
34
35/// Buffer and address constraints exposed by a host block queue.
36#[derive(Clone, Copy, Debug, PartialEq, Eq)]
37pub struct BlockBufferConfig {
38    /// Logical block size accepted by the queue.
39    pub block_size: NonZeroUsize,
40    /// Required CPU-buffer alignment in bytes.
41    pub align: usize,
42    /// Device-visible DMA address mask, when the queue uses DMA.
43    pub dma_mask: Option<u64>,
44}
45
46impl BlockBufferConfig {
47    pub const fn new(block_size: NonZeroUsize, align: usize, dma_mask: Option<u64>) -> Self {
48        Self {
49            block_size,
50            align,
51            dma_mask,
52        }
53    }
54}
55
56/// Direction of a block request.
57#[derive(Clone, Copy, Debug, PartialEq, Eq)]
58pub enum BlockTransferDirection {
59    Read,
60    Write,
61}
62
63/// Observable state of one host block-transfer state machine.
64#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
65pub enum BlockTransferState {
66    #[default]
67    Idle,
68    Submitted {
69        id: BlockRequestId,
70        mode: BlockTransferMode,
71        direction: BlockTransferDirection,
72    },
73    Complete {
74        id: BlockRequestId,
75        mode: BlockTransferMode,
76        direction: BlockTransferDirection,
77    },
78    Failed {
79        id: BlockRequestId,
80        mode: BlockTransferMode,
81        direction: BlockTransferDirection,
82    },
83}
84
85impl BlockTransferState {
86    pub const fn id(self) -> Option<BlockRequestId> {
87        match self {
88            Self::Idle => None,
89            Self::Submitted { id, .. } | Self::Complete { id, .. } | Self::Failed { id, .. } => {
90                Some(id)
91            }
92        }
93    }
94
95    pub const fn mode(self) -> Option<BlockTransferMode> {
96        match self {
97            Self::Idle => None,
98            Self::Submitted { mode, .. }
99            | Self::Complete { mode, .. }
100            | Self::Failed { mode, .. } => Some(mode),
101        }
102    }
103
104    pub const fn direction(self) -> Option<BlockTransferDirection> {
105        match self {
106            Self::Idle => None,
107            Self::Submitted { direction, .. }
108            | Self::Complete { direction, .. }
109            | Self::Failed { direction, .. } => Some(direction),
110        }
111    }
112}
113
114/// Result of advancing a submitted transfer without blocking.
115#[derive(Clone, Copy, Debug, PartialEq, Eq)]
116pub enum BlockPoll {
117    Pending,
118    Complete,
119}
120
121/// Direction of a generic SD/MMC data command.
122#[derive(Clone, Copy, Debug, PartialEq, Eq)]
123pub enum DataCommandDirection {
124    Read,
125    Write,
126}
127
128/// Observable state of one protocol data command.
129#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
130pub enum DataCommandState {
131    #[default]
132    Idle,
133    Submitted {
134        direction: DataCommandDirection,
135        cmd_index: u8,
136        block_size: u32,
137        block_count: u32,
138    },
139}
140
141/// Result of advancing a generic data command without blocking.
142#[derive(Clone, Copy, Debug)]
143pub enum DataCommandPoll {
144    Pending,
145    Complete(crate::response::Response),
146}
147
148/// Result of advancing a submitted command without blocking.
149#[derive(Clone, Copy, Debug, PartialEq, Eq)]
150pub enum CommandPoll {
151    Pending,
152    Complete,
153}
154
155/// Result of advancing a submitted command and harvesting its response when
156/// available.
157#[derive(Clone, Copy, Debug)]
158pub enum CommandResponsePoll {
159    Pending,
160    Complete(crate::response::Response),
161}
162
163/// Generic result of advancing an operation without blocking.
164#[derive(Clone, Copy, Debug)]
165pub enum OperationPoll<T> {
166    Pending,
167    Complete(T),
168}
169
170impl From<CommandResponsePoll> for OperationPoll<crate::response::Response> {
171    fn from(value: CommandResponsePoll) -> Self {
172        match value {
173            CommandResponsePoll::Pending => Self::Pending,
174            CommandResponsePoll::Complete(response) => Self::Complete(response),
175        }
176    }
177}
178
179impl From<DataCommandPoll> for OperationPoll<crate::response::Response> {
180    fn from(value: DataCommandPoll) -> Self {
181        match value {
182            DataCommandPoll::Pending => Self::Pending,
183            DataCommandPoll::Complete(response) => Self::Complete(response),
184        }
185    }
186}
187
188impl From<BlockPoll> for OperationPoll<()> {
189    fn from(value: BlockPoll) -> Self {
190        match value {
191            BlockPoll::Pending => Self::Pending,
192            BlockPoll::Complete => Self::Complete(()),
193        }
194    }
195}