#![no_std]
mod commands;
mod chip;
mod regs;
mod post;
use commands::*;
use chip::*;
pub use regs::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PicOperationMode {
FullyNested,
AutomaticRotation,
SpecialMask,
PolledMode,
}
pub struct ChainedPics {
initialized: bool,
pub master: Pic,
pub slave: Pic,
}
impl ChainedPics {
pub const fn new(master_offset: u8, slave_offset: u8) -> Self {
assert!(master_offset >= 32 && slave_offset >= 32, "Both master and slave offsets must not overlap with CPU exceptions.");
assert!(master_offset.abs_diff(slave_offset) >= 8, "The master and slave offsets are overlapping with each other.");
unsafe { Self::new_unchecked(master_offset, slave_offset) }
}
pub const fn new_contiguous(primary_offset: u8) -> Self {
Self::new(primary_offset, primary_offset + 8)
}
pub fn is_initialized(&self) -> bool {
self.initialized
}
pub fn initialize(&mut self) {
unsafe {
self.master.init(PicIRQMapping::Master(Some(ICW3_MASTER::SLAVE2)), false);
self.slave.init(PicIRQMapping::Slave(ICW3_SLAVE::MASTER2), false);
}
if !self.is_initialized() { self.initialized = true }
}
pub fn operation_mode_change(&mut self, new_op_mode: PicOperationMode) {
if self.master.operation_mode_current() != new_op_mode {
self.master.operation_mode_change(new_op_mode);
self.slave.operation_mode_change(new_op_mode);
}
}
pub unsafe fn is_spurious(&mut self, vec_id: u8) -> bool {
assert!(vec_id >= 32, "Cannot be one of the CPU exceptions.");
if self.slave.handles_interrupt(vec_id) {
if self.slave.is_spurious(vec_id) {
self.master.end_of_interrupt();
true
} else { false }
} else if self.master.handles_interrupt(vec_id) {
self.master.is_spurious(vec_id)
} else {
panic!("Provided interrupt is out of scope for both PICs.")
}
}
pub unsafe fn notify_end_of_interrupt(&mut self, vec_id: u8) {
assert!(vec_id >= 32, "Cannot be one of the CPU exceptions.");
if self.slave.handles_interrupt(vec_id) {
self.slave.end_of_interrupt();
self.master.end_of_interrupt();
} else
if self.master.handles_interrupt(vec_id) {
self.master.end_of_interrupt();
}
}
pub fn disable(&mut self) {
unsafe { self.write_mask(IrqMask::all()) };
}
pub fn enable(&mut self) {
unsafe { self.write_mask(IrqMask::empty()); }
}
pub fn disable_slave(&mut self) {
unsafe {
let mask = self.master.mask_read();
self.master.mask_write(
mask | OCW1::MASK_IRQ_2
);
}
}
pub fn enable_slave(&mut self) {
unsafe {
let mask = self.master.mask_read();
self.master.mask_write(
mask & !OCW1::MASK_IRQ_2
);
}
}
pub fn get_mask(&mut self) -> IrqMask {
IrqMask::from_bits_truncate(
u16::from_le_bytes([
self.master.mask_read().bits(), self.slave.mask_read().bits()
])
)
}
pub unsafe fn write_mask(&mut self, mask: IrqMask) {
let bytes = mask.bits().to_le_bytes();
unsafe {
self.master.mask_write(OCW1::from_bits_truncate(bytes[0]));
self.slave.mask_write(OCW1::from_bits_truncate(bytes[1]));
}
}
pub fn with_master<F>(&mut self, f: F) where
F: FnOnce(&mut Pic)
{
f(&mut self.master)
}
pub fn with_slave<F>(&mut self, f: F) where
F: FnOnce(&mut Pic) {
f(&mut self.slave)
}
pub const unsafe fn new_unchecked(master_offset: u8, slave_offset: u8) -> Self {
Self {
initialized: false,
master: Pic::new(master_offset, 0x20, 0x21),
slave: Pic::new(slave_offset, 0xa0, 0xa1),
}
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct IrqMask: u16 {
const IRQ0_TIMER = 1 << 0;
const IRQ1_PS2_KEYBOARD = 1 << 1;
const IRQ3_SERIAL_PORT2 = 1 << 3;
const IRQ4_SERIAL_PORT1 = 1 << 4;
const IRQ5_PARALLEL_PORT2 = 1 << 5;
const IRQ6_DISKETTE_DRIVE = 1 << 6;
const IRQ7_PARALLEL_PORT1 = 1 << 7;
const IRQ8_RTC = 1 << 8;
const IRQ9_CGA_VERTICAL_RETRACE = 1 << 9;
const IRQ10_FREE_1 = 1 << 10;
const IRQ11_FREE_2 = 1 << 11;
const IRQ12_PS2_MOUSE = 1 << 12;
const IRQ13_FPU = 1 << 13;
const IRQ14_PRIMARY_ATA = 1 << 14;
const IRQ15_SECONDARY_ATA = 1 << 15;
}
}