]> git.saurik.com Git - apple/xnu.git/blob - iokit/Drivers/platform/drvAppleIntelClassicPIC/PIC8259.cpp
xnu-123.5.tar.gz
[apple/xnu.git] / iokit / Drivers / platform / drvAppleIntelClassicPIC / PIC8259.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
24 *
25 * DRI: Michael Burg
26 */
27
28 #include <architecture/i386/pio.h>
29 #include <IOKit/IOLib.h>
30 #include <IOKit/IOPlatformExpert.h>
31 #include "AppleIntelClassicPIC.h"
32
33 // This must agree with the trap number reported by the low-level
34 // interrupt handler (osfmk/i386/locore.s).
35
36 #define kIntelReservedIntVectors 0x40
37
38 extern OSSymbol * gIntelPICName;
39
40 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
41
42 #undef super
43 #define super IOInterruptController
44
45 OSDefineMetaClassAndStructors(AppleIntelClassicPIC, IOInterruptController);
46
47 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
48
49 bool AppleIntelClassicPIC::start(IOService * provider)
50 {
51 IOInterruptAction handler;
52
53 if ( super::start(provider) == false ) return false;
54
55 // Allocate the memory for the vectors.
56
57 vectors = (IOInterruptVector *) IOMalloc( kNumVectors *
58 sizeof(IOInterruptVector) );
59 if ( vectors == NULL ) return false;
60
61 bzero(vectors, kNumVectors * sizeof(IOInterruptVector));
62
63 // Allocate locks for the vectors.
64
65 for ( int cnt = 0; cnt < kNumVectors; cnt++ )
66 {
67 vectors[cnt].interruptLock = IOLockAlloc();
68
69 if ( vectors[cnt].interruptLock == NULL )
70 {
71 return false;
72 }
73 }
74
75 // Mask out the interrupts except for the casacde line.
76
77 maskInterrupts = 0xffff & ~(1 << kPICSlaveID);
78
79 // Initialize master PIC.
80
81 initializePIC( kPIC1BasePort,
82 /* ICW1 */ kPIC_ICW1_IC4,
83 /* ICW2 */ kIntelReservedIntVectors,
84 /* ICW3 */ (1 << kPICSlaveID),
85 /* ICW4 */ kPIC_ICW4_uPM );
86
87 // Write to OCW1, OCW3, OCW2.
88 // The priority order is changed to (highest to lowest)
89 // 3 4 5 6 7 0 1 2
90 // The default priority after initialization is (highest to lowest)
91 // 0 1 2 3 4 5 6 7
92
93 outb( kPIC_OCW1(kPIC1BasePort), maskInterrupts & 0xff );
94 outb( kPIC_OCW3(kPIC1BasePort), kPIC_OCW3_MBO | kPIC_OCW3_RR );
95 outb( kPIC_OCW2(kPIC1BasePort), kPIC_OCW2_R |
96 kPIC_OCW2_SL |
97 kPIC_OCW2_LEVEL(2) );
98
99 // Initialize slave PIC.
100
101 initializePIC( kPIC2BasePort,
102 /* ICW1 */ kPIC_ICW1_IC4,
103 /* ICW2 */ kIntelReservedIntVectors + 8,
104 /* ICW3 */ kPICSlaveID,
105 /* ICW4 */ kPIC_ICW4_uPM );
106
107 // Write to OCW1, and OCW3.
108
109 outb( kPIC_OCW1(kPIC2BasePort), maskInterrupts >> 8 );
110 outb( kPIC_OCW3(kPIC2BasePort), kPIC_OCW3_MBO | kPIC_OCW3_RR );
111
112 // Record trigger type.
113
114 triggerTypes = inb( kPIC1TriggerTypePort ) |
115 ( inb( kPIC2TriggerTypePort ) << 8 );
116
117 // Primary interrupt controller
118
119 getPlatform()->setCPUInterruptProperties(provider);
120
121 // Register the interrupt handler function so it can service interrupts.
122
123 handler = getInterruptHandlerAddress();
124 if ( provider->registerInterrupt(0, this, handler, 0) != kIOReturnSuccess )
125 panic("AppleIntelClassicPIC: Failed to install platform interrupt handler");
126
127 provider->enableInterrupt(0);
128
129 // Register this interrupt controller so clients can find it.
130
131 getPlatform()->registerInterruptController(gIntelPICName, this);
132
133 return true;
134 }
135
136 //---------------------------------------------------------------------------
137 // Free the interrupt controller object. Deallocate all resources.
138
139 void AppleIntelClassicPIC::free(void)
140 {
141 if ( vectors )
142 {
143 for ( int cnt = 0; cnt < kNumVectors; cnt++ )
144 {
145 if (vectors[cnt].interruptLock)
146 IOLockFree(vectors[cnt].interruptLock);
147 }
148
149 IOFree( vectors, kNumVectors * sizeof(IOInterruptVector) );
150 vectors = 0;
151 }
152
153 super::free();
154 }
155
156 //---------------------------------------------------------------------------
157 // Initialize the PIC by sending the Initialization Command Words (ICW).
158
159 void AppleIntelClassicPIC::initializePIC( UInt16 port,
160 UInt8 icw1, UInt8 icw2,
161 UInt8 icw3, UInt8 icw4 )
162 {
163 // Initialize 8259's. Start the initialization sequence by
164 // issuing ICW1 (Initialization Command Word 1).
165 // Bit 4 must be set.
166
167 outb( kPIC_ICW1(port), kPIC_ICW1_MBO | icw1 );
168
169 // ICW2
170 // Upper 5 bits of the interrupt vector address. The lower three
171 // bits are set according to the interrupt level serviced.
172
173 outb( kPIC_ICW2(port), icw2 );
174
175 // ICW3 (Master Device)
176 // Set a 1 bit for each IR line that has a slave.
177
178 outb( kPIC_ICW3(port), icw3 );
179
180 // ICW4
181
182 outb( kPIC_ICW4(port), icw4 );
183 }
184
185 //---------------------------------------------------------------------------
186 // Report whether the interrupt line is edge or level triggered.
187
188 int AppleIntelClassicPIC::getVectorType(long vectorNumber,
189 IOInterruptVector * vector)
190 {
191 return getTriggerType(vectorNumber);
192 }
193
194 //---------------------------------------------------------------------------
195 //
196
197 IOInterruptAction AppleIntelClassicPIC::getInterruptHandlerAddress(void)
198 {
199 return (IOInterruptAction) &AppleIntelClassicPIC::handleInterrupt;
200 }
201
202 //---------------------------------------------------------------------------
203 // Handle an interrupt by servicing the 8259, and dispatch the
204 // handler associated with the interrupt vector.
205
206 IOReturn AppleIntelClassicPIC::handleInterrupt(void * savedState,
207 IOService * nub,
208 int source)
209 {
210 IOInterruptVector * vector;
211 long vectorNumber;
212
213 typedef void (*IntelClockFuncType)(void *);
214 IntelClockFuncType clockFunc;
215
216 vectorNumber = source - kIntelReservedIntVectors;
217
218 if (vectorNumber >= kNumVectors)
219 return kIOReturnSuccess;
220
221 // Disable and ack interrupt.
222
223 disableInterrupt(vectorNumber);
224 ackInterrupt( vectorNumber);
225
226 // Process the interrupt.
227
228 vector = &vectors[vectorNumber];
229
230 vector->interruptActive = 1;
231
232 if ( !vector->interruptDisabledSoft )
233 {
234 if ( vector->interruptRegistered )
235 {
236 // Call registered interrupt handler.
237
238 if (vectorNumber == kClockIRQ) // FIXME
239 {
240 clockFunc = (IntelClockFuncType) vector->handler;
241 clockFunc(savedState);
242 }
243 else
244 {
245 vector->handler(vector->target, vector->refCon,
246 vector->nub, vector->source);
247 }
248
249 // interruptDisabledSoft flag may be set by the
250 // handler to indicate that the interrupt should
251 // be disabled.
252
253 if ( vector->interruptDisabledSoft )
254 {
255 // Already "hard" disabled, set interruptDisabledHard
256 // to indicate this.
257
258 vector->interruptDisabledHard = 1;
259 }
260 else
261 {
262 // Re-enable the interrupt line.
263
264 enableInterrupt(vectorNumber);
265 }
266 }
267 }
268 else
269 {
270 vector->interruptDisabledHard = 1;
271 }
272
273 vector->interruptActive = 0;
274
275 return kIOReturnSuccess;
276 }
277
278 //---------------------------------------------------------------------------
279 //
280
281 bool AppleIntelClassicPIC::vectorCanBeShared(long vectorNumber,
282 IOInterruptVector * vector)
283 {
284 if ( getVectorType(vectorNumber, vector) == kIOInterruptTypeLevel )
285 return true;
286 else
287 return false;
288 }
289
290 //---------------------------------------------------------------------------
291 //
292
293 void AppleIntelClassicPIC::initVector(long vectorNumber,
294 IOInterruptVector * vector)
295 {
296 super::initVector(vectorNumber, vector);
297 }
298
299 //---------------------------------------------------------------------------
300 //
301
302 void AppleIntelClassicPIC::disableVectorHard(long vectorNumber,
303 IOInterruptVector * vector)
304 {
305 // Sorry, cacade/slave interrupt line cannot be disable.
306
307 if (vectorNumber == kPICSlaveID) return;
308
309 disableInterrupt(vectorNumber);
310 }
311
312 //---------------------------------------------------------------------------
313 //
314
315 void AppleIntelClassicPIC::enableVector(long vectorNumber,
316 IOInterruptVector * vector)
317 {
318 enableInterrupt(vectorNumber);
319 }