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