#![no_std]
#![warn(missing_docs)]
#![deny(clippy::all)]
#![feature(alloc_prelude)]
#![feature(optin_builtin_traits)]
extern crate alloc;
use alloc::boxed::Box;
use core::intrinsics::transmute;
use core::marker::PhantomData;
use core::ptr;
use core::mem;
pub use bare_metal::Nr;
#[inline(always)]
pub fn handle_isr(irqn: u8) {
match unsafe { &mut ISRS[irqn as usize] } {
Some(isr) => isr(),
None => default_interrupt_handler(irqn)
}
}
static mut ISRS: [Option<Box<FnMut()>>; 98] = [
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None,
];
static mut DEFAULT_INTERRUPT_HANDLER: Option<Box<FnMut(u8)>> = None;
fn default_interrupt_handler(irq: u8) {
unsafe {
match DEFAULT_INTERRUPT_HANDLER {
Some(ref mut handler) => handler(irq),
None => panic!("No default handler"),
}
}
}
#[derive(Debug)]
pub enum Error {
InterruptAlreadyInUse(u8),
}
pub struct InterruptHandle<T, REQ> {
_data_type: PhantomData<T>,
irq: REQ,
}
impl<T, REQ> InterruptHandle<T, REQ> {
const fn new(irq: REQ) -> Self {
InterruptHandle {
irq,
_data_type: PhantomData,
}
}
}
pub trait InterruptController {
type Request: Nr;
type Priority;
fn trigger(&mut self, irq: &Self::Request);
fn is_pending(irq: &Self::Request) -> bool;
fn pend(irq: &Self::Request);
fn unpend(irq: &Self::Request);
fn get_priority(irq: &Self::Request) -> Self::Priority;
fn set_priority(&mut self, irq: &Self::Request, priority: Self::Priority);
fn disable(&mut self, irq: &Self::Request);
fn enable(&mut self, irq: &Self::Request);
}
pub struct InterruptTable<'a, IC: InterruptController> {
_lifetime: PhantomData<&'a ()>,
ic: IC,
data: [*mut (); 98],
}
impl<'a, IC> !Sync for InterruptTable<'a, IC> {}
impl<'a, IC: InterruptController> Drop for InterruptTable<'a, IC> {
fn drop(&mut self) {
unsafe {
DEFAULT_INTERRUPT_HANDLER = None;
for (i, isr) in ISRS.iter().enumerate() {
assert!(
isr.is_none(),
"Interrupt {} is still enabled while the InterruptTable is being dropped",
i,
);
}
}
}
}
pub fn scope<'a, IC, F, C, R>(
ic: IC,
default_handler: F,
code: C,
) -> R
where
IC: InterruptController,
F: FnMut(u8) + Send,
C: FnOnce(&mut InterruptTable<'a, IC>) -> R,
{
unsafe {
debug_assert!(DEFAULT_INTERRUPT_HANDLER.is_none());
DEFAULT_INTERRUPT_HANDLER = Some(transmute::<
Box<FnMut(u8) + Send>,
Box<FnMut(u8) + 'static>,
>(Box::new(default_handler)));
}
let mut interrupt_table = InterruptTable {
_lifetime: PhantomData,
ic,
data: [ptr::null_mut(); 98],
};
code(&mut interrupt_table)
}
impl<'a, IC: InterruptController> InterruptTable<'a, IC> {
pub fn register<F>(
&mut self,
irq: IC::Request,
priority: IC::Priority,
mut isr: F,
) -> Result<InterruptHandle<(), IC::Request>, Error>
where
F: FnMut() + 'a + Send,
{
self.register_owned(irq, priority, (), move |_| isr())
}
fn err_if_irq_in_use(&self, irq: u8) -> Result<(), Error> {
if unsafe { ISRS[usize::from(irq)].is_some() } {
Err(Error::InterruptAlreadyInUse(irq))
} else {
Ok(())
}
}
pub fn register_owned<F, T>(
&mut self,
irq: IC::Request,
priority: IC::Priority,
owned_data: T,
mut isr: F,
) -> Result<InterruptHandle<T, IC::Request>, Error>
where
T: Send,
F: FnMut(&mut T) + 'a + Send,
{
self.err_if_irq_in_use(irq.nr())?;
self.data[usize::from(irq.nr())] = Box::into_raw(Box::new(owned_data)) as *mut ();
let isr = unsafe {
let parameter = &mut *(self.data[usize::from(irq.nr())] as *mut T);
transmute::<Box<FnMut()>, Box<FnMut() + 'static + Send>>(Box::new(move || {
isr(parameter);
}))
};
let interrupt_handle = self.insert_boxed_isr(irq, isr)?;
self.set_priority(&interrupt_handle, priority);
self.ic.enable(&interrupt_handle.irq);
Ok(interrupt_handle)
}
pub fn with_interrupt<F, C>(
&mut self,
irq: IC::Request,
priority: IC::Priority,
isr: F,
code: C,
) -> Result<(), Error>
where
F: FnMut() + Send,
C: FnOnce(&mut InterruptTable<IC>),
{
self.err_if_irq_in_use(irq.nr())?;
self.data[usize::from(irq.nr())] = Box::into_raw(Box::new(())) as *mut ();
let isr = unsafe {
transmute::<Box<FnMut() + Send>, Box<FnMut() + 'static + Send>>(Box::new(isr))
};
let interrupt_handle = self.insert_boxed_isr::<()>(irq, isr)?;
self.set_priority(&interrupt_handle, priority);
self.ic.enable(&interrupt_handle.irq);
code(self);
self.unregister(interrupt_handle);
Ok(())
}
fn insert_boxed_isr<T>(
&mut self,
irq: IC::Request,
isr_boxed: Box<FnMut() + 'static + Send>,
) -> Result<InterruptHandle<T, IC::Request>, Error> {
self.err_if_irq_in_use(irq.nr())?;
unsafe {
ISRS[usize::from(irq.nr())] = Some(isr_boxed);
}
Ok(InterruptHandle::new(irq))
}
pub fn unregister<T>(&mut self, interrupt_handle: InterruptHandle<T, IC::Request>) -> T {
self.ic.disable(&interrupt_handle.irq);
unsafe {
ISRS[usize::from(interrupt_handle.irq.nr())] = None;
}
let data = mem::replace(&mut self.data[usize::from(interrupt_handle.irq.nr())], ptr::null_mut());
*unsafe { Box::from_raw(data as *mut T) }
}
pub fn set_priority<T>(&mut self, interrupt_handle: &InterruptHandle<T, IC::Request>, priority: IC::Priority) {
self.ic.set_priority(&interrupt_handle.irq, priority)
}
pub fn get_priority<T>(&self, interrupt_handle: &InterruptHandle<T, IC::Request>) -> IC::Priority {
IC::get_priority(&interrupt_handle.irq)
}
pub fn clear_pending_state<T>(&mut self, interrupt_handle: &InterruptHandle<T, IC::Request>) {
IC::unpend(&interrupt_handle.irq);
}
pub fn set_pending_state<T>(&mut self, interrupt_handle: &InterruptHandle<T, IC::Request>) {
IC::pend(&interrupt_handle.irq);
}
pub fn get_pending_state<T>(&self, interrupt_handle: &InterruptHandle<T, IC::Request>) -> bool {
IC::is_pending(&interrupt_handle.irq)
}
pub fn trigger(&mut self, irq: IC::Request) {
self.ic.trigger(&irq)
}
}