2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
28 #include <architecture/i386/pio.h>
29 #include <IOKit/IOLib.h>
30 #include <IOKit/IOPlatformExpert.h>
31 #include "AppleIntelClassicPIC.h"
33 // This must agree with the trap number reported by the low-level
34 // interrupt handler (osfmk/i386/locore.s).
36 #define kIntelReservedIntVectors 0x40
38 extern OSSymbol
* gIntelPICName
;
40 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
43 #define super IOInterruptController
45 OSDefineMetaClassAndStructors(AppleIntelClassicPIC
, IOInterruptController
);
47 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
49 bool AppleIntelClassicPIC::start(IOService
* provider
)
51 IOInterruptAction handler
;
53 if ( super::start(provider
) == false ) return false;
55 // Allocate the memory for the vectors.
57 vectors
= (IOInterruptVector
*) IOMalloc( kNumVectors
*
58 sizeof(IOInterruptVector
) );
59 if ( vectors
== NULL
) return false;
61 bzero(vectors
, kNumVectors
* sizeof(IOInterruptVector
));
63 // Allocate locks for the vectors.
65 for ( int cnt
= 0; cnt
< kNumVectors
; cnt
++ )
67 vectors
[cnt
].interruptLock
= IOLockAlloc();
69 if ( vectors
[cnt
].interruptLock
== NULL
)
75 // Mask out the interrupts except for the casacde line.
77 maskInterrupts
= 0xffff & ~(1 << kPICSlaveID
);
79 // Initialize master PIC.
81 initializePIC( kPIC1BasePort
,
82 /* ICW1 */ kPIC_ICW1_IC4
,
83 /* ICW2 */ kIntelReservedIntVectors
,
84 /* ICW3 */ (1 << kPICSlaveID
),
85 /* ICW4 */ kPIC_ICW4_uPM
);
87 // Write to OCW1, OCW3, OCW2.
88 // The priority order is changed to (highest to lowest)
90 // The default priority after initialization is (highest to lowest)
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
|
99 // Initialize slave PIC.
101 initializePIC( kPIC2BasePort
,
102 /* ICW1 */ kPIC_ICW1_IC4
,
103 /* ICW2 */ kIntelReservedIntVectors
+ 8,
104 /* ICW3 */ kPICSlaveID
,
105 /* ICW4 */ kPIC_ICW4_uPM
);
107 // Write to OCW1, and OCW3.
109 outb( kPIC_OCW1(kPIC2BasePort
), maskInterrupts
>> 8 );
110 outb( kPIC_OCW3(kPIC2BasePort
), kPIC_OCW3_MBO
| kPIC_OCW3_RR
);
112 // Record trigger type.
114 triggerTypes
= inb( kPIC1TriggerTypePort
) |
115 ( inb( kPIC2TriggerTypePort
) << 8 );
117 // Primary interrupt controller
119 getPlatform()->setCPUInterruptProperties(provider
);
121 // Register the interrupt handler function so it can service interrupts.
123 handler
= getInterruptHandlerAddress();
124 if ( provider
->registerInterrupt(0, this, handler
, 0) != kIOReturnSuccess
)
125 panic("AppleIntelClassicPIC: Failed to install platform interrupt handler");
127 provider
->enableInterrupt(0);
129 // Register this interrupt controller so clients can find it.
131 getPlatform()->registerInterruptController(gIntelPICName
, this);
136 //---------------------------------------------------------------------------
137 // Free the interrupt controller object. Deallocate all resources.
139 void AppleIntelClassicPIC::free(void)
143 for ( int cnt
= 0; cnt
< kNumVectors
; cnt
++ )
145 if (vectors
[cnt
].interruptLock
)
146 IOLockFree(vectors
[cnt
].interruptLock
);
149 IOFree( vectors
, kNumVectors
* sizeof(IOInterruptVector
) );
156 //---------------------------------------------------------------------------
157 // Initialize the PIC by sending the Initialization Command Words (ICW).
159 void AppleIntelClassicPIC::initializePIC( UInt16 port
,
160 UInt8 icw1
, UInt8 icw2
,
161 UInt8 icw3
, UInt8 icw4
)
163 // Initialize 8259's. Start the initialization sequence by
164 // issuing ICW1 (Initialization Command Word 1).
165 // Bit 4 must be set.
167 outb( kPIC_ICW1(port
), kPIC_ICW1_MBO
| icw1
);
170 // Upper 5 bits of the interrupt vector address. The lower three
171 // bits are set according to the interrupt level serviced.
173 outb( kPIC_ICW2(port
), icw2
);
175 // ICW3 (Master Device)
176 // Set a 1 bit for each IR line that has a slave.
178 outb( kPIC_ICW3(port
), icw3
);
182 outb( kPIC_ICW4(port
), icw4
);
185 //---------------------------------------------------------------------------
186 // Report whether the interrupt line is edge or level triggered.
188 int AppleIntelClassicPIC::getVectorType(long vectorNumber
,
189 IOInterruptVector
* vector
)
191 return getTriggerType(vectorNumber
);
194 //---------------------------------------------------------------------------
197 IOInterruptAction
AppleIntelClassicPIC::getInterruptHandlerAddress(void)
199 return (IOInterruptAction
) &AppleIntelClassicPIC::handleInterrupt
;
202 //---------------------------------------------------------------------------
203 // Handle an interrupt by servicing the 8259, and dispatch the
204 // handler associated with the interrupt vector.
206 IOReturn
AppleIntelClassicPIC::handleInterrupt(void * savedState
,
210 IOInterruptVector
* vector
;
213 typedef void (*IntelClockFuncType
)(void *);
214 IntelClockFuncType clockFunc
;
216 vectorNumber
= source
- kIntelReservedIntVectors
;
218 if (vectorNumber
>= kNumVectors
)
219 return kIOReturnSuccess
;
221 // Disable and ack interrupt.
223 disableInterrupt(vectorNumber
);
224 ackInterrupt( vectorNumber
);
226 // Process the interrupt.
228 vector
= &vectors
[vectorNumber
];
230 vector
->interruptActive
= 1;
232 if ( !vector
->interruptDisabledSoft
)
234 if ( vector
->interruptRegistered
)
236 // Call registered interrupt handler.
238 if (vectorNumber
== kClockIRQ
) // FIXME
240 clockFunc
= (IntelClockFuncType
) vector
->handler
;
241 clockFunc(savedState
);
245 vector
->handler(vector
->target
, vector
->refCon
,
246 vector
->nub
, vector
->source
);
249 // interruptDisabledSoft flag may be set by the
250 // handler to indicate that the interrupt should
253 if ( vector
->interruptDisabledSoft
)
255 // Already "hard" disabled, set interruptDisabledHard
258 vector
->interruptDisabledHard
= 1;
262 // Re-enable the interrupt line.
264 enableInterrupt(vectorNumber
);
270 vector
->interruptDisabledHard
= 1;
273 vector
->interruptActive
= 0;
275 return kIOReturnSuccess
;
278 //---------------------------------------------------------------------------
281 bool AppleIntelClassicPIC::vectorCanBeShared(long vectorNumber
,
282 IOInterruptVector
* vector
)
284 if ( getVectorType(vectorNumber
, vector
) == kIOInterruptTypeLevel
)
290 //---------------------------------------------------------------------------
293 void AppleIntelClassicPIC::initVector(long vectorNumber
,
294 IOInterruptVector
* vector
)
296 super::initVector(vectorNumber
, vector
);
299 //---------------------------------------------------------------------------
302 void AppleIntelClassicPIC::disableVectorHard(long vectorNumber
,
303 IOInterruptVector
* vector
)
305 // Sorry, cacade/slave interrupt line cannot be disable.
307 if (vectorNumber
== kPICSlaveID
) return;
309 disableInterrupt(vectorNumber
);
312 //---------------------------------------------------------------------------
315 void AppleIntelClassicPIC::enableVector(long vectorNumber
,
316 IOInterruptVector
* vector
)
318 enableInterrupt(vectorNumber
);