use super::TABLE_BASE;
use bitflags::bitflags;
use core::convert::{TryFrom, TryInto};
use core::fmt;
pub const IRQ_MODE_MASK: u32 = 0x0000_0700;
#[derive(Debug)]
#[repr(u8)]
pub enum IrqMode {
Fixed = 0b000,
LowestPriority = 0b001,
SystemManagement = 0b010,
NonMaskable = 0b100,
Init = 0b101,
External = 0b111,
}
impl IrqMode {
pub(super) fn as_u32(self) -> u32 {
(self as u32) << 8
}
}
impl TryFrom<u32> for IrqMode {
type Error = u32;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match (value & IRQ_MODE_MASK) >> 8 {
0b000 => Ok(IrqMode::Fixed),
0b001 => Ok(IrqMode::LowestPriority),
0b010 => Ok(IrqMode::SystemManagement),
0b100 => Ok(IrqMode::NonMaskable),
0b101 => Ok(IrqMode::Init),
0b111 => Ok(IrqMode::External),
other => Err(other),
}
}
}
bitflags! {
pub struct IrqFlags: u32 {
const LOGICAL_DEST = 1 << 11;
const SEND_PENDING = 1 << 12;
const LOW_ACTIVE = 1 << 13;
const REMOTE_IRR = 1 << 14;
const LEVEL_TRIGGERED = 1 << 15;
const MASKED = 1 << 16;
}
}
#[derive(Default)]
pub struct RedirectionTableEntry {
low: u32,
high: u32,
}
impl RedirectionTableEntry {
pub(crate) fn from_raw(low: u32, high: u32) -> Self {
Self { low, high }
}
pub(crate) fn into_raw(self) -> (u32, u32) {
(self.low, self.high)
}
pub fn vector(&self) -> u8 {
(self.low & 0xff) as u8
}
pub fn set_vector(&mut self, vector: u8) {
self.low = self.low & !0xff | vector as u32
}
pub fn mode(&self) -> IrqMode {
self.low.try_into().unwrap()
}
pub fn set_mode(&mut self, mode: IrqMode) {
self.low = self.low & !IRQ_MODE_MASK | mode.as_u32()
}
pub fn flags(&self) -> IrqFlags {
IrqFlags::from_bits_truncate(self.low)
}
pub fn set_flags(&mut self, flags: IrqFlags) {
let ro_flags = IrqFlags::SEND_PENDING | IrqFlags::REMOTE_IRR;
self.low = self.low & !(IrqFlags::all() - ro_flags).bits()
| (flags - ro_flags).bits()
}
pub fn dest(&self) -> u8 {
(self.high >> 24) as u8
}
pub fn set_dest(&mut self, dest: u8) {
self.high = (dest as u32) << 24;
}
}
pub fn lo(irq: u8) -> u32 {
TABLE_BASE + (2 * u32::from(irq))
}
pub fn hi(irq: u8) -> u32 {
lo(irq) + 1
}
impl fmt::Debug for RedirectionTableEntry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RedirectionTableEntry")
.field("vector", &self.vector())
.field("mode", &self.mode())
.field("flags", &self.flags())
.field("dest", &self.dest())
.finish()
}
}