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