Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions axdriver_block/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ categories.workspace = true
ramdisk = []
bcm2835-sdhci = ["dep:bcm2835-sdhci"]
default = []
sdmmc = ["dep:simple-sdmmc"]

[dependencies]
axdriver_base = { workspace = true }
bcm2835-sdhci = { git = "https://github.com/lhw2002426/bcm2835-sdhci.git", rev = "e974f16", optional = true }
log = { workspace = true }
simple-sdmmc = { version = "0.1", optional = true }
3 changes: 3 additions & 0 deletions axdriver_block/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ pub mod ramdisk;
#[cfg(feature = "bcm2835-sdhci")]
pub mod bcm2835sdhci;

#[cfg(feature = "sdmmc")]
pub mod sdmmc;

#[doc(no_inline)]
pub use axdriver_base::{BaseDriverOps, DevError, DevResult, DeviceType};

Expand Down
88 changes: 88 additions & 0 deletions axdriver_block/src/sdmmc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//! SD/MMC driver based on SDIO.

use axdriver_base::{BaseDriverOps, DevError, DevResult, DeviceType};
use simple_sdmmc::SdMmc;

use crate::BlockDriverOps;

/// A SD/MMC driver.
pub struct SdMmcDriver(SdMmc);

impl SdMmcDriver {
/// Creates a new [`SdMmcDriver`] from the given base address.
///
/// # Safety
///
/// The caller must ensure that `base` is a valid pointer to the SD/MMC
/// controller's register block and that no other code is concurrently
/// accessing the same hardware.
pub unsafe fn new(base: usize) -> Self {
Self(unsafe { SdMmc::new(base) })
}
}

impl BaseDriverOps for SdMmcDriver {
fn device_type(&self) -> DeviceType {
DeviceType::Block
}

fn device_name(&self) -> &str {
"sdmmc"
}
}

impl BlockDriverOps for SdMmcDriver {
fn num_blocks(&self) -> u64 {
self.0.num_blocks()
}

fn block_size(&self) -> usize {
SdMmc::BLOCK_SIZE
}

fn read_block(&mut self, block_id: u64, buf: &mut [u8]) -> DevResult {
let (blocks, remainder) = buf.as_chunks_mut::<{ SdMmc::BLOCK_SIZE }>();

// the buf length must be a multiple of block size
if !remainder.is_empty() {
return Err(DevError::InvalidParam);
}

// check if block id exceeds device capacity
if block_id.saturating_add(blocks.len() as u64) > self.0.num_blocks() {
return Err(DevError::InvalidParam);
}

let block_id: u32 = block_id.try_into().map_err(|_| DevError::InvalidParam)?;
for (i, block) in blocks.iter_mut().enumerate() {
self.0.read_block(block_id + i as u32, block);
Comment thread
AsakuraMizu marked this conversation as resolved.
}
Comment thread
AsakuraMizu marked this conversation as resolved.

Ok(())
}

fn write_block(&mut self, block_id: u64, buf: &[u8]) -> DevResult {
let (blocks, remainder) = buf.as_chunks::<{ SdMmc::BLOCK_SIZE }>();

// the buf length must be a multiple of block size
if !remainder.is_empty() {
return Err(DevError::InvalidParam);
}

// check if block id exceeds device capacity
if block_id.saturating_add(blocks.len() as u64) > self.0.num_blocks() {
return Err(DevError::InvalidParam);
}

let block_id: u32 = block_id.try_into().map_err(|_| DevError::InvalidParam)?;
for (i, block) in blocks.iter().enumerate() {
self.0.write_block(block_id + i as u32, block);
}
Comment thread
AsakuraMizu marked this conversation as resolved.

Ok(())
}

fn flush(&mut self) -> DevResult {
Ok(())
}
}