Fixed ARM build
[ZeXOS.git] / kernel / arch / i386 / irq.c
blob75df315d11c032ae8bd9fa1dd03d1f9b8893fe39
1 /*
2 * ZeX/OS
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/>.
21 #include <system.h>
22 #include <arch/io.h>
23 #include <string.h>
26 /* These are own ISRs that point to our special IRQ handler
27 * instead of the regular 'fault_handler' function */
28 extern void irq0();
29 extern void irq1();
30 extern void irq2();
31 extern void irq3();
32 extern void irq4();
33 extern void irq5();
34 extern void irq6();
35 extern void irq7();
36 extern void irq8();
37 extern void irq9();
38 extern void irq10();
39 extern void irq11();
40 extern void irq12();
41 extern void irq13();
42 extern void irq14();
43 extern void irq15();
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
72 * 47 */
73 void irq_remap (void)
75 outb (0x20, 0x11);
76 outb (0xA0, 0x11);
77 outb (0x21, 0x20);
78 outb (0xA1, 0x28);
79 outb (0x21, 0x04);
80 outb (0xA1, 0x02);
81 outb (0x21, 0x01);
82 outb (0xA1, 0x01);
83 outb (0x21, 0x0);
84 outb (0xA1, 0x0);
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 ()
92 irq_remap ();
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);
112 return 1;
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];
134 if (handler)
135 handler (r);
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 */
140 if (r->int_no >= 40)
141 outb (0xA0, 0x20);
143 /* In either case, we need to send an EOI to the master
144 * interrupt controller too */
145 outb (0x20, 0x20);