1#![no_std]
10
11extern crate alloc;
12
13use alloc::boxed::Box;
14use core::{
15 fmt,
16 num::{NonZeroU16, NonZeroU32},
17};
18
19use dma_api::{CompletedDma, DmaDirection, PreparedDma};
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub struct Command {
24 pub index: u8,
25 pub argument: u32,
26 pub response: ResponseType,
27}
28
29impl Command {
30 pub const fn new(index: u8, argument: u32, response: ResponseType) -> Self {
31 Self {
32 index,
33 argument,
34 response,
35 }
36 }
37
38 pub const fn index(self) -> u8 {
39 self.index
40 }
41
42 pub const fn argument(self) -> u32 {
43 self.argument
44 }
45
46 pub const fn with_response(self, response: ResponseType) -> Self {
47 Self { response, ..self }
48 }
49
50 pub const fn with_resp_type(self, response: ResponseType) -> Self {
54 self.with_response(response)
55 }
56
57 pub const fn cmd(self) -> u8 {
59 self.index
60 }
61
62 pub const fn arg(self) -> u32 {
64 self.argument
65 }
66
67 pub const fn data_direction(&self) -> Option<DataDirection> {
73 match self.index {
74 17 | 18 => Some(DataDirection::Read),
75 24 | 25 => Some(DataDirection::Write),
76 _ => None,
77 }
78 }
79
80 pub const fn data_block_size(&self) -> Option<u32> {
82 match self.index {
83 17 | 18 | 24 | 25 => Some(512),
84 _ => None,
85 }
86 }
87
88 pub fn crc7(&self) -> u8 {
90 let mut crc: u8 = 0;
91 let token: u8 = 0x40 | (self.index & 0x3F);
92 crc = crc7_update(crc, token);
93 for byte in self.argument.to_be_bytes() {
94 crc = crc7_update(crc, byte);
95 }
96 (crc << 1) | 1
97 }
98
99 pub fn to_spi_bytes(&self) -> [u8; 6] {
101 let crc = self.crc7();
102 let token = 0x40 | (self.index & 0x3F);
103 let arg = self.argument.to_be_bytes();
104 [token, arg[0], arg[1], arg[2], arg[3], crc]
105 }
106}
107
108fn crc7_update(crc: u8, byte: u8) -> u8 {
109 let mut crc = crc;
110 let mut data = byte;
111 for _ in 0..8 {
112 crc <<= 1;
113 if (crc ^ data) & 0x80 != 0 {
114 crc ^= 0x89;
115 }
116 data <<= 1;
117 }
118 crc
119}
120
121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123#[non_exhaustive]
124pub enum ResponseType {
125 None,
126 R1,
127 R1b,
128 R2,
129 R3,
130 R4,
131 R5,
132 R6,
133 R7,
134}
135
136#[derive(Debug, Clone, Copy, PartialEq, Eq)]
145pub struct RawResponse {
146 pub ty: ResponseType,
147 pub words: [u32; 4],
148}
149
150impl RawResponse {
151 pub const fn new(ty: ResponseType, words: [u32; 4]) -> Self {
152 Self { ty, words }
153 }
154
155 pub const fn empty() -> Self {
156 Self {
157 ty: ResponseType::None,
158 words: [0; 4],
159 }
160 }
161}
162
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
165#[non_exhaustive]
166pub enum DataDirection {
167 Read,
168 Write,
169}
170
171pub enum DataBuffer<'a> {
173 Read(&'a mut [u8]),
174 Write(&'a [u8]),
175 Dma(PreparedDma),
176}
177
178impl DataBuffer<'_> {
179 pub fn len(&self) -> usize {
180 match self {
181 Self::Read(buf) => buf.len(),
182 Self::Write(buf) => buf.len(),
183 Self::Dma(buffer) => buffer.len().get(),
184 }
185 }
186
187 pub fn is_empty(&self) -> bool {
188 self.len() == 0
189 }
190
191 pub fn matches_direction(&self, direction: DataDirection) -> bool {
192 match self {
193 Self::Read(_) => direction == DataDirection::Read,
194 Self::Write(_) => direction == DataDirection::Write,
195 Self::Dma(buffer) => matches!(
196 (buffer.direction(), direction),
197 (DmaDirection::FromDevice, DataDirection::Read)
198 | (DmaDirection::ToDevice, DataDirection::Write)
199 | (DmaDirection::Bidirectional, _)
200 ),
201 }
202 }
203}
204
205pub type DataTransfer<'a> = DataBuffer<'a>;
206
207pub struct DmaPhaseError {
209 error: Error,
210 buffer: Box<PreparedDma>,
211}
212
213impl DmaPhaseError {
214 fn new(error: Error, buffer: PreparedDma) -> Self {
215 Self {
216 error,
217 buffer: Box::new(buffer),
218 }
219 }
220
221 pub const fn error(&self) -> Error {
222 self.error
223 }
224
225 pub fn into_buffer(self) -> PreparedDma {
226 *self.buffer
227 }
228
229 pub fn into_parts(self) -> (Error, PreparedDma) {
230 (self.error, *self.buffer)
231 }
232}
233
234impl fmt::Debug for DmaPhaseError {
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236 f.debug_struct("DmaPhaseError")
237 .field("error", &self.error)
238 .finish_non_exhaustive()
239 }
240}
241
242impl fmt::Display for DmaPhaseError {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 self.error.fmt(f)
245 }
246}
247
248impl core::error::Error for DmaPhaseError {}
249
250pub struct DataPhase<'a> {
252 pub direction: DataDirection,
253 pub block_size: NonZeroU16,
254 pub block_count: NonZeroU32,
255 pub buffer: DataBuffer<'a>,
256}
257
258impl<'a> DataPhase<'a> {
259 pub fn read(
260 block_size: NonZeroU16,
261 block_count: NonZeroU32,
262 buffer: &'a mut [u8],
263 ) -> Result<Self, Error> {
264 let phase = Self {
265 direction: DataDirection::Read,
266 block_size,
267 block_count,
268 buffer: DataBuffer::Read(buffer),
269 };
270 phase.validate()?;
271 Ok(phase)
272 }
273
274 pub fn write(
275 block_size: NonZeroU16,
276 block_count: NonZeroU32,
277 buffer: &'a [u8],
278 ) -> Result<Self, Error> {
279 let phase = Self {
280 direction: DataDirection::Write,
281 block_size,
282 block_count,
283 buffer: DataBuffer::Write(buffer),
284 };
285 phase.validate()?;
286 Ok(phase)
287 }
288
289 pub fn dma(
290 direction: DataDirection,
291 block_size: NonZeroU16,
292 block_count: NonZeroU32,
293 buffer: PreparedDma,
294 ) -> Result<Self, DmaPhaseError> {
295 let phase = Self {
296 direction,
297 block_size,
298 block_count,
299 buffer: DataBuffer::Dma(buffer),
300 };
301 match phase.validate() {
302 Ok(()) => Ok(phase),
303 Err(err) => {
304 let DataBuffer::Dma(buffer) = phase.buffer else {
305 unreachable!("DataPhase::dma always stores a DMA buffer")
306 };
307 Err(DmaPhaseError::new(err, buffer))
308 }
309 }
310 }
311
312 pub fn validate(&self) -> Result<(), Error> {
313 let expected = usize::from(self.block_size.get())
314 .checked_mul(
315 usize::try_from(self.block_count.get()).map_err(|_| Error::InvalidArgument)?,
316 )
317 .ok_or(Error::InvalidArgument)?;
318 if self.buffer.len() != expected {
319 return Err(Error::InvalidArgument);
320 }
321 if !self.buffer.matches_direction(self.direction) {
322 return Err(Error::InvalidArgument);
323 }
324 Ok(())
325 }
326}
327
328pub struct Transaction<'a> {
330 pub command: Command,
331 pub data: Option<DataPhase<'a>>,
332}
333
334impl<'a> Transaction<'a> {
335 pub const fn command(command: Command) -> Self {
336 Self {
337 command,
338 data: None,
339 }
340 }
341
342 pub const fn with_data(command: Command, data: DataPhase<'a>) -> Self {
343 Self {
344 command,
345 data: Some(data),
346 }
347 }
348}
349
350pub struct SubmitTransactionError<'a> {
356 pub error: Error,
357 transaction: Option<Box<Transaction<'a>>>,
358}
359
360impl<'a> SubmitTransactionError<'a> {
361 pub fn new(error: Error, transaction: Transaction<'a>) -> Self {
362 Self {
363 error,
364 transaction: Some(Box::new(transaction)),
365 }
366 }
367
368 pub const fn consumed(error: Error) -> Self {
369 Self {
370 error,
371 transaction: None,
372 }
373 }
374
375 pub fn into_transaction(self) -> Option<Transaction<'a>> {
376 self.transaction.map(|transaction| *transaction)
377 }
378}
379
380#[derive(Debug, Clone, Copy, PartialEq, Eq)]
382pub enum RequestPoll<T> {
383 Pending,
384 Ready(Result<T, Error>),
385}
386
387#[derive(Debug, Clone, Copy, PartialEq, Eq)]
395#[non_exhaustive]
396pub enum PollRequestError {
397 WrongOwner,
398 WrongKind,
399 AlreadyCompleted,
400 StaleGeneration,
401 RecoveryFailed,
407}
408
409#[derive(Debug, Clone, Copy, PartialEq, Eq)]
411#[non_exhaustive]
412pub enum BusWidth {
413 Bit1,
414 Bit4,
415 Bit8,
416}
417
418#[derive(Debug, Clone, Copy, PartialEq, Eq)]
420#[non_exhaustive]
421pub enum ClockSpeed {
422 Identification,
423 Default,
424 HighSpeed,
425 Sdr12,
426 Sdr25,
427 Sdr50,
428 Sdr104,
429 Ddr50,
430 Hs200,
431}
432
433#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
435pub struct ClockHz(pub u32);
436
437#[derive(Debug, Clone, Copy, PartialEq, Eq)]
439#[non_exhaustive]
440pub enum SignalVoltage {
441 V330,
442 V180,
443 V120,
444}
445
446#[derive(Debug, Clone, Copy, PartialEq, Eq)]
448#[non_exhaustive]
449pub enum BusOp {
450 ResetAll,
451 ResetCommandLine,
452 ResetDataLine,
453 PowerOn,
454 PowerOff,
455 SetClock(ClockSpeed),
456 SetClockHz(ClockHz),
457 SetBusWidth(BusWidth),
458 SetSignalVoltage(SignalVoltage),
459 ExecuteTuning {
460 command: Command,
461 block_size: NonZeroU16,
462 },
463}
464
465#[derive(Debug, Clone, Copy, PartialEq, Eq)]
467#[non_exhaustive]
468pub enum Error {
469 Busy,
470 Timeout,
471 Crc,
472 NoCard,
473 Unsupported,
474 InvalidArgument,
475 Misaligned,
476 Bus,
477 Controller,
478}
479
480impl fmt::Display for Error {
481 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
482 let s = match self {
483 Self::Busy => "host bus is busy",
484 Self::Timeout => "host bus timeout",
485 Self::Crc => "host bus CRC error",
486 Self::NoCard => "no card present",
487 Self::Unsupported => "operation is not supported",
488 Self::InvalidArgument => "invalid host bus argument",
489 Self::Misaligned => "misaligned host bus buffer",
490 Self::Bus => "host bus error",
491 Self::Controller => "host controller error",
492 };
493 f.write_str(s)
494 }
495}
496
497impl core::error::Error for Error {}
498
499impl fmt::Display for PollRequestError {
500 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
501 let s = match self {
502 Self::WrongOwner => "request belongs to a different host",
503 Self::WrongKind => "request was polled through the wrong operation kind",
504 Self::AlreadyCompleted => "request has already completed",
505 Self::StaleGeneration => "request generation is no longer active",
506 Self::RecoveryFailed => "request recovery failed",
507 };
508 f.write_str(s)
509 }
510}
511
512impl core::error::Error for PollRequestError {}
513
514pub trait SdioHost {
519 type TransactionRequest<'a>
520 where
521 Self: 'a;
522 type BusRequest;
523
524 unsafe fn submit_transaction<'a>(
533 &mut self,
534 transaction: Transaction<'a>,
535 ) -> Result<Self::TransactionRequest<'a>, Error>
536 where
537 Self: 'a;
538
539 unsafe fn submit_transaction_owned<'a>(
549 &mut self,
550 transaction: Transaction<'a>,
551 ) -> Result<Self::TransactionRequest<'a>, SubmitTransactionError<'a>>
552 where
553 Self: 'a,
554 {
555 match unsafe { self.submit_transaction(transaction) } {
556 Ok(request) => Ok(request),
557 Err(error) => Err(SubmitTransactionError::consumed(error)),
558 }
559 }
560
561 fn poll_transaction<'a>(
562 &mut self,
563 request: &mut Self::TransactionRequest<'a>,
564 ) -> Result<RequestPoll<RawResponse>, PollRequestError>
565 where
566 Self: 'a;
567
568 fn abort_transaction<'a>(
576 &mut self,
577 request: &mut Self::TransactionRequest<'a>,
578 ) -> Result<(), Error>
579 where
580 Self: 'a;
581
582 fn take_completed_dma<'a>(
583 &mut self,
584 _request: &mut Self::TransactionRequest<'a>,
585 ) -> Option<CompletedDma>
586 where
587 Self: 'a,
588 {
589 None
590 }
591
592 unsafe fn submit_bus_op(&mut self, op: BusOp) -> Result<Self::BusRequest, Error>;
599
600 fn poll_bus_op(
601 &mut self,
602 request: &mut Self::BusRequest,
603 ) -> Result<RequestPoll<()>, PollRequestError>;
604
605 fn abort_bus_op(&mut self, request: &mut Self::BusRequest) -> Result<(), Error>;
611
612 fn now_ms(&self) -> Option<u64> {
613 None
614 }
615}
616
617#[cfg(test)]
618mod tests {
619 use super::*;
620
621 struct MockHost {
622 busy: bool,
623 }
624
625 #[derive(Debug)]
626 struct MockTransactionRequest {
627 response: RawResponse,
628 pending_once: bool,
629 done: bool,
630 }
631
632 #[derive(Debug)]
633 struct MockBusRequest {
634 pending_once: bool,
635 done: bool,
636 }
637
638 impl SdioHost for MockHost {
639 type TransactionRequest<'a>
640 = MockTransactionRequest
641 where
642 Self: 'a;
643 type BusRequest = MockBusRequest;
644
645 unsafe fn submit_transaction<'a>(
646 &mut self,
647 transaction: Transaction<'a>,
648 ) -> Result<Self::TransactionRequest<'a>, Error>
649 where
650 Self: 'a,
651 {
652 if self.busy {
653 return Err(Error::Busy);
654 }
655 self.busy = true;
656 Ok(MockTransactionRequest {
657 response: RawResponse::new(transaction.command.response, [0x1234, 0, 0, 0]),
658 pending_once: true,
659 done: false,
660 })
661 }
662
663 fn poll_transaction<'a>(
664 &mut self,
665 request: &mut Self::TransactionRequest<'a>,
666 ) -> Result<RequestPoll<RawResponse>, PollRequestError>
667 where
668 Self: 'a,
669 {
670 if request.done {
671 return Err(PollRequestError::AlreadyCompleted);
672 }
673 if request.pending_once {
674 request.pending_once = false;
675 return Ok(RequestPoll::Pending);
676 }
677 self.busy = false;
678 request.done = true;
679 Ok(RequestPoll::Ready(Ok(request.response)))
680 }
681
682 fn abort_transaction<'a>(
683 &mut self,
684 request: &mut Self::TransactionRequest<'a>,
685 ) -> Result<(), Error>
686 where
687 Self: 'a,
688 {
689 request.done = true;
690 self.busy = false;
691 Ok(())
692 }
693
694 unsafe fn submit_bus_op(&mut self, _op: BusOp) -> Result<Self::BusRequest, Error> {
695 if self.busy {
696 return Err(Error::Busy);
697 }
698 self.busy = true;
699 Ok(MockBusRequest {
700 pending_once: false,
701 done: false,
702 })
703 }
704
705 fn poll_bus_op(
706 &mut self,
707 request: &mut Self::BusRequest,
708 ) -> Result<RequestPoll<()>, PollRequestError> {
709 if request.done {
710 return Err(PollRequestError::AlreadyCompleted);
711 }
712 if request.pending_once {
713 request.pending_once = false;
714 return Ok(RequestPoll::Pending);
715 }
716 self.busy = false;
717 request.done = true;
718 Ok(RequestPoll::Ready(Ok(())))
719 }
720
721 fn abort_bus_op(&mut self, request: &mut Self::BusRequest) -> Result<(), Error> {
722 request.done = true;
723 self.busy = false;
724 Ok(())
725 }
726 }
727
728 #[test]
729 fn data_phase_validates_buffer_shape() {
730 let mut read = [0u8; 1024];
731 let block = NonZeroU16::new(512).unwrap();
732 let phase = DataPhase::read(block, NonZeroU32::new(2).unwrap(), &mut read).unwrap();
733 assert_eq!(phase.direction, DataDirection::Read);
734 assert_eq!(phase.buffer.len(), 1024);
735 }
736
737 #[test]
738 fn host_reports_busy_for_second_active_transaction() {
739 let mut host = MockHost { busy: false };
740 let cmd = Command::new(17, 0, ResponseType::R1);
741 let mut request = unsafe { host.submit_transaction(Transaction::command(cmd)) }.unwrap();
742 assert_eq!(
743 unsafe { host.submit_transaction(Transaction::command(cmd)) }.unwrap_err(),
744 Error::Busy
745 );
746 assert_eq!(
747 host.poll_transaction(&mut request),
748 Ok(RequestPoll::Pending)
749 );
750 assert!(matches!(
751 host.poll_transaction(&mut request),
752 Ok(RequestPoll::Ready(Ok(_)))
753 ));
754 assert_eq!(
755 host.poll_transaction(&mut request),
756 Err(PollRequestError::AlreadyCompleted)
757 );
758 assert!(unsafe { host.submit_transaction(Transaction::command(cmd)) }.is_ok());
759 }
760
761 #[test]
762 fn bus_op_uses_same_single_active_contract() {
763 let mut host = MockHost { busy: false };
764 let _request = unsafe { host.submit_bus_op(BusOp::SetClock(ClockSpeed::Default)) }.unwrap();
765 assert_eq!(
766 unsafe { host.submit_bus_op(BusOp::SetBusWidth(BusWidth::Bit4)) }.unwrap_err(),
767 Error::Busy
768 );
769 }
770
771 #[test]
772 fn abort_releases_single_active_contract() {
773 let mut host = MockHost { busy: false };
774 let cmd = Command::new(17, 0, ResponseType::R1);
775 let mut request = unsafe { host.submit_transaction(Transaction::command(cmd)) }.unwrap();
776
777 host.abort_transaction(&mut request).unwrap();
778
779 assert!(unsafe { host.submit_transaction(Transaction::command(cmd)) }.is_ok());
780 assert_eq!(
781 host.poll_transaction(&mut request),
782 Err(PollRequestError::AlreadyCompleted)
783 );
784 }
785}