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.
9 #include <arch/x86/pic.h>
14 #include <arch/x86/arch_int.h>
21 # define TRACE(x) dprintf x
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.
72 pic_is_spurious_interrupt(int32 num
)
77 // Note, detecting spurious interrupts on line 15 obviously doesn't
78 // work correctly - and since those are extremely rare, anyway, we
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;
90 pic_is_level_triggered_interrupt(int32 num
)
92 if (num
< 0 || num
> PIC_NUM_INTS
)
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.
104 pic_end_of_interrupt(int32 num
)
106 if (num
< 0 || num
> PIC_NUM_INTS
)
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
);
120 pic_enable_io_interrupt(int32 num
)
122 // interrupt is specified "normalized"
123 if (num
< 0 || num
> PIC_NUM_INTS
)
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
);
133 out8(in8(PIC_SLAVE_MASK
) & ~(1 << (num
- PIC_SLAVE_INT_BASE
)), PIC_SLAVE_MASK
);
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)
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
);
152 out8(in8(PIC_SLAVE_MASK
) | (1 << (num
- PIC_SLAVE_INT_BASE
)), PIC_SLAVE_MASK
);
157 pic_configure_io_interrupt(int32 num
, uint32 config
)
161 if (num
< 0 || num
> PIC_NUM_INTS
|| num
== 2)
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
);
170 value
= in8(PIC_SLAVE_TRIGGER_MODE
);
171 localBit
= num
- PIC_SLAVE_INT_BASE
;
174 if (config
& B_LEVEL_TRIGGERED
)
175 value
|= 1 << localBit
;
177 value
&= ~(1 << localBit
);
179 if (num
< PIC_SLAVE_INT_BASE
)
180 out8(value
, PIC_MASTER_TRIGGER_MODE
);
182 out8(value
, PIC_SLAVE_TRIGGER_MODE
);
184 sLevelTriggeredInterrupts
= in8(PIC_MASTER_TRIGGER_MODE
)
185 | (in8(PIC_SLAVE_TRIGGER_MODE
) << 8);
192 static const interrupt_controller picController
= {
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
,
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
225 // should set everything possible to level triggered
226 out8(0xf8, PIC_MASTER_TRIGGER_MODE
);
227 out8(0xde, PIC_SLAVE_TRIGGER_MODE
);
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
);
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);