1pub use sdio_host2::Command;
2
3use crate::response::ResponseType;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10#[non_exhaustive]
11pub enum DataDirection {
12 None,
14 Read,
16 Write,
18}
19
20impl DataDirection {
21 pub const fn is_none(self) -> bool {
23 matches!(self, DataDirection::None)
24 }
25}
26
27pub const CMD0: Command = Command::new(0, 0, ResponseType::None);
33
34pub const CMD2: Command = Command::new(2, 0, ResponseType::R2);
36
37pub const CMD3_SD: Command = Command::new(3, 0, ResponseType::R6);
39pub fn cmd3_mmc(rca: u16) -> Command {
41 Command::new(3, (rca as u32) << 16, ResponseType::R1)
42}
43
44pub fn cmd4(dsr: u16) -> Command {
46 Command::new(4, (dsr as u32) << 16, ResponseType::None)
47}
48
49pub fn cmd6(arg: u32) -> Command {
51 Command::new(6, arg, ResponseType::R1)
52}
53
54pub fn cmd6_high_speed(switch: bool) -> Command {
60 cmd6_sd_access_mode(switch, 1)
61}
62
63pub fn cmd6_sd_access_mode(switch: bool, function: u8) -> Command {
69 let mode = if switch { 1u32 << 31 } else { 0 };
70 let groups = 0x00FF_FFF0u32 | u32::from(function & 0xF);
72 Command::new(6, mode | groups, ResponseType::R1)
73}
74
75pub fn cmd7(rca: u16) -> Command {
77 Command::new(7, (rca as u32) << 16, ResponseType::R1b)
78}
79
80pub fn cmd8(voltage: u8, check_pattern: u8) -> Command {
82 let arg = ((voltage as u32) << 8) | check_pattern as u32;
83 Command::new(8, arg, ResponseType::R7)
84}
85
86pub fn cmd9(rca: u16) -> Command {
88 Command::new(9, (rca as u32) << 16, ResponseType::R2)
89}
90
91pub fn cmd10(rca: u16) -> Command {
93 Command::new(10, (rca as u32) << 16, ResponseType::R2)
94}
95
96pub const CMD11: Command = Command::new(11, 0, ResponseType::R1);
103
104pub const CMD12: Command = Command::new(12, 0, ResponseType::R1b);
106
107pub fn cmd13(rca: u16) -> Command {
109 Command::new(13, (rca as u32) << 16, ResponseType::R1)
110}
111
112pub fn cmd16(block_len: u32) -> Command {
114 Command::new(16, block_len, ResponseType::R1)
115}
116
117pub fn cmd17(addr: u32) -> Command {
119 Command::new(17, addr, ResponseType::R1)
120}
121
122pub fn cmd18(addr: u32) -> Command {
124 Command::new(18, addr, ResponseType::R1)
125}
126
127pub fn cmd24(addr: u32) -> Command {
129 Command::new(24, addr, ResponseType::R1)
130}
131
132pub fn cmd25(addr: u32) -> Command {
134 Command::new(25, addr, ResponseType::R1)
135}
136
137pub const CMD19: Command = Command::new(19, 0, ResponseType::R1);
144
145pub const CMD21: Command = Command::new(21, 0, ResponseType::R1);
152
153pub const SD_TUNING_BLOCK_SIZE: u32 = 64;
155pub const MMC_TUNING_BLOCK_SIZE_4BIT: u32 = 64;
157pub const MMC_TUNING_BLOCK_SIZE_8BIT: u32 = 128;
159
160pub fn cmd32(addr: u32) -> Command {
162 Command::new(32, addr, ResponseType::R1)
163}
164
165pub fn cmd33(addr: u32) -> Command {
167 Command::new(33, addr, ResponseType::R1)
168}
169
170pub const CMD38: Command = Command::new(38, 0, ResponseType::R1b);
172
173pub fn cmd41(hcs: bool, voltage_window: u32) -> Command {
175 cmd41_with_s18r(hcs, voltage_window, false)
176}
177
178pub fn cmd41_with_s18r(hcs: bool, voltage_window: u32, s18r: bool) -> Command {
180 let arg = if hcs { 0x4000_0000 } else { 0 }
181 | if s18r { 1 << 24 } else { 0 }
182 | (voltage_window & 0x00FF_F800);
183 Command::new(41, arg, ResponseType::R3)
184}
185
186pub fn cmd55(rca: u16) -> Command {
188 Command::new(55, (rca as u32) << 16, ResponseType::R1)
189}
190
191pub const CMD58: Command = Command::new(58, 0, ResponseType::R3);
193
194pub fn cmd1(voltage_window: u32) -> Command {
198 Command::new(1, voltage_window, ResponseType::R3)
199}
200
201pub fn cmd6_mmc_switch(access: u8, index: u8, value: u8) -> Command {
209 let arg = ((access as u32) << 24) | ((index as u32) << 16) | ((value as u32) << 8);
210 Command::new(6, arg, ResponseType::R1b)
211}
212
213pub const CMD8_MMC: Command = Command::new(8, 0, ResponseType::R1);
220
221pub mod ext_csd {
224 pub const DEVICE_TYPE: usize = 196;
226 pub const HS_TIMING: usize = 185;
230 pub const BUS_WIDTH: usize = 183;
233 pub const SEC_COUNT: usize = 212;
235
236 pub mod device_type {
237 pub const HS_26: u8 = 1 << 0;
239 pub const HS_52: u8 = 1 << 1;
241 pub const HS200_18V: u8 = 1 << 4;
243 pub const HS200_12V: u8 = 1 << 5;
245 }
246}
247
248pub const CMD5: Command = Command::new(5, 0, ResponseType::R4);
252
253pub fn cmd52(write: bool, function: u8, raw: bool, addr: u32, data: u8) -> Command {
257 let arg = (write as u32) << 31
258 | ((function as u32) & 0x7) << 28
259 | (raw as u32) << 27
260 | (addr & 0x1_FFFF) << 9
261 | (data as u32);
262 Command::new(52, arg, ResponseType::R5)
263}
264
265pub fn cmd53(
270 write: bool,
271 function: u8,
272 block_mode: bool,
273 addr: u32,
274 op_code: bool,
275 count: u16,
276) -> Command {
277 let arg = (write as u32) << 31
278 | ((function as u32) & 0x7) << 28
279 | (block_mode as u32) << 27
280 | (op_code as u32) << 26
281 | (addr & 0x1_FFFF) << 9
282 | (count as u32 & 0x1FF);
283 Command::new(53, arg, ResponseType::R5)
284}
285
286#[cfg(test)]
287mod tests {
288 use super::*;
289
290 #[test]
291 fn test_cmd0_crc() {
292 let bytes = CMD0.to_spi_bytes();
293 assert_eq!(bytes[0], 0x40);
295 assert_eq!(bytes[5], 0x95);
296 }
297
298 #[test]
299 fn test_cmd8_spi_bytes() {
300 let cmd = cmd8(0x01, 0xAA);
301 let bytes = cmd.to_spi_bytes();
302 assert_eq!(bytes[0], 0x48); assert_eq!(bytes[1], 0x00);
304 assert_eq!(bytes[2], 0x00);
305 assert_eq!(bytes[3], 0x01);
306 assert_eq!(bytes[4], 0xAA);
307 }
308
309 #[test]
310 fn cmd52_encodes_full_17_bit_address() {
311 let cmd = cmd52(true, 1, false, 0x1_ABCD, 0x55);
312 let expected = (1u32 << 31) | (1u32 << 28) | (0x1_ABCDu32 << 9) | 0x55;
314 assert_eq!(cmd.argument, expected);
315 assert_eq!(cmd.index, 52);
316 }
317
318 #[test]
319 fn cmd53_encodes_full_17_bit_address_and_count() {
320 let cmd = cmd53(false, 2, true, 0x1_FFFF, true, 0x1FF);
321 let expected = (2u32 << 28) | (1u32 << 27) | (1u32 << 26) | (0x1_FFFFu32 << 9) | 0x1FF;
323 assert_eq!(cmd.argument, expected);
324 assert_eq!(cmd.index, 53);
325 }
326
327 #[test]
328 fn data_direction_classifies_block_commands() {
329 assert_eq!(
330 cmd17(0).data_direction(),
331 Some(sdio_host2::DataDirection::Read)
332 );
333 assert_eq!(
334 cmd18(0).data_direction(),
335 Some(sdio_host2::DataDirection::Read)
336 );
337 assert_eq!(
338 cmd24(0).data_direction(),
339 Some(sdio_host2::DataDirection::Write)
340 );
341 assert_eq!(
342 cmd25(0).data_direction(),
343 Some(sdio_host2::DataDirection::Write)
344 );
345 assert_eq!(cmd6(0).data_direction(), None);
348 assert_eq!(CMD0.data_direction(), None);
349 assert_eq!(CMD12.data_direction(), None);
350 assert!(CMD0.data_direction().is_none());
351 }
352
353 #[test]
354 fn data_block_size_reports_known_lengths() {
355 assert_eq!(cmd17(0).data_block_size(), Some(512));
356 assert_eq!(cmd18(0).data_block_size(), Some(512));
357 assert_eq!(cmd24(0).data_block_size(), Some(512));
358 assert_eq!(cmd25(0).data_block_size(), Some(512));
359 assert_eq!(cmd6(0).data_block_size(), None);
360 assert_eq!(CMD0.data_block_size(), None);
361 assert_eq!(CMD12.data_block_size(), None);
362 }
363
364 #[test]
365 fn cmd6_high_speed_arg_matches_spec() {
366 let switch = cmd6_high_speed(true);
367 assert_eq!(switch.index, 6);
368 assert_eq!(switch.argument, 0x80FF_FFF1);
369 let check = cmd6_high_speed(false);
370 assert_eq!(check.argument, 0x00FF_FFF1);
371 }
372
373 #[test]
374 fn cmd6_sd_access_mode_arg_selects_group1_function() {
375 let sdr104 = cmd6_sd_access_mode(true, 3);
376 assert_eq!(sdr104.index, 6);
377 assert_eq!(sdr104.argument, 0x80FF_FFF3);
378
379 let ddr50 = cmd6_sd_access_mode(false, 4);
380 assert_eq!(ddr50.argument, 0x00FF_FFF4);
381 }
382
383 #[test]
384 fn cmd41_with_s18r_sets_1v8_request_bit() {
385 let cmd = cmd41_with_s18r(true, 0xFF8000, true);
386 assert_eq!(cmd.argument, 0x4100_0000 | 0x00FF_8000);
387 }
388
389 #[test]
390 fn with_resp_type_overrides_only_resp_type() {
391 let original = cmd41(true, 0xFF8000);
392 let overridden = original.with_resp_type(ResponseType::R1);
393 assert_eq!(overridden.index, original.index);
394 assert_eq!(overridden.argument, original.argument);
395 assert_eq!(overridden.response, ResponseType::R1);
396 assert_eq!(original.response, ResponseType::R3);
397 }
398}