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