#include #include "pic.h" #include "irq.h" #include "../idt/idt.h" /* These are own ISRs that point to our special IRQ handler * instead of the regular 'fault_handler' function */ extern void i86_irq0(); extern void i86_irq1(); extern void i86_irq2(); extern void i86_irq3(); extern void i86_irq4(); extern void i86_irq5(); extern void i86_irq6(); extern void i86_irq7(); extern void i86_irq8(); extern void i86_irq9(); extern void i86_irq10(); extern void i86_irq11(); extern void i86_irq12(); extern void i86_irq13(); extern void i86_irq14(); extern void i86_irq15(); /* This array is actually an array of function pointers. We use * this to handle custom IRQ handlers for a given IRQ */ void *IrqRoutines[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* This installs a custom IRQ handler for the given IRQ */ void i86_IrqInstallHandler (int irq, void (*handler)(ISR_stack_regs *r)) { IrqRoutines[irq] = handler; } void i86_IrqUninstallHandler (int irq) { IrqRoutines[irq] = 0; } /* We first remap the interrupt controllers, and then we install * the appropriate ISRs to the correct entries in the IDT. This * is just like installing the exception handlers */ void i86_IrqInstall() { i86_PicRemap(32,40); i86_IdtSetGate(32, (unsigned)i86_irq0, 0x08, 0x8E); i86_IdtSetGate(33, (unsigned)i86_irq1, 0x08, 0x8E); i86_IdtSetGate(34, (unsigned)i86_irq2, 0x08, 0x8E); i86_IdtSetGate(35, (unsigned)i86_irq3, 0x08, 0x8E); i86_IdtSetGate(36, (unsigned)i86_irq4, 0x08, 0x8E); i86_IdtSetGate(37, (unsigned)i86_irq5, 0x08, 0x8E); i86_IdtSetGate(38, (unsigned)i86_irq6, 0x08, 0x8E); i86_IdtSetGate(39, (unsigned)i86_irq7, 0x08, 0x8E); i86_IdtSetGate(40, (unsigned)i86_irq8, 0x08, 0x8E); i86_IdtSetGate(41, (unsigned)i86_irq9, 0x08, 0x8E); i86_IdtSetGate(42, (unsigned)i86_irq10, 0x08, 0x8E); i86_IdtSetGate(43, (unsigned)i86_irq11, 0x08, 0x8E); i86_IdtSetGate(44, (unsigned)i86_irq12, 0x08, 0x8E); i86_IdtSetGate(45, (unsigned)i86_irq13, 0x08, 0x8E); i86_IdtSetGate(46, (unsigned)i86_irq14, 0x08, 0x8E); i86_IdtSetGate(47, (unsigned)i86_irq15, 0x08, 0x8E); } /* Each of the IRQ ISRs point to this function, rather than * the 'fault_handler' in 'isrs.c'. The IRQ Controllers need * to be told when you are done servicing them, so you need * to send them an "End of Interrupt" command (0x20). There * are two 8259 chips: The first exists at 0x20, the second * exists at 0xA0. If the second controller (an IRQ from 8 to * 15) gets an interrupt, you need to acknowledge the * interrupt at BOTH controllers, otherwise, you only send * an EOI command to the first controller. If you don't send * an EOI, you won't raise any more IRQs */ void i86_IrqHandler (ISR_stack_regs *r) { /* This is a blank function pointer */ void (*handler)(ISR_stack_regs *r); /* Find out if we have a custom handler to run for this * IRQ, and then finally, run it */ handler = IrqRoutines[r->int_no - 32]; if (handler) handler(r); /* If the IDT entry that was invoked was greater than 40 * (meaning IRQ8 - 15), then we need to send an EOI to * the slave controller */ if (r->int_no >=40) outportb(0x0A, 0x20); /* In either case, we need to send an EOI to the master * interrupt controller too */ outportb(0x20, 0x20); }