use core::{num::NonZeroU16, task::Waker};
pub use sdio_host2::{BusWidth, ClockSpeed, SignalVoltage};
use crate::{
block::{BlockRequestId, CommandResponsePoll, DataCommandPoll, OperationPoll},
cmd::Command,
error::Error,
};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub enum HostEventKind {
#[default]
None,
CommandComplete,
TransferComplete,
ReceiveReady,
TransmitReady,
Error,
Other,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub enum HostEventSource {
#[default]
Controller,
Command,
Data,
}
pub trait HostEvent {
fn kind(&self) -> HostEventKind;
fn source(&self) -> HostEventSource {
HostEventSource::Controller
}
fn queue_id(&self) -> Option<BlockRequestId> {
None
}
}
impl HostEvent for () {
fn kind(&self) -> HostEventKind {
HostEventKind::None
}
}
pub trait SdioIrqHandle: Send + 'static {
type Event: HostEvent + Default;
fn handle_irq(&mut self) -> Self::Event;
}
pub trait SdioIrqHost: SdioHost {
type IrqHandle: SdioIrqHandle<Event = Self::Event>;
fn irq_handle(&mut self) -> Self::IrqHandle;
}
pub const SDMMC_BLOCK_QUEUE_ID: usize = 0;
pub fn block_queue_ready_from_host_event(event: &impl HostEvent) -> Option<usize> {
match event.kind() {
HostEventKind::None => None,
_ => Some(SDMMC_BLOCK_QUEUE_ID),
}
}
pub trait SdioHost {
type Event: HostEvent + Default;
fn submit_command(&mut self, cmd: &Command) -> Result<(), Error>;
fn poll_command_response(&mut self) -> Result<CommandResponsePoll, Error>;
type DataRequest<'a>
where
Self: 'a;
fn submit_read_data<'a>(
&mut self,
cmd: &Command,
buf: &'a mut [u8],
block_size: u32,
block_count: u32,
) -> Result<Self::DataRequest<'a>, Error>;
fn submit_write_data<'a>(
&mut self,
cmd: &Command,
buf: &'a [u8],
block_size: u32,
block_count: u32,
) -> Result<Self::DataRequest<'a>, Error>;
fn poll_data_request<'a>(
&mut self,
request: &mut Self::DataRequest<'a>,
) -> Result<DataCommandPoll, Error>;
type BusRequest;
fn set_bus_width(&mut self, width: BusWidth) -> Result<(), Error>;
fn set_clock(&mut self, speed: ClockSpeed) -> Result<(), Error>;
fn switch_voltage(&mut self, _voltage: SignalVoltage) -> Result<(), Error> {
Err(Error::UnsupportedCommand)
}
fn execute_tuning(&mut self, _cmd_index: u8, _block_size: NonZeroU16) -> Result<(), Error> {
Err(Error::UnsupportedCommand)
}
fn submit_bus_op(&mut self, op: SdioBusOp) -> Result<Self::BusRequest, Error>;
fn poll_bus_op(&mut self, request: &mut Self::BusRequest) -> Result<OperationPoll<()>, Error>;
fn enable_completion_irq(&mut self) -> Result<(), Error> {
Ok(())
}
fn disable_completion_irq(&mut self) -> Result<(), Error> {
Ok(())
}
fn completion_irq_enabled(&self) -> bool {
false
}
fn register_waker(&mut self, _waker: &Waker) {}
fn now_ms(&self) -> Option<u64> {
None
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SdioBusOp {
ResetAll,
PowerOn,
PowerOff,
SetBusWidth(BusWidth),
SetClock(ClockSpeed),
SwitchVoltage(SignalVoltage),
ExecuteTuning {
cmd_index: u8,
block_size: NonZeroU16,
},
}
#[derive(Debug, Clone, Copy)]
pub struct ReadyBusRequest;
pub fn submit_ready_bus_op<H: SdioHost<BusRequest = ReadyBusRequest>>(
host: &mut H,
op: SdioBusOp,
) -> Result<ReadyBusRequest, Error> {
match op {
SdioBusOp::ResetAll | SdioBusOp::PowerOn | SdioBusOp::PowerOff => {}
SdioBusOp::SetBusWidth(width) => host.set_bus_width(width)?,
SdioBusOp::SetClock(speed) => host.set_clock(speed)?,
SdioBusOp::SwitchVoltage(voltage) => host.switch_voltage(voltage)?,
SdioBusOp::ExecuteTuning {
cmd_index,
block_size,
} => host.execute_tuning(cmd_index, block_size)?,
}
Ok(ReadyBusRequest)
}
pub fn poll_ready_bus_op(_request: &mut ReadyBusRequest) -> Result<OperationPoll<()>, Error> {
Ok(OperationPoll::Complete(()))
}