Skip to main content

sdio/
lib.rs

1//! SD Card Registers
2//!
3//! Register representations can be created from an array of little endian
4//! words. Note that the SDMMC protocol transfers the registers in big endian
5//! byte order.
6//!
7//! PLSS_v7_10: Physical Layer Specification Simplified Specification Version
8//! 7.10. March 25, 2020. (C) SD Card Association
9
10#![cfg_attr(not(test), no_std)]
11
12use aligned::{A4, Aligned};
13use embedded_hal_async::delay::DelayNs;
14
15use crate::sd::{
16    BlockSize, CardCapacity, CardStatus, OCR, block_size, read_multiple_blocks, read_single_block,
17    stop_transmission, write_multiple_blocks, write_single_block,
18};
19
20pub mod common;
21pub mod emmc;
22pub mod sd;
23pub mod sdio;
24pub mod spi;
25
26const INIT_FREQ: u32 = 400_000;
27
28#[derive(Debug)]
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30pub enum MmcError {
31    Timeout,
32    Crc,
33    IllegalCommand,
34    Busy,
35    Io,
36    SignalingSwitchFailed,
37    Unsupported,
38    Other,
39}
40
41#[derive(Debug, Clone, Copy)]
42#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43pub enum BusWidth {
44    W1,
45    W4,
46    W8,
47}
48
49#[derive(Debug, Clone, Copy)]
50#[cfg_attr(feature = "defmt", derive(defmt::Format))]
51pub enum ResponseLen {
52    Zero,
53    R48,
54    R136,
55}
56
57impl ResponseLen {
58    pub const fn words(&self) -> usize {
59        match self {
60            Self::Zero => 0,
61            Self::R48 => 1,
62            Self::R136 => 4,
63        }
64    }
65}
66
67/// ---------------------------------------------------------------------------
68/// Response Trait
69/// ---------------------------------------------------------------------------
70///
71/// Represents a parsed response from the card.
72/// Each command defines its own associated response type via a GAT.
73/// This allows strongly typed responses (R1, R2, R3, R5, R6, R7, etc.)
74/// instead of a generic "MmcResponse" blob.
75///
76/// Example:
77///   CMD8 → R7
78///   CMD17 → R1
79///   CMD9  → R2
80///
81pub trait Response: Sized {
82    /// Whether to check the CRC
83    const CRC: bool;
84
85    /// Whether to wait until DAT0 goes high
86    const BUSY: bool;
87
88    /// Response length
89    const LEN: ResponseLen;
90
91    /// Parse the reponse from words. Only the `ResponseLen` words are used.
92    fn from_words(buf: &[u32; 4]) -> Self;
93}
94
95/// ---------------------------------------------------------------------------
96/// Command Trait (with GAT for response type)
97/// ---------------------------------------------------------------------------
98///
99/// Represents a protocol command (CMD0–CMD63, ACMDs, CMD52/53 for SDIO).
100///
101/// - `INDEX` is the fixed command index from the SD/MMC/SDIO spec.
102/// - `arg()` returns the 32-bit argument field.
103/// - `Resp<'a>` is the associated response type for this command.
104///
105/// This gives you compile-time correctness:
106///   - CMD8 always returns R7
107///   - CMD17 always returns R1
108///   - CMD9 always returns R2
109///
110/// No downcasting, no runtime parsing, no mistakes.
111///
112pub trait Command {
113    /// The fixed command index (e.g., 17 for CMD17).
114    const INDEX: u8;
115
116    /// The associated response type for this command.
117    type Resp<'a>: Response
118    where
119        Self: 'a;
120
121    /// The fixed command index (e.g., 17 for CMD17).
122    fn index(&self) -> u8 {
123        Self::INDEX
124    }
125
126    /// Compute the 32-bit argument for this command.
127    fn arg(&self) -> u32;
128}
129
130/// Block mode: fixed-size blocks (CMD17/18/24/25, CMD53 block mode)
131pub trait BlockCommand: Command {
132    /// Size of each block in bytes (usually 512 for SD/MMC).
133    fn block_size(&self) -> BlockSize;
134
135    /// Number of blocks to transfer.
136    fn block_count(&self) -> u32;
137}
138
139/// Byte mode: arbitrary byte counts (CMD53 byte mode, SPI multi-byte)
140pub trait ByteCommand: Command {
141    /// Number of bytes to transfer (arbitrary length).
142    fn byte_count(&self) -> usize;
143}
144
145/// ControlCommand: commands with no data transfer (CMD0, CMD8, CMD55, etc.)
146pub trait ControlCommand: Command {}
147
148/// BlockReadCommand: block-mode read (CMD17, CMD18)
149pub trait BlockReadCommand: BlockCommand {
150    /// Mutable buffer for block-mode reads. The length of this buffer must be `block_size()` * `block_count()`
151    fn buf(&mut self) -> &mut Aligned<A4, [u8]>;
152}
153
154/// BlockWriteCommand: block-mode write (CMD24, CMD25)
155pub trait BlockWriteCommand: BlockCommand {
156    /// Buffer for block-mode writes. The length of this buffer must be `block_size()` * `block_count()`
157    fn buf(&self) -> &Aligned<A4, [u8]>;
158}
159
160/// ByteReadCommand: byte-mode read (CMD53 byte read)
161pub trait ByteReadCommand: ByteCommand {
162    /// Mutable buffer for byte-mode reads. The length of this buffer must be `byte_count()`.
163    fn buf(&mut self) -> &mut Aligned<A4, [u8]>;
164}
165
166/// ByteWriteCommand: byte-mode write (CMD53 byte write)
167pub trait ByteWriteCommand: ByteCommand {
168    /// Buffer for byte-mode writes. The length of this buffer must be `byte_count()`.
169    fn buf(&self) -> &Aligned<A4, [u8]>;
170}
171
172/// ---------------------------------------------------------------------------
173/// MmcBus Trait
174/// ---------------------------------------------------------------------------
175///
176/// This is the lowest-level hardware abstraction for SD/MMC/SDIO host
177/// controllers. It corresponds to the Linux `mmc_host_ops` interface.
178///
179/// It exposes:
180///   • Command-only operations
181///   • Block-mode read/write
182///   • Byte-mode read/write
183///   • Bus configuration (clock, width)
184///
185/// Everything else (card initialization, SDIO function drivers, block devices)
186/// is built on top of this trait.
187///
188/// If hardware support is available, methods should not return until DAT0 goes high
189/// if the associated reponse has `BUSY` set to `true`.
190pub trait MmcBus {
191    /// Send a command that has no data transfer (e.g., CMD0, CMD8, CMD55).
192    ///
193    /// If called with `CMD11`, the bus should perform the voltage switch sequence.
194    fn send_command<'a, C>(
195        &mut self,
196        cmd: C,
197    ) -> impl Future<Output = Result<C::Resp<'a>, MmcError>>
198    where
199        C: ControlCommand + 'a;
200
201    /// Read N blocks of fixed size (CMD17, CMD18, CMD53 block mode).
202    fn read_blocks<'a, C>(&mut self, cmd: C) -> impl Future<Output = Result<C::Resp<'a>, MmcError>>
203    where
204        C: BlockReadCommand + 'a;
205
206    /// Write N blocks of fixed size (CMD24, CMD25, CMD53 block mode).
207    fn write_blocks<'a, C>(
208        &mut self,
209        cmd: C,
210    ) -> impl Future<Output = Result<C::Resp<'a>, MmcError>>
211    where
212        C: BlockWriteCommand + 'a;
213
214    /// Read an arbitrary number of bytes (CMD53 byte mode, SPI multi-byte).
215    fn read_bytes<'a, C>(&mut self, cmd: C) -> impl Future<Output = Result<C::Resp<'a>, MmcError>>
216    where
217        C: ByteReadCommand + 'a;
218
219    /// Write an arbitrary number of bytes (CMD53 byte mode, SPI multi-byte).
220    fn write_bytes<'a, C>(&mut self, cmd: C) -> impl Future<Output = Result<C::Resp<'a>, MmcError>>
221    where
222        C: ByteWriteCommand + 'a;
223
224    /// Initialize the bus in one-bit mode at 3.3v and the requested frequency.
225    ///
226    /// `hz` will always be `400_000`. The argument is provided so that the HAL does not have to define this.
227    fn init_idle(&mut self, hz: u32) -> impl Future<Output = Result<(), MmcError>>;
228
229    /// Tune the bus, if required. Called after the bus is set to the target frequency; needed for uhs.
230    #[allow(unused_variables)]
231    fn tune_bus<O>(
232        &mut self,
233        width: BusWidth,
234        hz: u32,
235        op: &mut O,
236    ) -> impl Future<Output = Result<(), MmcError>>
237    where
238        O: TuningOp,
239    {
240        async { Ok(()) }
241    }
242
243    /// Wait for DAT1 to be pulled low.
244    fn wait_for_event(&mut self) -> impl Future<Output = Result<(), MmcError>> {
245        async { Ok(()) }
246    }
247
248    /// Configure bus width and frequency.
249    ///
250    /// Will not be called with a frequency higher than `supports_frequency()` or a bus width above
251    /// `supports_bus_width()`.
252    fn set_bus(&mut self, width: BusWidth, hz: u32) -> Result<(), MmcError>;
253
254    /// Optional: whether the host supports native MMC mode. Otherwise, SPI mode is used.
255    fn supports_mmc(&self) -> bool {
256        false
257    }
258
259    /// Optional: the maximum bus width available to the host
260    fn supports_bus_width(&self) -> BusWidth {
261        BusWidth::W1
262    }
263
264    /// Optional: whether the host supports 1.8v. If true, `send_command` will be called with `CMD11`.
265    fn supports_1v8(&self) -> bool {
266        false
267    }
268
269    /// Optional: the maximum frequency supported by this bus. Defaults to 25Mhz
270    fn supports_frequency(&self) -> u32 {
271        25_000_000
272    }
273}
274
275impl<T: MmcBus> MmcBus for &mut T {
276    async fn send_command<'a, C>(&mut self, cmd: C) -> Result<C::Resp<'a>, MmcError>
277    where
278        C: ControlCommand + 'a,
279    {
280        T::send_command(self, cmd).await
281    }
282
283    async fn read_blocks<'a, C>(&mut self, cmd: C) -> Result<C::Resp<'a>, MmcError>
284    where
285        C: BlockReadCommand + 'a,
286    {
287        T::read_blocks(self, cmd).await
288    }
289
290    async fn write_blocks<'a, C>(&mut self, cmd: C) -> Result<C::Resp<'a>, MmcError>
291    where
292        C: BlockWriteCommand + 'a,
293    {
294        T::write_blocks(self, cmd).await
295    }
296
297    async fn read_bytes<'a, C>(&mut self, cmd: C) -> Result<C::Resp<'a>, MmcError>
298    where
299        C: ByteReadCommand + 'a,
300    {
301        T::read_bytes(self, cmd).await
302    }
303
304    async fn write_bytes<'a, C>(&mut self, cmd: C) -> Result<C::Resp<'a>, MmcError>
305    where
306        C: ByteWriteCommand + 'a,
307    {
308        T::write_bytes(self, cmd).await
309    }
310
311    async fn tune_bus<O>(&mut self, width: BusWidth, hz: u32, op: &mut O) -> Result<(), MmcError>
312    where
313        O: TuningOp,
314    {
315        T::tune_bus(self, width, hz, op).await
316    }
317
318    async fn wait_for_event(&mut self) -> Result<(), MmcError> {
319        T::wait_for_event(self).await
320    }
321
322    async fn init_idle(&mut self, hz: u32) -> Result<(), MmcError> {
323        T::init_idle(self, hz).await
324    }
325
326    fn set_bus(&mut self, width: BusWidth, hz: u32) -> Result<(), MmcError> {
327        T::set_bus(self, width, hz)
328    }
329
330    fn supports_1v8(&self) -> bool {
331        T::supports_1v8(self)
332    }
333
334    fn supports_bus_width(&self) -> BusWidth {
335        T::supports_bus_width(self)
336    }
337
338    fn supports_frequency(&self) -> u32 {
339        T::supports_frequency(self)
340    }
341
342    fn supports_mmc(&self) -> bool {
343        T::supports_mmc(self)
344    }
345}
346
347/// R1 — Zero response
348pub struct R0;
349
350impl Response for R0 {
351    const CRC: bool = false;
352    const LEN: ResponseLen = ResponseLen::Zero;
353    const BUSY: bool = false;
354
355    fn from_words(_buf: &[u32; 4]) -> Self {
356        Self
357    }
358}
359
360/// R1 — Normal status response
361///
362/// 48-bit, CRC-checked, no busy
363pub struct R1 {
364    pub status: u32,
365}
366
367#[derive(Debug, Clone, Copy, PartialEq, Eq)]
368pub enum CardState {
369    Idle,         // 0
370    Ready,        // 1
371    Ident,        // 2
372    Standby,      // 3
373    Transfer,     // 4
374    Data,         // 5
375    Receive,      // 6
376    Programming,  // 7
377    Reserved(u8), // 8–15
378}
379
380impl R1 {
381    /// Error bits defined in the SD Physical Spec §4.10.1 (Table 4-41).
382    pub const ERR_MASK: u32 = 0xFDF9_8008;
383
384    pub fn to_result(&self) -> Result<(), MmcError> {
385        if self.is_error() {
386            Err(MmcError::Other)
387        } else {
388            Ok(())
389        }
390    }
391
392    pub fn is_error(&self) -> bool {
393        self.status & Self::ERR_MASK != 0
394    }
395
396    pub fn app_cmd(&self) -> bool {
397        self.status & (1 << 5) != 0
398    }
399
400    pub fn ready_for_data(&self) -> bool {
401        self.status & (1 << 8) != 0
402    }
403
404    pub fn current_state(&self) -> CardState {
405        let v = ((self.status >> 9) & 0xF) as u8;
406        match v {
407            0 => CardState::Idle,
408            1 => CardState::Ready,
409            2 => CardState::Ident,
410            3 => CardState::Standby,
411            4 => CardState::Transfer,
412            5 => CardState::Data,
413            6 => CardState::Receive,
414            7 => CardState::Programming,
415            other => CardState::Reserved(other),
416        }
417    }
418}
419
420impl Response for R1 {
421    const CRC: bool = true;
422    const LEN: ResponseLen = ResponseLen::R48;
423    const BUSY: bool = false;
424
425    fn from_words(buf: &[u32; 4]) -> Self {
426        R1 { status: buf[0] }
427    }
428}
429
430/// R1b — R1 + busy on DAT0
431///
432/// 48-bit, CRC-checked, *busy*
433/// Card holds DAT0 low until internal operation completes.
434pub struct R1b {
435    pub status: u32,
436}
437
438impl R1b {
439    /// Convert this to a normal R1 response
440    pub const fn to_response(&self) -> R1 {
441        R1 {
442            status: self.status,
443        }
444    }
445}
446
447impl Response for R1b {
448    const CRC: bool = true;
449    const LEN: ResponseLen = ResponseLen::R48;
450    const BUSY: bool = true;
451
452    fn from_words(buf: &[u32; 4]) -> Self {
453        R1b { status: buf[0] }
454    }
455}
456
457/// R2 — CID/CSD (136-bit)
458///
459/// 136-bit, CRC-checked, no busy
460pub struct R2 {
461    pub words: [u32; 4],
462}
463
464impl Response for R2 {
465    const CRC: bool = true;
466    const LEN: ResponseLen = ResponseLen::R136;
467    const BUSY: bool = false;
468
469    fn from_words(buf: &[u32; 4]) -> Self {
470        R2 {
471            words: [buf[0], buf[1], buf[2], buf[3]],
472        }
473    }
474}
475
476/// R3 — OCR (Operating Conditions)
477///
478/// 48-bit, *no CRC*, no busy
479/// Used during initialization before CRC is enabled.
480pub struct R3 {
481    pub ocr: u32,
482}
483
484impl Response for R3 {
485    const CRC: bool = false;
486    const LEN: ResponseLen = ResponseLen::R48;
487    const BUSY: bool = false;
488
489    fn from_words(buf: &[u32; 4]) -> Self {
490        R3 { ocr: buf[0] }
491    }
492}
493
494/// R6 — Published RCA (SD only)
495///
496/// 48-bit, CRC-checked, no busy
497pub struct R6 {
498    pub rca: u16,
499    pub status: u16,
500}
501
502impl Response for R6 {
503    const CRC: bool = true;
504    const LEN: ResponseLen = ResponseLen::R48;
505    const BUSY: bool = false;
506
507    fn from_words(buf: &[u32; 4]) -> Self {
508        let v = buf[0];
509        R6 {
510            rca: (v >> 16) as u16,
511            status: (v & 0xFFFF) as u16,
512        }
513    }
514}
515
516/// R7 — Interface condition (CMD8)
517///
518/// 48-bit, CRC-checked, no busy
519pub struct R7 {
520    pub voltage: u8,
521    pub check_pattern: u8,
522}
523
524impl Response for R7 {
525    const CRC: bool = true;
526    const LEN: ResponseLen = ResponseLen::R48;
527    const BUSY: bool = false;
528
529    fn from_words(buf: &[u32; 4]) -> Self {
530        let v = buf[0];
531        R7 {
532            voltage: ((v >> 8) & 0xF) as u8,
533            check_pattern: (v & 0xFF) as u8,
534        }
535    }
536}
537
538// ===========================================================================
539// SDIO RESPONSES
540// ===========================================================================
541
542/// R4 — SDIO OCR + capability
543///
544/// 48-bit, *no CRC*, no busy
545/// Returned by CMD5 (IO_SEND_OP_COND)
546pub struct R4 {
547    pub ocr: u32,
548}
549
550impl Response for R4 {
551    const CRC: bool = false;
552    const LEN: ResponseLen = ResponseLen::R48;
553    const BUSY: bool = false;
554
555    fn from_words(buf: &[u32; 4]) -> Self {
556        R4 { ocr: buf[0] }
557    }
558}
559
560/// R5 — SDIO Direct I/O response
561///
562/// 48-bit, CRC-checked, no busy
563/// Returned by CMD52 (direct I/O)
564pub struct R5 {
565    pub flags: u8,
566    pub data: u8,
567}
568
569impl R5 {
570    /// COM_CRC_ERROR: the CRC of the command that triggered this was bad.
571    pub const FLAG_COM_CRC_ERROR: u8 = 1 << 7;
572    /// ILLEGAL_COMMAND: command not legal in the current state.
573    pub const FLAG_ILLEGAL_COMMAND: u8 = 1 << 6;
574    /// General ERROR.
575    pub const FLAG_ERROR: u8 = 1 << 3;
576    /// FUNCTION_NUMBER: requested function does not exist on this card.
577    pub const FLAG_FUNCTION_NUMBER: u8 = 1 << 1;
578    /// OUT_OF_RANGE: register address out of range for this function.
579    pub const FLAG_OUT_OF_RANGE: u8 = 1 << 0;
580
581    /// Mask of all bits that indicate a hard error.
582    pub const ERROR_FLAGS: u8 = Self::FLAG_COM_CRC_ERROR
583        | Self::FLAG_ILLEGAL_COMMAND
584        | Self::FLAG_ERROR
585        | Self::FLAG_FUNCTION_NUMBER
586        | Self::FLAG_OUT_OF_RANGE;
587
588    pub fn to_result(&self) -> Result<(), MmcError> {
589        if self.is_error() {
590            Err(MmcError::Other)
591        } else {
592            Ok(())
593        }
594    }
595
596    pub fn is_error(&self) -> bool {
597        self.flags & Self::ERROR_FLAGS != 0
598    }
599}
600
601impl Response for R5 {
602    const CRC: bool = true;
603    const LEN: ResponseLen = ResponseLen::R48;
604    const BUSY: bool = false;
605
606    fn from_words(buf: &[u32; 4]) -> Self {
607        let v = buf[0];
608        R5 {
609            flags: ((v >> 8) & 0xFF) as u8,
610            data: (v & 0xFF) as u8,
611        }
612    }
613}
614
615/// Bus Tuning Operation
616pub trait TuningOp {
617    /// Execute the operation. If error, abort the operation and return.
618    ///
619    /// Otherwise:
620    ///     - If `Ok(true)`, the tap is considered acceptable
621    ///     - If `Ok(false)`, the tap is not considered acceptable.
622    fn exec<B: MmcBus>(&mut self, bus: &mut B) -> impl Future<Output = Result<bool, MmcError>>;
623}
624
625// Allow passing some commands by reference
626impl<T: Command> Command for &T {
627    const INDEX: u8 = T::INDEX;
628
629    type Resp<'a>
630        = T::Resp<'a>
631    where
632        Self: 'a;
633
634    fn arg(&self) -> u32 {
635        T::arg(self)
636    }
637}
638
639impl<T: Command> Command for &mut T {
640    const INDEX: u8 = T::INDEX;
641
642    type Resp<'a>
643        = T::Resp<'a>
644    where
645        Self: 'a;
646
647    fn arg(&self) -> u32 {
648        T::arg(self)
649    }
650}
651
652impl<T: ControlCommand> ControlCommand for &T {}
653
654impl<T: BlockCommand> BlockCommand for &mut T {
655    fn block_count(&self) -> u32 {
656        T::block_count(self)
657    }
658
659    fn block_size(&self) -> BlockSize {
660        T::block_size(self)
661    }
662}
663
664impl<T: BlockReadCommand> BlockReadCommand for &mut T {
665    fn buf(&mut self) -> &mut Aligned<A4, [u8]> {
666        T::buf(self)
667    }
668}
669
670/// Bus Adapter that implements common functionality of all bus users
671struct BusAdapter<B: MmcBus, D: DelayNs> {
672    pub bus: B,
673    pub delay: D,
674    pub rca: u16,
675}
676
677impl<B: MmcBus, D: DelayNs> BusAdapter<B, D> {
678    /// Send the app command notification if this is an app command
679    async fn app_cmd(&mut self, app_cmd: bool) -> Result<(), MmcError> {
680        if app_cmd {
681            self.bus
682                .send_command(sd::app_cmd(self.rca))
683                .await?
684                .to_result()?
685        }
686
687        Ok(())
688    }
689
690    /// Check whether the card is ready for data
691    async fn check_card(&mut self) -> bool {
692        if let Ok(status) = self
693            .bus
694            .send_command(common::card_status(self.rca, false))
695            .await
696            && CardStatus::<()>::from(status).ready_for_data()
697        {
698            true
699        } else {
700            false
701        }
702    }
703
704    /// Wait for the card to be ready if required
705    async fn wait_if_required<R: Response>(&mut self) -> Result<(), MmcError> {
706        if !R::BUSY {
707            return Ok(());
708        }
709
710        // Wait up to 750ms + cmd time for ready after R1b response
711        // Note: this is a rather simplistic timeout loop. It can be improved later.
712        for _ in 0..750 {
713            if self.check_card().await {
714                return Ok(());
715            }
716
717            self.delay.delay_ms(1).await;
718        }
719
720        Err(MmcError::Timeout)
721    }
722
723    pub async fn init_idle(&mut self) -> Result<(), MmcError> {
724        // While the SD/SDIO card or eMMC is in identification mode,
725        // the SDMMC_CK frequency must be no more than 400 kHz.
726        self.bus.init_idle(INIT_FREQ).await?;
727
728        // Wait 74 cycles
729        self.delay.delay_us(74_000_000 / INIT_FREQ).await;
730
731        if self.bus.supports_mmc() {
732            self.send_command(common::idle(), false).await?;
733        } else {
734            self.send_command(common::idle_spi(), false).await?;
735        }
736
737        Ok(())
738    }
739
740    /// Select one card and place it into the _Tranfer State_
741    ///
742    /// If `None` is specifed for `card`, all cards are put back into
743    /// _Stand-by State_
744    pub async fn select_card(&mut self, rca: Option<u16>) -> Result<(), MmcError> {
745        match self
746            .send_command(common::select_card(rca.unwrap_or(0)), false)
747            .await
748        {
749            Err(MmcError::Timeout) if rca.is_none() => Ok(()),
750            result => result.map(|_| ()),
751        }
752    }
753
754    /// Get the ocr with the provided command
755    pub async fn get_ocr<'a, C: ControlCommand + 'a, Ext>(
756        &mut self,
757        cmd: &'a C,
758        app_cmd: bool,
759    ) -> Result<OCR<Ext>, MmcError>
760    where
761        OCR<Ext>: From<<C as Command>::Resp<'a>>,
762    {
763        // Wait up to 750ms + cmd time for ready after R1b response
764        // Note: this is a rather simplistic timeout loop. It can be improved later.
765        for _ in 0..750 {
766            let ocr: OCR<Ext> = self.send_command(cmd, app_cmd).await?.into();
767
768            if !ocr.is_busy() {
769                // Power up done
770                return Ok(ocr);
771            }
772
773            self.delay.delay_ms(1).await;
774        }
775
776        Err(MmcError::Timeout)
777    }
778
779    /// Send a command that has no data transfer (e.g., CMD0, CMD8, CMD55).
780    ///
781    /// Provide `Some(rca)` to execute this as an app cmd.
782    pub async fn send_command<'a, C: ControlCommand + 'a>(
783        &mut self,
784        cmd: C,
785        app_cmd: bool,
786    ) -> Result<C::Resp<'a>, MmcError> {
787        self.app_cmd(app_cmd).await?;
788        let res = self.bus.send_command(cmd).await?;
789        self.wait_if_required::<C::Resp<'a>>().await?;
790
791        Ok(res)
792    }
793
794    /// Read N blocks of fixed size (CMD17, CMD18).
795    ///
796    /// Provide `Some(rca)` to execute this as an app cmd.
797    ///
798    /// Do not call this method for CMD53. Instead, call the underlying bus method.
799    pub async fn read_blocks<'a, C: BlockReadCommand + 'a>(
800        &mut self,
801        cmd: C,
802        app_cmd: bool,
803    ) -> Result<C::Resp<'a>, MmcError> {
804        self.app_cmd(app_cmd).await?;
805        let res = self.bus.read_blocks(cmd).await?;
806        self.wait_if_required::<C::Resp<'a>>().await?;
807
808        Ok(res)
809    }
810
811    /// Write N blocks of fixed size (CMD24, CMD25).
812    ///
813    /// Provide `Some(rca)` to execute this as an app cmd.
814    ///
815    /// Do not call this method for CMD53. Instead, call the underlying bus method.
816    pub async fn write_blocks<'a, C: BlockWriteCommand + 'a>(
817        &mut self,
818        cmd: C,
819        app_cmd: bool,
820    ) -> Result<C::Resp<'a>, MmcError> {
821        self.app_cmd(app_cmd).await?;
822        let res = self.bus.write_blocks(cmd).await?;
823        self.wait_if_required::<C::Resp<'a>>().await?;
824
825        Ok(res)
826    }
827}
828
829/// The signalling scheme used on the SDMMC bus
830#[non_exhaustive]
831#[allow(missing_docs)]
832#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
833pub enum Signalling {
834    #[default]
835    SDR12,
836    SDR25,
837    SDR50,
838    SDR104,
839    DDR50,
840}
841
842/// Represents either an SD or EMMC card
843trait Acquirable: Sized + Clone + Default {
844    // Acquire a storage device from an initialized idle bus
845    fn acquire<B: MmcBus, D: DelayNs>(
846        bus: &mut BusAdapter<B, D>,
847        block_size: BlockSize,
848        bus_width: BusWidth,
849        freq: u32,
850    ) -> impl Future<Output = Result<Self, MmcError>>;
851}
852
853/// Represents either an SD or EMMC card
854#[allow(private_bounds)]
855pub trait Addressable: Acquirable {
856    /// Associated type
857    type Ext;
858
859    /// Is this a standard or high capacity peripheral?
860    fn get_capacity(&self) -> CardCapacity;
861
862    /// Number of blocks in this card
863    fn block_count(&self) -> u32;
864
865    /// Whether the device supports `CMD23 (SET_BLOCK_COUNT)`.
866    fn supports_cmd23(&self) -> bool;
867
868    /// Whether the device supports `ACMD23`.
869    fn supports_acmd23(&self) -> bool;
870}
871
872/// Represents a block storage device with a 512 byte block size
873pub type DefaultBlockDevice<T, B, D> = BlockDevice<T, B, D, 512>;
874
875/// Represents a block storage device
876pub struct BlockDevice<T: Addressable, B: MmcBus, D: DelayNs, const BLOCK_SIZE: usize> {
877    info: T,
878    bus: BusAdapter<B, D>,
879}
880
881/// Card or Emmc storage device
882impl<A: Addressable, B: MmcBus, D: DelayNs, const BLOCK_SIZE: usize>
883    BlockDevice<A, B, D, BLOCK_SIZE>
884{
885    /// Create a new block device
886    pub async fn new(bus: B, delay: D, freq: u32) -> Result<Self, MmcError> {
887        let mut this = Self::new_uninit(bus, delay);
888        this.reacquire(freq).await?;
889
890        Ok(this)
891    }
892
893    /// Create a new uninit block device
894    pub fn new_uninit(bus: B, delay: D) -> Self {
895        Self {
896            info: A::default(),
897            bus: BusAdapter { bus, delay, rca: 0 },
898        }
899    }
900
901    /// Reacquire the device
902    pub async fn reacquire(&mut self, freq: u32) -> Result<(), MmcError> {
903        // Clamp the frequency to the supported bus frequency.
904        let freq = freq.clamp(0, self.bus.bus.supports_frequency());
905        let bus_width = self.bus.bus.supports_bus_width();
906
907        self.bus.init_idle().await?;
908        self.info = A::acquire(&mut self.bus, block_size(BLOCK_SIZE), bus_width, freq).await?;
909
910        Ok(())
911    }
912
913    /// Get the card info
914    pub fn card(&self) -> A {
915        self.info.clone()
916    }
917
918    fn get_addr(&self, block_idx: u32) -> u32 {
919        // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes
920        match self.info.get_capacity() {
921            CardCapacity::StandardCapacity => block_idx * BLOCK_SIZE as u32,
922            _ => block_idx,
923        }
924    }
925
926    /// Read a data block.
927    #[inline]
928    async fn read_block(
929        &mut self,
930        block_idx: u32,
931        block: &mut Aligned<A4, [u8; BLOCK_SIZE]>,
932    ) -> Result<(), MmcError> {
933        self.bus
934            .read_blocks(read_single_block(self.get_addr(block_idx), block), false)
935            .await?
936            .to_result()?;
937
938        Ok(())
939    }
940
941    /// Read multiple data blocks.
942    #[inline]
943    async fn read_blocks(
944        &mut self,
945        block_idx: u32,
946        blocks: &mut [Aligned<A4, [u8; BLOCK_SIZE]>],
947    ) -> Result<(), MmcError> {
948        self.bus
949            .read_blocks(
950                read_multiple_blocks(self.get_addr(block_idx), blocks),
951                false,
952            )
953            .await?
954            .to_result()?;
955
956        self.bus.send_command(stop_transmission(), false).await?;
957
958        Ok(())
959    }
960
961    /// Write a data block.
962    #[inline]
963    async fn write_block(
964        &mut self,
965        block_idx: u32,
966        block: &Aligned<A4, [u8; BLOCK_SIZE]>,
967    ) -> Result<(), MmcError> {
968        self.bus
969            .write_blocks(write_single_block(self.get_addr(block_idx), block), false)
970            .await?
971            .to_response()
972            .to_result()?;
973
974        Ok(())
975    }
976
977    /// Write multiple data blocks.
978    #[inline]
979    async fn write_blocks(
980        &mut self,
981        block_idx: u32,
982        blocks: &[Aligned<A4, [u8; BLOCK_SIZE]>],
983    ) -> Result<(), MmcError> {
984        if self.info.supports_acmd23() {
985            self.bus
986                .send_command(sd::set_wr_blk_erase_count(blocks.len() as u32), true)
987                .await?
988                .to_result()?;
989        }
990
991        let supports_cmd23 = self.info.supports_cmd23();
992
993        if supports_cmd23 {
994            self.bus
995                .send_command(sd::set_block_count(blocks.len() as u32), false)
996                .await?
997                .to_result()?;
998        }
999
1000        self.bus
1001            .write_blocks(
1002                write_multiple_blocks(self.get_addr(block_idx), blocks),
1003                false,
1004            )
1005            .await?
1006            .to_response()
1007            .to_result()?;
1008
1009        if !supports_cmd23 {
1010            self.bus.send_command(stop_transmission(), false).await?;
1011        }
1012
1013        Ok(())
1014    }
1015}
1016
1017impl<A: Addressable, B: MmcBus, D: DelayNs, const BLOCK_SIZE: usize>
1018    block_device_driver::BlockDevice<BLOCK_SIZE> for BlockDevice<A, B, D, BLOCK_SIZE>
1019{
1020    type Align = A4;
1021    type Error = MmcError;
1022
1023    #[inline]
1024    async fn read(
1025        &mut self,
1026        block_address: u32,
1027        blocks: &mut [aligned::Aligned<Self::Align, [u8; BLOCK_SIZE]>],
1028    ) -> Result<(), Self::Error> {
1029        assert_eq!(BLOCK_SIZE % 4, 0);
1030
1031        // TODO: I think block_address needs to be adjusted by the partition start offset
1032        if blocks.len() == 1 {
1033            self.read_block(block_address, &mut blocks[0]).await?;
1034        } else {
1035            self.read_blocks(block_address, blocks).await?;
1036        }
1037        Ok(())
1038    }
1039
1040    #[inline]
1041    async fn write(
1042        &mut self,
1043        block_address: u32,
1044        blocks: &[aligned::Aligned<Self::Align, [u8; BLOCK_SIZE]>],
1045    ) -> Result<(), Self::Error> {
1046        assert_eq!(BLOCK_SIZE % 4, 0);
1047
1048        // TODO: I think block_address needs to be adjusted by the partition start offset
1049        if blocks.len() == 1 {
1050            self.write_block(block_address, &blocks[0]).await?;
1051        } else {
1052            self.write_blocks(block_address, blocks).await?;
1053        }
1054        Ok(())
1055    }
1056
1057    async fn size(&mut self) -> Result<u64, Self::Error> {
1058        Ok(self.info.block_count() as u64 * BLOCK_SIZE as u64)
1059    }
1060}