use x86::io::*;
use super::interrupts::IDT;
use crate::arch::x86_64::kernel::interrupts::ExceptionStackFrame;
const PIC1_COMMAND_PORT: u16 = 0x20;
const PIC1_DATA_PORT: u16 = 0x21;
const PIC2_COMMAND_PORT: u16 = 0xA0;
const PIC2_DATA_PORT: u16 = 0xA1;
pub const PIC1_INTERRUPT_OFFSET: u8 = 32;
const PIC2_INTERRUPT_OFFSET: u8 = 40;
const SPURIOUS_IRQ_NUMBER: u8 = 7;
const PIC_EOI_COMMAND: u8 = 0x20;
pub fn eoi(int_no: u8) {
unsafe {
if int_no >= 40 {
outb(PIC2_COMMAND_PORT, PIC_EOI_COMMAND);
}
outb(PIC1_COMMAND_PORT, PIC_EOI_COMMAND);
}
}
pub fn init() {
unsafe {
let idt = &mut IDT;
idt[(PIC1_INTERRUPT_OFFSET + SPURIOUS_IRQ_NUMBER) as usize]
.set_handler_fn(spurious_interrupt_on_master)
.set_stack_index(0);
idt[(PIC2_INTERRUPT_OFFSET + SPURIOUS_IRQ_NUMBER) as usize]
.set_handler_fn(spurious_interrupt_on_slave)
.set_stack_index(0);
outb(PIC1_COMMAND_PORT, 0x11);
outb(PIC2_COMMAND_PORT, 0x11);
outb(PIC1_DATA_PORT, PIC1_INTERRUPT_OFFSET);
outb(PIC2_DATA_PORT, PIC2_INTERRUPT_OFFSET);
outb(PIC1_DATA_PORT, 0x04);
outb(PIC2_DATA_PORT, 0x02);
outb(PIC1_DATA_PORT, 0x01);
outb(PIC2_DATA_PORT, 0x01);
outb(PIC1_DATA_PORT, 0xFF);
outb(PIC2_DATA_PORT, 0xFF);
}
}
extern "x86-interrupt" fn spurious_interrupt_on_master(_stack_frame: ExceptionStackFrame) {
debug!("Spurious Interrupt on Master PIC (IRQ7)");
}
extern "x86-interrupt" fn spurious_interrupt_on_slave(_stack_frame: ExceptionStackFrame) {
debug!("Spurious Interrupt on Slave PIC (IRQ15)");
unsafe {
outb(PIC1_COMMAND_PORT, PIC_EOI_COMMAND);
}
}
fn edit_mask(int_no: u8, insert: bool) {
let port = if int_no >= 40 {
PIC2_DATA_PORT
} else {
PIC1_DATA_PORT
};
let offset = if int_no >= 40 { 40 } else { 32 };
unsafe {
let mask = inb(port);
if insert {
outb(port, mask | 1 << (int_no - offset));
} else {
outb(port, mask & !(1 << (int_no - offset)));
}
}
}
pub fn mask(int_no: u8) {
edit_mask(int_no, true);
}
pub fn unmask(int_no: u8) {
edit_mask(int_no, false);
}