124 lines
3.5 KiB
Rust
124 lines
3.5 KiB
Rust
// Originally from pic8259 (https://docs.rs/pic8259/0.10.1/pic8259/)
|
|
// But this one feeds my addiction of not adding unnecessary crates
|
|
// And I can read and learn about the PIC too ig
|
|
// Driver for the 8086 PIC, we will switch to the APIC later on.
|
|
|
|
use super::io::{io_wait, outb};
|
|
|
|
// Command used to begin PIC initialization.
|
|
const CMD_INIT: u8 = 0x11;
|
|
|
|
// Command used to acknowledge an interrupt.
|
|
const CMD_END_OF_INTERRUPT: u8 = 0x20;
|
|
|
|
// The mode we want to run the PIC in.
|
|
const MODE_8086: u8 = 0x01;
|
|
|
|
struct Pic {
|
|
// The base interrupt offset
|
|
offset: u8,
|
|
|
|
// The I/O port we send commands to.
|
|
command: u8,
|
|
|
|
// The I/O port we receive commands from
|
|
data: u8,
|
|
}
|
|
|
|
impl Pic {
|
|
// Are we in charge of handling this interrupt?
|
|
fn handles_interrupt(&self, interrupt_id: u8) -> bool {
|
|
return self.offset <= interrupt_id && interrupt_id < self.offset + 8;
|
|
}
|
|
|
|
// Notify us that an interrupt has been handled and we're ready
|
|
// for more
|
|
fn end_of_interrupt(&mut self) {
|
|
return outb(self.command as u16, CMD_END_OF_INTERRUPT);
|
|
}
|
|
|
|
// Write the interrupt mask of this PIC
|
|
fn write_mask(&mut self, mask: u8) {
|
|
return outb(self.data as u16, mask);
|
|
}
|
|
}
|
|
|
|
// A pair of chained Pic controllers.
|
|
pub struct ChainedPics {
|
|
pics: [Pic; 2],
|
|
}
|
|
|
|
impl ChainedPics {
|
|
// Create a new interface for the chained pic controllers.
|
|
#[inline]
|
|
pub const fn new(offset1: u8, offset2: u8) -> ChainedPics {
|
|
ChainedPics {
|
|
pics: [
|
|
Pic {
|
|
offset: offset1,
|
|
command: 0x20,
|
|
data: 0x21,
|
|
},
|
|
Pic {
|
|
offset: offset2,
|
|
command: 0xA0,
|
|
data: 0xA1,
|
|
},
|
|
],
|
|
}
|
|
}
|
|
|
|
// Initialize the chained pic controllers.
|
|
pub fn initialize(&mut self) {
|
|
// Tell each PIC we're going to initialize it.
|
|
outb(self.pics[0].command as u16, CMD_INIT);
|
|
io_wait();
|
|
outb(self.pics[1].command as u16, CMD_INIT);
|
|
io_wait();
|
|
|
|
// Byte 1: Set up our base offsets.
|
|
outb(self.pics[0].data as u16, self.pics[0].offset);
|
|
io_wait();
|
|
outb(self.pics[1].data as u16, self.pics[1].offset);
|
|
io_wait();
|
|
|
|
// Byte 2: Configure chaining
|
|
outb(self.pics[0].data as u16, 4); // Tell Master Pic that there is a slave Pic at IRQ2
|
|
io_wait();
|
|
outb(self.pics[1].data as u16, 2); // Tell Slave PIC it's cascade identity
|
|
io_wait();
|
|
|
|
// Byte 3: Set out mode.
|
|
outb(self.pics[0].data as u16, MODE_8086);
|
|
io_wait();
|
|
outb(self.pics[1].data as u16, MODE_8086);
|
|
io_wait();
|
|
}
|
|
|
|
pub fn write_masks(&mut self, mask1: u8, mask2: u8) {
|
|
self.pics[0].write_mask(mask1);
|
|
self.pics[1].write_mask(mask2);
|
|
}
|
|
|
|
// Keep for later if we want to use APIC later in the future
|
|
#[allow(dead_code)]
|
|
pub fn disable(&mut self) {
|
|
self.write_masks(0xFF, 0xFF);
|
|
}
|
|
|
|
pub fn handles_interrupt(&self, interrupt_id: u8) -> bool {
|
|
return self
|
|
.pics
|
|
.iter()
|
|
.any(|pic| pic.handles_interrupt(interrupt_id));
|
|
}
|
|
|
|
pub fn notify_end_of_interrupt(&mut self, interrupt_id: u8) {
|
|
if self.handles_interrupt(interrupt_id) && self.pics[1].handles_interrupt(interrupt_id) {
|
|
self.pics[1].end_of_interrupt();
|
|
}
|
|
|
|
self.pics[0].end_of_interrupt();
|
|
}
|
|
}
|