headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / kernel / arch / x86 / pic.cpp
bloba802ff32d96376d2b752dc863f67c92eca1c78c0
1 /*
2 * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
5 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
6 * Distributed under the terms of the NewOS License.
7 */
9 #include <arch/x86/pic.h>
11 #include <arch/cpu.h>
12 #include <arch/int.h>
14 #include <arch/x86/arch_int.h>
16 #include <int.h>
19 //#define TRACE_PIC
20 #ifdef TRACE_PIC
21 # define TRACE(x) dprintf x
22 #else
23 # define TRACE(x) ;
24 #endif
27 // Definitions for the PIC 8259 controller
28 // (this is not a complete list, only what we're actually using)
30 #define PIC_MASTER_CONTROL 0x20
31 #define PIC_MASTER_MASK 0x21
32 #define PIC_SLAVE_CONTROL 0xa0
33 #define PIC_SLAVE_MASK 0xa1
34 #define PIC_MASTER_INIT1 PIC_MASTER_CONTROL
35 #define PIC_MASTER_INIT2 PIC_MASTER_MASK
36 #define PIC_MASTER_INIT3 PIC_MASTER_MASK
37 #define PIC_MASTER_INIT4 PIC_MASTER_MASK
38 #define PIC_SLAVE_INIT1 PIC_SLAVE_CONTROL
39 #define PIC_SLAVE_INIT2 PIC_SLAVE_MASK
40 #define PIC_SLAVE_INIT3 PIC_SLAVE_MASK
41 #define PIC_SLAVE_INIT4 PIC_SLAVE_MASK
43 // the edge/level trigger control registers
44 #define PIC_MASTER_TRIGGER_MODE 0x4d0
45 #define PIC_SLAVE_TRIGGER_MODE 0x4d1
47 #define PIC_INIT1 0x10
48 #define PIC_INIT1_SEND_INIT4 0x01
49 #define PIC_INIT3_IR2_IS_SLAVE 0x04
50 #define PIC_INIT3_SLAVE_ID2 0x02
51 #define PIC_INIT4_x86_MODE 0x01
53 #define PIC_CONTROL3 0x08
54 #define PIC_CONTROL3_READ_ISR 0x03
55 #define PIC_CONTROL3_READ_IRR 0x02
57 #define PIC_NON_SPECIFIC_EOI 0x20
59 #define PIC_SLAVE_INT_BASE 8
60 #define PIC_NUM_INTS 0x0f
63 static uint16 sLevelTriggeredInterrupts = 0;
64 // binary mask: 1 level, 0 edge
67 /*! Tests if the interrupt in-service register of the responsible
68 PIC is set for interrupts 7 and 15, and if that's not the case,
69 it must assume it's a spurious interrupt.
71 static bool
72 pic_is_spurious_interrupt(int32 num)
74 if (num != 7)
75 return false;
77 // Note, detecting spurious interrupts on line 15 obviously doesn't
78 // work correctly - and since those are extremely rare, anyway, we
79 // just ignore them
81 out8(PIC_CONTROL3 | PIC_CONTROL3_READ_ISR, PIC_MASTER_CONTROL);
82 int32 isr = in8(PIC_MASTER_CONTROL);
83 out8(PIC_CONTROL3 | PIC_CONTROL3_READ_IRR, PIC_MASTER_CONTROL);
85 return (isr & 0x80) == 0;
89 static bool
90 pic_is_level_triggered_interrupt(int32 num)
92 if (num < 0 || num > PIC_NUM_INTS)
93 return false;
95 return (sLevelTriggeredInterrupts & (1 << num)) != 0;
99 /*! Sends a non-specified EOI (end of interrupt) notice to the PIC in
100 question (or both of them).
101 This clears the PIC interrupt in-service bit.
103 static bool
104 pic_end_of_interrupt(int32 num)
106 if (num < 0 || num > PIC_NUM_INTS)
107 return false;
109 // PIC 8259 controlled interrupt
110 if (num >= PIC_SLAVE_INT_BASE)
111 out8(PIC_NON_SPECIFIC_EOI, PIC_SLAVE_CONTROL);
113 // we always need to acknowledge the master PIC
114 out8(PIC_NON_SPECIFIC_EOI, PIC_MASTER_CONTROL);
115 return true;
119 static void
120 pic_enable_io_interrupt(int32 num)
122 // interrupt is specified "normalized"
123 if (num < 0 || num > PIC_NUM_INTS)
124 return;
126 // enable PIC 8259 controlled interrupt
128 TRACE(("pic_enable_io_interrupt: irq %ld\n", num));
130 if (num < PIC_SLAVE_INT_BASE)
131 out8(in8(PIC_MASTER_MASK) & ~(1 << num), PIC_MASTER_MASK);
132 else
133 out8(in8(PIC_SLAVE_MASK) & ~(1 << (num - PIC_SLAVE_INT_BASE)), PIC_SLAVE_MASK);
137 static void
138 pic_disable_io_interrupt(int32 num)
140 // interrupt is specified "normalized"
141 // never disable slave pic line IRQ 2
142 if (num < 0 || num > PIC_NUM_INTS || num == 2)
143 return;
145 // disable PIC 8259 controlled interrupt
147 TRACE(("pic_disable_io_interrupt: irq %ld\n", num));
149 if (num < PIC_SLAVE_INT_BASE)
150 out8(in8(PIC_MASTER_MASK) | (1 << num), PIC_MASTER_MASK);
151 else
152 out8(in8(PIC_SLAVE_MASK) | (1 << (num - PIC_SLAVE_INT_BASE)), PIC_SLAVE_MASK);
156 static void
157 pic_configure_io_interrupt(int32 num, uint32 config)
159 uint8 value;
160 int32 localBit;
161 if (num < 0 || num > PIC_NUM_INTS || num == 2)
162 return;
164 TRACE(("pic_configure_io_interrupt: irq %ld; config 0x%08lx\n", num, config));
166 if (num < PIC_SLAVE_INT_BASE) {
167 value = in8(PIC_MASTER_TRIGGER_MODE);
168 localBit = num;
169 } else {
170 value = in8(PIC_SLAVE_TRIGGER_MODE);
171 localBit = num - PIC_SLAVE_INT_BASE;
174 if (config & B_LEVEL_TRIGGERED)
175 value |= 1 << localBit;
176 else
177 value &= ~(1 << localBit);
179 if (num < PIC_SLAVE_INT_BASE)
180 out8(value, PIC_MASTER_TRIGGER_MODE);
181 else
182 out8(value, PIC_SLAVE_TRIGGER_MODE);
184 sLevelTriggeredInterrupts = in8(PIC_MASTER_TRIGGER_MODE)
185 | (in8(PIC_SLAVE_TRIGGER_MODE) << 8);
189 void
190 pic_init()
192 static const interrupt_controller picController = {
193 "8259 PIC",
194 &pic_enable_io_interrupt,
195 &pic_disable_io_interrupt,
196 &pic_configure_io_interrupt,
197 &pic_is_spurious_interrupt,
198 &pic_is_level_triggered_interrupt,
199 &pic_end_of_interrupt,
200 NULL
203 // Start initialization sequence for the master and slave PICs
204 out8(PIC_INIT1 | PIC_INIT1_SEND_INIT4, PIC_MASTER_INIT1);
205 out8(PIC_INIT1 | PIC_INIT1_SEND_INIT4, PIC_SLAVE_INIT1);
207 // Set start of interrupts to 0x20 for master, 0x28 for slave
208 out8(ARCH_INTERRUPT_BASE, PIC_MASTER_INIT2);
209 out8(ARCH_INTERRUPT_BASE + PIC_SLAVE_INT_BASE, PIC_SLAVE_INIT2);
211 // Specify cascading through interrupt 2
212 out8(PIC_INIT3_IR2_IS_SLAVE, PIC_MASTER_INIT3);
213 out8(PIC_INIT3_SLAVE_ID2, PIC_SLAVE_INIT3);
215 // Set both to operate in 8086 mode
216 out8(PIC_INIT4_x86_MODE, PIC_MASTER_INIT4);
217 out8(PIC_INIT4_x86_MODE, PIC_SLAVE_INIT4);
219 out8(0xfb, PIC_MASTER_MASK); // Mask off all interrupts (except slave pic line IRQ 2).
220 out8(0xff, PIC_SLAVE_MASK); // Mask off interrupts on the slave.
222 // determine which interrupts are level or edge triggered
224 #if 0
225 // should set everything possible to level triggered
226 out8(0xf8, PIC_MASTER_TRIGGER_MODE);
227 out8(0xde, PIC_SLAVE_TRIGGER_MODE);
228 #endif
230 sLevelTriggeredInterrupts = in8(PIC_MASTER_TRIGGER_MODE)
231 | (in8(PIC_SLAVE_TRIGGER_MODE) << 8);
233 TRACE(("PIC level trigger mode: 0x%08lx\n", sLevelTriggeredInterrupts));
235 reserve_io_interrupt_vectors(16, 0, INTERRUPT_TYPE_EXCEPTION);
237 // make the pic controller the current one
238 arch_int_set_interrupt_controller(picController);
242 void
243 pic_disable(uint16& enabledInterrupts)
245 enabledInterrupts = ~(in8(PIC_MASTER_MASK) | in8(PIC_SLAVE_MASK) << 8);
246 enabledInterrupts &= 0xfffb; // remove slave PIC from the mask
248 // Mask off all interrupts on master and slave
249 out8(0xff, PIC_MASTER_MASK);
250 out8(0xff, PIC_SLAVE_MASK);
252 free_io_interrupt_vectors(16, 0);