issue #1986 separate blocks to prevent unsafe user code

This commit is contained in:
Tyler Gilbert 2023-09-30 22:48:49 -05:00
parent d42cfda2db
commit 5dd9e9b3b7

View File

@ -502,7 +502,7 @@ impl Config {
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum SubBlock { enum WhichSubBlock {
A = 0, A = 0,
B = 1, B = 1,
} }
@ -513,28 +513,30 @@ enum RingBuffer<'d, C: Channel, W: word::Word> {
} }
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
fn wdr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: SubBlock) -> *mut W { fn dr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut W {
let ch = w.ch(sub_block as usize); let ch = w.ch(sub_block as usize);
ch.dr().as_ptr() as _ ch.dr().as_ptr() as _
} }
#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] pub struct SubBlock<'d, T: Instance, C: Channel, W: word::Word> {
fn rdr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: SubBlock) -> *mut W {
let ch = w.ch(sub_block as usize);
ch.dr().as_ptr() as _
}
pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> {
_peri: PeripheralRef<'d, T>, _peri: PeripheralRef<'d, T>,
sd: Option<PeripheralRef<'d, AnyPin>>, sd: Option<PeripheralRef<'d, AnyPin>>,
fs: Option<PeripheralRef<'d, AnyPin>>, fs: Option<PeripheralRef<'d, AnyPin>>,
sck: Option<PeripheralRef<'d, AnyPin>>, sck: Option<PeripheralRef<'d, AnyPin>>,
mclk: Option<PeripheralRef<'d, AnyPin>>, mclk: Option<PeripheralRef<'d, AnyPin>>,
ring_buffer: RingBuffer<'d, C, W>, ring_buffer: RingBuffer<'d, C, W>,
sub_block: SubBlock, sub_block: WhichSubBlock,
}
pub struct SubBlockA {}
pub struct SubBlockB {}
pub struct Sai<'d, T: Instance> {
_peri: PeripheralRef<'d, T>,
sub_block_a_peri: Option<PeripheralRef<'d, T>>,
sub_block_b_peri: Option<PeripheralRef<'d, T>>,
} }
impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
// return the type for (sd, sck) // return the type for (sd, sck)
fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) { fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) {
( (
@ -551,11 +553,11 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
) )
} }
fn get_ring_buffer( fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>(
dma: impl Peripheral<P = C> + 'd, dma: impl Peripheral<P = C> + 'd,
dma_buf: &'d mut [W], dma_buf: &'d mut [W],
request: Request, request: Request,
sub_block: SubBlock, sub_block: WhichSubBlock,
tx_rx: TxRx, tx_rx: TxRx,
) -> RingBuffer<'d, C, W> { ) -> RingBuffer<'d, C, W> {
let opts = TransferOptions { let opts = TransferOptions {
@ -565,143 +567,41 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
}; };
match tx_rx { match tx_rx {
TxRx::Transmitter => RingBuffer::Writable(unsafe { TxRx::Transmitter => RingBuffer::Writable(unsafe {
WritableRingBuffer::new_write(dma, request, wdr(T::REGS, sub_block), dma_buf, opts) WritableRingBuffer::new_write(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
}), }),
TxRx::Receiver => RingBuffer::Readable(unsafe { TxRx::Receiver => RingBuffer::Readable(unsafe {
ReadableRingBuffer::new_read(dma, request, rdr(T::REGS, sub_block), dma_buf, opts) ReadableRingBuffer::new_read(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
}), }),
} }
} }
pub fn new_asynchronous_block_a_with_mclk( impl<'d, T: Instance> Sai<'d, T> {
peri: impl Peripheral<P = T> + 'd, pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self {
sck: impl Peripheral<P = impl SckAPin<T>> + 'd, T::enable();
sd: impl Peripheral<P = impl SdAPin<T>> + 'd, T::reset();
fs: impl Peripheral<P = impl FsAPin<T>> + 'd,
mclk: impl Peripheral<P = impl MclkAPin<T>> + 'd,
dma: impl Peripheral<P = C> + 'd,
dma_buf: &'d mut [W],
mut config: Config,
) -> Self
where
C: Channel + DmaA<T>,
{
into_ref!(mclk);
let (_sd_af_type, ck_af_type) = Self::get_af_types(config.mode, config.tx_rx); Self {
_peri: unsafe { peri.clone_unchecked().into_ref() },
mclk.set_as_af(mclk.af_num(), ck_af_type); sub_block_a_peri: Some(unsafe { peri.clone_unchecked().into_ref() }),
mclk.set_speed(crate::gpio::Speed::VeryHigh); sub_block_b_peri: Some(peri.into_ref()),
}
if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
config.master_clock_divider = MasterClockDivider::Div1;
} }
Self::new_asynchronous_block_a(peri, sck, sd, fs, dma, dma_buf, config) pub fn take_sub_block_a(self: &mut Self) -> Option<PeripheralRef<'d, T>> {
if self.sub_block_a_peri.is_some() {
self.sub_block_a_peri.take()
} else {
None
}
} }
pub fn new_asynchronous_block_a( pub fn take_sub_block_b(self: &mut Self) -> Option<PeripheralRef<'d, T>> {
peri: impl Peripheral<P = T> + 'd, if self.sub_block_b_peri.is_some() {
sck: impl Peripheral<P = impl SckAPin<T>> + 'd, self.sub_block_b_peri.take()
sd: impl Peripheral<P = impl SdAPin<T>> + 'd, } else {
fs: impl Peripheral<P = impl FsAPin<T>> + 'd, None
dma: impl Peripheral<P = C> + 'd,
dma_buf: &'d mut [W],
config: Config,
) -> Self
where
C: Channel + DmaA<T>,
{
into_ref!(peri, dma, sck, sd, fs);
let (sd_af_type, ck_af_type) = Self::get_af_types(config.mode, config.tx_rx);
sd.set_as_af(sd.af_num(), sd_af_type);
sd.set_speed(crate::gpio::Speed::VeryHigh);
sck.set_as_af(sck.af_num(), ck_af_type);
sck.set_speed(crate::gpio::Speed::VeryHigh);
fs.set_as_af(fs.af_num(), ck_af_type);
fs.set_speed(crate::gpio::Speed::VeryHigh);
let sub_block = SubBlock::A;
let request = dma.request();
Self::new_inner(
peri,
sub_block,
Some(sck.map_into()),
None,
Some(sd.map_into()),
Some(fs.map_into()),
Self::get_ring_buffer(dma, dma_buf, request, sub_block, config.tx_rx),
config,
)
} }
pub fn new_asynchronous_block_b_with_mclk(
peri: impl Peripheral<P = T> + 'd,
sck: impl Peripheral<P = impl SckBPin<T>> + 'd,
sd: impl Peripheral<P = impl SdBPin<T>> + 'd,
fs: impl Peripheral<P = impl FsBPin<T>> + 'd,
mclk: impl Peripheral<P = impl MclkBPin<T>> + 'd,
dma: impl Peripheral<P = C> + 'd,
dma_buf: &'d mut [W],
mut config: Config,
) -> Self
where
C: Channel + DmaB<T>,
{
into_ref!(mclk);
let (_sd_af_type, ck_af_type) = Self::get_af_types(config.mode, config.tx_rx);
mclk.set_as_af(mclk.af_num(), ck_af_type);
mclk.set_speed(crate::gpio::Speed::VeryHigh);
if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
config.master_clock_divider = MasterClockDivider::Div1;
} }
Self::new_asynchronous_block_b(peri, sck, sd, fs, dma, dma_buf, config)
}
pub fn new_asynchronous_block_b(
peri: impl Peripheral<P = T> + 'd,
sck: impl Peripheral<P = impl SckBPin<T>> + 'd,
sd: impl Peripheral<P = impl SdBPin<T>> + 'd,
fs: impl Peripheral<P = impl FsBPin<T>> + 'd,
dma: impl Peripheral<P = C> + 'd,
dma_buf: &'d mut [W],
config: Config,
) -> Self
where
C: Channel + DmaB<T>,
{
into_ref!(dma, peri, sck, sd, fs);
let (sd_af_type, ck_af_type) = Self::get_af_types(config.mode, config.tx_rx);
sd.set_as_af(sd.af_num(), sd_af_type);
sd.set_speed(crate::gpio::Speed::VeryHigh);
sck.set_as_af(sck.af_num(), ck_af_type);
sck.set_speed(crate::gpio::Speed::VeryHigh);
fs.set_as_af(fs.af_num(), ck_af_type);
fs.set_speed(crate::gpio::Speed::VeryHigh);
let sub_block = SubBlock::B;
let request = dma.request();
Self::new_inner(
peri,
sub_block,
Some(sck.map_into()),
None,
Some(sd.map_into()),
Some(fs.map_into()),
Self::get_ring_buffer(dma, dma_buf, request, sub_block, config.tx_rx),
config,
)
} }
fn update_synchronous_config(config: &mut Config) { fn update_synchronous_config(config: &mut Config) {
@ -721,74 +621,210 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
} }
} }
pub fn new_synchronous_block_a( impl SubBlockA {
pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>(
peri: impl Peripheral<P = T> + 'd,
sck: impl Peripheral<P = impl SckAPin<T>> + 'd,
sd: impl Peripheral<P = impl SdAPin<T>> + 'd,
fs: impl Peripheral<P = impl FsAPin<T>> + 'd,
mclk: impl Peripheral<P = impl MclkAPin<T>> + 'd,
dma: impl Peripheral<P = C> + 'd,
dma_buf: &'d mut [W],
mut config: Config,
) -> SubBlock<T, C, W>
where
C: Channel + DmaA<T>,
{
into_ref!(mclk);
let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
mclk.set_as_af(mclk.af_num(), ck_af_type);
mclk.set_speed(crate::gpio::Speed::VeryHigh);
if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
config.master_clock_divider = MasterClockDivider::Div1;
}
Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config)
}
pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>(
peri: impl Peripheral<P = T> + 'd,
sck: impl Peripheral<P = impl SckAPin<T>> + 'd,
sd: impl Peripheral<P = impl SdAPin<T>> + 'd,
fs: impl Peripheral<P = impl FsAPin<T>> + 'd,
dma: impl Peripheral<P = C> + 'd,
dma_buf: &'d mut [W],
config: Config,
) -> SubBlock<T, C, W>
where
C: Channel + DmaA<T>,
{
into_ref!(peri, dma, sck, sd, fs);
let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
sd.set_as_af(sd.af_num(), sd_af_type);
sd.set_speed(crate::gpio::Speed::VeryHigh);
sck.set_as_af(sck.af_num(), ck_af_type);
sck.set_speed(crate::gpio::Speed::VeryHigh);
fs.set_as_af(fs.af_num(), ck_af_type);
fs.set_speed(crate::gpio::Speed::VeryHigh);
let sub_block = WhichSubBlock::A;
let request = dma.request();
SubBlock::new_inner(
peri,
sub_block,
Some(sck.map_into()),
None,
Some(sd.map_into()),
Some(fs.map_into()),
get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx),
config,
)
}
pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
sd: impl Peripheral<P = impl SdAPin<T>> + 'd, sd: impl Peripheral<P = impl SdAPin<T>> + 'd,
dma: impl Peripheral<P = C> + 'd, dma: impl Peripheral<P = C> + 'd,
dma_buf: &'d mut [W], dma_buf: &'d mut [W],
mut config: Config, mut config: Config,
) -> Self ) -> SubBlock<T, C, W>
where where
C: Channel + DmaA<T>, C: Channel + DmaA<T>,
{ {
Self::update_synchronous_config(&mut config); update_synchronous_config(&mut config);
into_ref!(dma, peri, sd); into_ref!(dma, peri, sd);
let (sd_af_type, _ck_af_type) = Self::get_af_types(config.mode, config.tx_rx); let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx);
sd.set_as_af(sd.af_num(), sd_af_type); sd.set_as_af(sd.af_num(), sd_af_type);
sd.set_speed(crate::gpio::Speed::VeryHigh); sd.set_speed(crate::gpio::Speed::VeryHigh);
let sub_block = SubBlock::A; let sub_block = WhichSubBlock::A;
let request = dma.request(); let request = dma.request();
Self::new_inner( SubBlock::new_inner(
peri, peri,
sub_block, sub_block,
None, None,
None, None,
Some(sd.map_into()), Some(sd.map_into()),
None, None,
Self::get_ring_buffer(dma, dma_buf, request, sub_block, config.tx_rx), get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx),
config,
)
}
}
impl SubBlockB {
pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>(
peri: impl Peripheral<P = T> + 'd,
sck: impl Peripheral<P = impl SckBPin<T>> + 'd,
sd: impl Peripheral<P = impl SdBPin<T>> + 'd,
fs: impl Peripheral<P = impl FsBPin<T>> + 'd,
mclk: impl Peripheral<P = impl MclkBPin<T>> + 'd,
dma: impl Peripheral<P = C> + 'd,
dma_buf: &'d mut [W],
mut config: Config,
) -> SubBlock<T, C, W>
where
C: Channel + DmaB<T>,
{
into_ref!(mclk);
let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
mclk.set_as_af(mclk.af_num(), ck_af_type);
mclk.set_speed(crate::gpio::Speed::VeryHigh);
if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
config.master_clock_divider = MasterClockDivider::Div1;
}
Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config)
}
pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>(
peri: impl Peripheral<P = T> + 'd,
sck: impl Peripheral<P = impl SckBPin<T>> + 'd,
sd: impl Peripheral<P = impl SdBPin<T>> + 'd,
fs: impl Peripheral<P = impl FsBPin<T>> + 'd,
dma: impl Peripheral<P = C> + 'd,
dma_buf: &'d mut [W],
config: Config,
) -> SubBlock<T, C, W>
where
C: Channel + DmaB<T>,
{
into_ref!(dma, peri, sck, sd, fs);
let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
sd.set_as_af(sd.af_num(), sd_af_type);
sd.set_speed(crate::gpio::Speed::VeryHigh);
sck.set_as_af(sck.af_num(), ck_af_type);
sck.set_speed(crate::gpio::Speed::VeryHigh);
fs.set_as_af(fs.af_num(), ck_af_type);
fs.set_speed(crate::gpio::Speed::VeryHigh);
let sub_block = WhichSubBlock::B;
let request = dma.request();
SubBlock::new_inner(
peri,
sub_block,
Some(sck.map_into()),
None,
Some(sd.map_into()),
Some(fs.map_into()),
get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx),
config, config,
) )
} }
pub fn new_synchronous_block_b( pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
sd: impl Peripheral<P = impl SdBPin<T>> + 'd, sd: impl Peripheral<P = impl SdBPin<T>> + 'd,
dma: impl Peripheral<P = C> + 'd, dma: impl Peripheral<P = C> + 'd,
dma_buf: &'d mut [W], dma_buf: &'d mut [W],
mut config: Config, mut config: Config,
) -> Self ) -> SubBlock<T, C, W>
where where
C: Channel + DmaB<T>, C: Channel + DmaB<T>,
{ {
Self::update_synchronous_config(&mut config); update_synchronous_config(&mut config);
into_ref!(dma, peri, sd); into_ref!(dma, peri, sd);
let (sd_af_type, _ck_af_type) = Self::get_af_types(config.mode, config.tx_rx); let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx);
sd.set_as_af(sd.af_num(), sd_af_type); sd.set_as_af(sd.af_num(), sd_af_type);
sd.set_speed(crate::gpio::Speed::VeryHigh); sd.set_speed(crate::gpio::Speed::VeryHigh);
let sub_block = SubBlock::B; let sub_block = WhichSubBlock::B;
let request = dma.request(); let request = dma.request();
Self::new_inner( SubBlock::new_inner(
peri, peri,
sub_block, sub_block,
None, None,
None, None,
Some(sd.map_into()), Some(sd.map_into()),
None, None,
Self::get_ring_buffer(dma, dma_buf, request, sub_block, config.tx_rx), get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx),
config, config,
) )
} }
}
impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> {
pub fn start(self: &mut Self) { pub fn start(self: &mut Self) {
match self.ring_buffer { match self.ring_buffer {
RingBuffer::Writable(ref mut rb) => { RingBuffer::Writable(ref mut rb) => {
@ -809,7 +845,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
fn new_inner( fn new_inner(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
sub_block: SubBlock, sub_block: WhichSubBlock,
sck: Option<PeripheralRef<'d, AnyPin>>, sck: Option<PeripheralRef<'d, AnyPin>>,
mclk: Option<PeripheralRef<'d, AnyPin>>, mclk: Option<PeripheralRef<'d, AnyPin>>,
sd: Option<PeripheralRef<'d, AnyPin>>, sd: Option<PeripheralRef<'d, AnyPin>>,
@ -974,7 +1010,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
} }
} }
impl<'d, T: Instance, C: Channel, W: word::Word> Drop for Sai<'d, T, C, W> { impl<'d, T: Instance, C: Channel, W: word::Word> Drop for SubBlock<'d, T, C, W> {
fn drop(&mut self) { fn drop(&mut self) {
let ch = T::REGS.ch(self.sub_block as usize); let ch = T::REGS.ch(self.sub_block as usize);
ch.cr1().modify(|w| w.set_saien(false)); ch.cr1().modify(|w| w.set_saien(false));
@ -1018,9 +1054,9 @@ foreach_peripheral!(
}; };
); );
impl<'d, T: Instance, C: Channel, W: word::Word> SetConfig for Sai<'d, T, C, W> { impl<'d, T: Instance> SetConfig for Sai<'d, T> {
type Config = Config; type Config = Config;
fn set_config(&mut self, config: &Self::Config) { fn set_config(&mut self, config: &Self::Config) {
self.reconfigure(*config); // self.reconfigure(*config);
} }
} }