use core::marker::PhantomData;
use r3_core::{
kernel::{
traits::KernelInterruptLine, ClearInterruptLineError, EnableInterruptLineError,
InterruptNum, InterruptPriority, PendInterruptLineError, QueryInterruptLineError,
SetInterruptLinePriorityError,
},
utils::Init,
};
use crate::{klock, KernelTraits, PortInterrupts, System};
unsafe impl<Traits: KernelTraits> r3_core::kernel::raw::KernelInterruptLine for System<Traits> {
const RAW_MANAGED_INTERRUPT_PRIORITY_RANGE: core::ops::Range<InterruptPriority> =
<Traits as PortInterrupts>::MANAGED_INTERRUPT_PRIORITY_RANGE;
const RAW_MANAGED_INTERRUPT_LINES: &'static [InterruptNum] =
<Traits as PortInterrupts>::MANAGED_INTERRUPT_LINES;
#[cfg_attr(not(feature = "inline_syscall"), inline(never))]
unsafe fn raw_interrupt_line_set_priority(
this: InterruptNum,
value: InterruptPriority,
) -> Result<(), SetInterruptLinePriorityError> {
let mut _lock = klock::lock_cpu::<Traits>()?;
if !Traits::is_task_context() {
return Err(SetInterruptLinePriorityError::BadContext);
}
unsafe { Traits::set_interrupt_line_priority(this, value) }
}
#[inline]
unsafe fn raw_interrupt_line_enable(
this: InterruptNum,
) -> Result<(), EnableInterruptLineError> {
unsafe { Traits::enable_interrupt_line(this) }
}
#[inline]
unsafe fn raw_interrupt_line_disable(
this: InterruptNum,
) -> Result<(), EnableInterruptLineError> {
unsafe { Traits::disable_interrupt_line(this) }
}
#[inline]
unsafe fn raw_interrupt_line_pend(this: InterruptNum) -> Result<(), PendInterruptLineError> {
unsafe { Traits::pend_interrupt_line(this) }
}
#[inline]
unsafe fn raw_interrupt_line_clear(this: InterruptNum) -> Result<(), ClearInterruptLineError> {
unsafe { Traits::clear_interrupt_line(this) }
}
#[inline]
unsafe fn raw_interrupt_line_is_pending(
this: InterruptNum,
) -> Result<bool, QueryInterruptLineError> {
unsafe { Traits::is_interrupt_line_pending(this) }
}
}
#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub struct InterruptLineInit {
pub(super) line: InterruptNum,
pub(super) priority: InterruptPriority,
pub(super) flags: InterruptLineInitFlags,
}
impl Init for InterruptLineInit {
const INIT: Self = Self {
line: 0,
priority: Init::INIT,
flags: InterruptLineInitFlags::empty(),
};
}
bitflags::bitflags! {
#[doc(hidden)]
pub struct InterruptLineInitFlags: u32 {
const ENABLE = 1 << 0;
const SET_PRIORITY = 1 << 1;
}
}
#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub struct InterruptAttr<Traits> {
pub _phantom: PhantomData<Traits>,
pub line_inits: &'static [InterruptLineInit],
}
impl<Traits: KernelTraits> InterruptAttr<Traits> {
pub(super) unsafe fn init(&self, _lock: klock::CpuLockTokenRefMut<Traits>) {
for line_init in self.line_inits {
if line_init
.flags
.contains(InterruptLineInitFlags::SET_PRIORITY)
{
unsafe {
<Traits as PortInterrupts>::set_interrupt_line_priority(
line_init.line,
line_init.priority,
)
.unwrap();
}
}
if line_init.flags.contains(InterruptLineInitFlags::ENABLE) {
unsafe { System::<Traits>::raw_interrupt_line_enable(line_init.line).unwrap() };
}
}
}
}