1//! embedded-sdmmc-rs - Block Device support
2//!
3//! Generic code for handling block devices.
45/// Represents a standard 512 byte block (also known as a sector). IBM PC
6/// formatted 5.25" and 3.5" floppy disks, SD/MMC cards up to 1 GiB in size
7/// and IDE/SATA Hard Drives up to about 2 TiB all have 512 byte blocks.
8///
9/// This library does not support devices with a block size other than 512
10/// bytes.
11#[derive(Clone)]
12pub struct Block {
13/// The 512 bytes in this block (or sector).
14pub contents: [u8; Block::LEN],
15}
1617/// Represents the linear numeric address of a block (or sector). The first
18/// block on a disk gets `BlockIdx(0)` (which usually contains the Master Boot
19/// Record).
20#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
21pub struct BlockIdx(pub u32);
2223/// Represents the a number of blocks (or sectors). Add this to a `BlockIdx`
24/// to get an actual address on disk.
25#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
26pub struct BlockCount(pub u32);
2728/// An iterator returned from `Block::range`.
29pub struct BlockIter {
30 inclusive_end: BlockIdx,
31 current: BlockIdx,
32}
3334/// Represents a block device - a device which can read and write blocks (or
35/// sectors). Only supports devices which are <= 2 TiB in size.
36pub trait BlockDevice {
37/// The errors that the `BlockDevice` can return. Must be debug formattable.
38type Error: core::fmt::Debug;
39/// Read one or more blocks, starting at the given block index.
40fn read(
41&self,
42 blocks: &mut [Block],
43 start_block_idx: BlockIdx,
44 reason: &str,
45 ) -> Result<(), Self::Error>;
46/// Write one or more blocks, starting at the given block index.
47fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
48/// Determine how many blocks this device can hold.
49fn num_blocks(&self) -> Result<BlockCount, Self::Error>;
50}
5152impl Block {
53/// All our blocks are a fixed length of 512 bytes. We do not support
54 /// 'Advanced Format' Hard Drives with 4 KiB blocks, nor weird old
55 /// pre-3.5-inch floppy disk formats.
56pub const LEN: usize = 512;
5758/// Sometimes we want `LEN` as a `u32` and the casts don't look nice.
59pub const LEN_U32: u32 = 512;
6061/// Create a new block full of zeros.
62pub fn new() -> Block {
63 Block {
64 contents: [0u8; Self::LEN],
65 }
66 }
67}
6869impl Default for Block {
70fn default() -> Self {
71Self::new()
72 }
73}
7475impl core::ops::Add<BlockCount> for BlockIdx {
76type Output = BlockIdx;
77fn add(self, rhs: BlockCount) -> BlockIdx {
78 BlockIdx(self.0 + rhs.0)
79 }
80}
8182impl core::ops::AddAssign<BlockCount> for BlockIdx {
83fn add_assign(&mut self, rhs: BlockCount) {
84self.0 += rhs.0
85}
86}
8788impl core::ops::Add<BlockCount> for BlockCount {
89type Output = BlockCount;
90fn add(self, rhs: BlockCount) -> BlockCount {
91 BlockCount(self.0 + rhs.0)
92 }
93}
9495impl core::ops::AddAssign<BlockCount> for BlockCount {
96fn add_assign(&mut self, rhs: BlockCount) {
97self.0 += rhs.0
98}
99}
100101impl core::ops::Sub<BlockCount> for BlockIdx {
102type Output = BlockIdx;
103fn sub(self, rhs: BlockCount) -> BlockIdx {
104 BlockIdx(self.0 - rhs.0)
105 }
106}
107108impl core::ops::SubAssign<BlockCount> for BlockIdx {
109fn sub_assign(&mut self, rhs: BlockCount) {
110self.0 -= rhs.0
111}
112}
113114impl core::ops::Sub<BlockCount> for BlockCount {
115type Output = BlockCount;
116fn sub(self, rhs: BlockCount) -> BlockCount {
117 BlockCount(self.0 - rhs.0)
118 }
119}
120121impl core::ops::SubAssign<BlockCount> for BlockCount {
122fn sub_assign(&mut self, rhs: BlockCount) {
123self.0 -= rhs.0
124}
125}
126127impl core::ops::Deref for Block {
128type Target = [u8; 512];
129fn deref(&self) -> &[u8; 512] {
130&self.contents
131 }
132}
133134impl core::ops::DerefMut for Block {
135fn deref_mut(&mut self) -> &mut [u8; 512] {
136&mut self.contents
137 }
138}
139140impl core::fmt::Debug for Block {
141fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
142writeln!(fmt, "Block:")?;
143for line in self.contents.chunks(32) {
144for b in line {
145write!(fmt, "{:02x}", b)?;
146 }
147write!(fmt, " ")?;
148for &b in line {
149if b >= 0x20 && b <= 0x7F {
150write!(fmt, "{}", b as char)?;
151 } else {
152write!(fmt, ".")?;
153 }
154 }
155writeln!(fmt)?;
156 }
157Ok(())
158 }
159}
160161impl BlockIdx {
162/// Convert a block index into a 64-bit byte offset from the start of the
163 /// volume. Useful if your underlying block device actually works in
164 /// bytes, like `open("/dev/mmcblk0")` does on Linux.
165pub fn into_bytes(self) -> u64 {
166 (u64::from(self.0)) * (Block::LEN as u64)
167 }
168169/// Create an iterator from the current `BlockIdx` through the given
170 /// number of blocks.
171pub fn range(self, num: BlockCount) -> BlockIter {
172 BlockIter::new(self, self + BlockCount(num.0))
173 }
174}
175176impl BlockCount {
177/// Take a number of blocks and increment by the integer number of blocks
178 /// required to get to the block that holds the byte at the given offset.
179pub fn offset_bytes(self, offset: u32) -> Self {
180 BlockCount(self.0 + (offset / Block::LEN_U32))
181 }
182}
183184impl BlockIter {
185/// Create a new `BlockIter`, from the given start block, through (and
186 /// including) the given end block.
187pub fn new(start: BlockIdx, inclusive_end: BlockIdx) -> BlockIter {
188 BlockIter {
189 inclusive_end,
190 current: start,
191 }
192 }
193}
194195impl core::iter::Iterator for BlockIter {
196type Item = BlockIdx;
197fn next(&mut self) -> Option<Self::Item> {
198if self.current.0 >= self.inclusive_end.0 {
199None
200} else {
201let this = self.current;
202self.current += BlockCount(1);
203Some(this)
204 }
205 }
206}
207208// ****************************************************************************
209//
210// End Of File
211//
212// ****************************************************************************