#include #include "../idt/idt.h" #include "../pic/pic.h" #include "irq.h" /* This array is actually an array of function pointers. We use * this to handle custom IRQ handlers for a given IRQ */ void *irq_routines[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_irq_install_handler (int irq, void (*handler)(ISR_stack_regs *r)) { irq_routines[irq] = handler; } void i86_irq_uninstall_handler (int irq) { irq_routines[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_irq_install() { i86_pic_remap(32,40); i86_idt_set_gate(32, (unsigned)i86_irq0, 0x08, 0x8E); i86_idt_set_gate(33, (unsigned)i86_irq1, 0x08, 0x8E); i86_idt_set_gate(34, (unsigned)i86_irq2, 0x08, 0x8E); i86_idt_set_gate(35, (unsigned)i86_irq3, 0x08, 0x8E); i86_idt_set_gate(36, (unsigned)i86_irq4, 0x08, 0x8E); i86_idt_set_gate(37, (unsigned)i86_irq5, 0x08, 0x8E); i86_idt_set_gate(38, (unsigned)i86_irq6, 0x08, 0x8E); i86_idt_set_gate(39, (unsigned)i86_irq7, 0x08, 0x8E); i86_idt_set_gate(40, (unsigned)i86_irq8, 0x08, 0x8E); i86_idt_set_gate(41, (unsigned)i86_irq9, 0x08, 0x8E); i86_idt_set_gate(42, (unsigned)i86_irq10, 0x08, 0x8E); i86_idt_set_gate(43, (unsigned)i86_irq11, 0x08, 0x8E); i86_idt_set_gate(44, (unsigned)i86_irq12, 0x08, 0x8E); i86_idt_set_gate(45, (unsigned)i86_irq13, 0x08, 0x8E); i86_idt_set_gate(46, (unsigned)i86_irq14, 0x08, 0x8E); i86_idt_set_gate(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_irq_handler (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 = irq_routines[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); }