3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 /* These are own ISRs that point to our special IRQ handler
25 * instead of the regular 'fault_handler' function */
43 /* This array is actually an array of function pointers. We use
44 * this to handle custom IRQ handlers for a given IRQ */
45 void *irq_routines
[16] =
47 0, 0, 0, 0, 0, 0, 0, 0,
48 0, 0, 0, 0, 0, 0, 0, 0
51 /* This installs a custom IRQ handler for the given IRQ */
52 void irq_install_handler (int irq
, void (*handler
)(struct regs
*r
))
54 irq_routines
[irq
] = handler
;
57 /* This clears the handler for a given IRQ */
58 void irq_uninstall_handler (int irq
)
60 irq_routines
[irq
] = 0;
63 /* Normally, IRQs 0 to 7 are mapped to entries 8 to 15. This
64 * is a problem in protected mode, because IDT entry 8 is a
65 * Double Fault! Without remapping, every time IRQ0 fires,
66 * you get a Double Fault Exception, which is NOT actually
67 * what's happening. We send commands to the Programmable
68 * Interrupt Controller (PICs - also called the 8259's) in
69 * order to make IRQ0 to 15 be remapped to IDT entries 32 to
85 /* We first remap the interrupt controllers, and then we install
86 * the appropriate ISRs to the correct entries in the IDT. This
87 * is just like installing the exception handlers */
88 unsigned int irq_install ()
92 idt_set_gate(32, (unsigned)irq0
, 0x08, 0x8E);
93 idt_set_gate(33, (unsigned)irq1
, 0x08, 0x8E);
94 idt_set_gate(34, (unsigned)irq2
, 0x08, 0x8E);
95 idt_set_gate(35, (unsigned)irq3
, 0x08, 0x8E);
96 idt_set_gate(36, (unsigned)irq4
, 0x08, 0x8E);
97 idt_set_gate(37, (unsigned)irq5
, 0x08, 0x8E);
98 idt_set_gate(38, (unsigned)irq6
, 0x08, 0x8E);
99 idt_set_gate(39, (unsigned)irq7
, 0x08, 0x8E);
101 idt_set_gate(40, (unsigned)irq8
, 0x08, 0x8E);
102 idt_set_gate(41, (unsigned)irq9
, 0x08, 0x8E);
103 idt_set_gate(42, (unsigned)irq10
, 0x08, 0x8E);
104 idt_set_gate(43, (unsigned)irq11
, 0x08, 0x8E);
105 idt_set_gate(44, (unsigned)irq12
, 0x08, 0x8E);
106 idt_set_gate(45, (unsigned)irq13
, 0x08, 0x8E);
107 idt_set_gate(46, (unsigned)irq14
, 0x08, 0x8E);
108 idt_set_gate(47, (unsigned)irq15
, 0x08, 0x8E);
113 /* Each of the IRQ ISRs point to this function, rather than
114 * the 'fault_handler' in 'isrs.c'. The IRQ Controllers need
115 * to be told when you are done servicing them, so you need
116 * to send them an "End of Interrupt" command (0x20). There
117 * are two 8259 chips: The first exists at 0x20, the second
118 * exists at 0xA0. If the second controller (an IRQ from 8 to
119 * 15) gets an interrupt, you need to acknowledge the
120 * interrupt at BOTH controllers, otherwise, you only send
121 * an EOI command to the first controller. If you don't send
122 * an EOI, you won't raise any more IRQs */
123 void irq_handler (struct regs
*r
)
125 /* This is a blank function pointer */
126 void (*handler
)(struct regs
*r
);
128 /* Find out if we have a custom handler to run for this
129 * IRQ, and then finally, run it */
130 handler
= irq_routines
[r
->int_no
- 32];
135 /* If the IDT entry that was invoked was greater than 40
136 * (meaning IRQ8 - 15), then we need to send an EOI to
137 * the slave controller */
140 outportb(0xA0, 0x20);
143 /* In either case, we need to send an EOI to the master
144 * interrupt controller too */
145 outportb(0x20, 0x20);