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.
31 #include <ppc/proc_reg.h>
34 #include <IOKit/IOLib.h>
35 #include <IOKit/IOService.h>
36 #include <IOKit/IOPlatformExpert.h>
37 #include <IOKit/IOInterrupts.h>
38 #include <IOKit/IOInterruptController.h>
41 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
43 #define super IOService
45 OSDefineMetaClassAndAbstractStructors(IOInterruptController
, IOService
);
47 OSMetaClassDefineReservedUnused(IOInterruptController
, 0);
48 OSMetaClassDefineReservedUnused(IOInterruptController
, 1);
49 OSMetaClassDefineReservedUnused(IOInterruptController
, 2);
50 OSMetaClassDefineReservedUnused(IOInterruptController
, 3);
51 OSMetaClassDefineReservedUnused(IOInterruptController
, 4);
52 OSMetaClassDefineReservedUnused(IOInterruptController
, 5);
54 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
56 IOReturn
IOInterruptController::registerInterrupt(IOService
*nub
, int source
,
58 IOInterruptHandler handler
,
61 IOInterruptSource
*interruptSources
;
63 IOInterruptVector
*vector
;
67 IOService
*originalNub
;
70 interruptSources
= nub
->_interruptSources
;
71 vectorData
= interruptSources
[source
].vectorData
;
72 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
73 vector
= &vectors
[vectorNumber
];
75 // Get the lock for this vector.
76 IOTakeLock(vector
->interruptLock
);
78 // If this vector is already in use, and can be shared,
79 // register as a shared interrupt.
80 if (vector
->interruptRegistered
) {
81 if (!vectorCanBeShared(vectorNumber
, vector
)) {
82 IOUnlock(vector
->interruptLock
);
83 return kIOReturnNoResources
;
86 // If this vector is not already shared, break it out.
87 if (vector
->sharedController
== 0) {
88 // Make the IOShareInterruptController instance
89 vector
->sharedController
= new IOSharedInterruptController
;
90 if (vector
->sharedController
== 0) {
91 IOUnlock(vector
->interruptLock
);
92 return kIOReturnNoMemory
;
95 // Save the nub and source for the original consumer.
96 originalNub
= vector
->nub
;
97 originalSource
= vector
->source
;
99 // Save the dis/enable state for the original consumer's interrupt.
100 // Then disable the source
101 wasDisabledSoft
= vector
->interruptDisabledSoft
;
102 disableInterrupt(originalNub
, originalSource
);
104 // Initialize the new shared interrupt controller.
105 error
= vector
->sharedController
->initInterruptController(this,
107 // If the IOSharedInterruptController could not be initalized,
108 // put the original consumor's interrupt back to normal and
109 // get rid of whats left of the shared controller.
110 if (error
!= kIOReturnSuccess
) {
111 enableInterrupt(originalNub
, originalSource
);
112 vector
->sharedController
->release();
113 vector
->sharedController
= 0;
114 IOUnlock(vector
->interruptLock
);
118 // Try to register the original consumer on the shared controller.
119 error
= vector
->sharedController
->registerInterrupt(originalNub
,
124 // If the original consumer could not be moved to the shared controller,
125 // put the original consumor's interrupt back to normal and
126 // get rid of whats left of the shared controller.
127 if (error
!= kIOReturnSuccess
) {
128 enableInterrupt(originalNub
, originalSource
);
129 vector
->sharedController
->release();
130 vector
->sharedController
= 0;
131 IOUnlock(vector
->interruptLock
);
135 // Fill in vector with the shared controller's info.
136 vector
->handler
= (IOInterruptHandler
)vector
->sharedController
->getInterruptHandlerAddress();
137 vector
->nub
= vector
->sharedController
;
139 vector
->target
= vector
->sharedController
;
142 // Enable the original consumer's interrupt if needed.
143 if (!wasDisabledSoft
) originalNub
->enableInterrupt(originalSource
);
146 error
= vector
->sharedController
->registerInterrupt(nub
, source
, target
,
148 IOUnlock(vector
->interruptLock
);
152 // Fill in vector with the client's info.
153 vector
->handler
= handler
;
155 vector
->source
= source
;
156 vector
->target
= target
;
157 vector
->refCon
= refCon
;
159 // Do any specific initalization for this vector.
160 initVector(vectorNumber
, vector
);
162 // Get the vector ready. It starts hard disabled.
163 vector
->interruptDisabledHard
= 1;
164 vector
->interruptDisabledSoft
= 1;
165 vector
->interruptRegistered
= 1;
167 IOUnlock(vector
->interruptLock
);
168 return kIOReturnSuccess
;
171 IOReturn
IOInterruptController::unregisterInterrupt(IOService
*nub
, int source
)
173 IOInterruptSource
*interruptSources
;
175 IOInterruptVector
*vector
;
178 interruptSources
= nub
->_interruptSources
;
179 vectorData
= interruptSources
[source
].vectorData
;
180 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
181 vector
= &vectors
[vectorNumber
];
183 // Get the lock for this vector.
184 IOTakeLock(vector
->interruptLock
);
186 // Return success if it is not already registered
187 if (!vector
->interruptRegistered
) {
188 IOUnlock(vector
->interruptLock
);
189 return kIOReturnSuccess
;
192 // Soft disable the source.
193 disableInterrupt(nub
, source
);
195 // Turn the source off at hardware.
196 disableVectorHard(vectorNumber
, vector
);
198 // Clear all the storage for the vector except for interruptLock.
199 vector
->interruptActive
= 0;
200 vector
->interruptDisabledSoft
= 0;
201 vector
->interruptDisabledHard
= 0;
202 vector
->interruptRegistered
= 0;
209 IOUnlock(vector
->interruptLock
);
210 return kIOReturnSuccess
;
213 IOReturn
IOInterruptController::getInterruptType(IOService
*nub
, int source
,
216 IOInterruptSource
*interruptSources
;
218 IOInterruptVector
*vector
;
221 if (interruptType
== 0) return kIOReturnBadArgument
;
223 interruptSources
= nub
->_interruptSources
;
224 vectorData
= interruptSources
[source
].vectorData
;
225 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
226 vector
= &vectors
[vectorNumber
];
228 *interruptType
= getVectorType(vectorNumber
, vector
);
230 return kIOReturnSuccess
;
233 IOReturn
IOInterruptController::enableInterrupt(IOService
*nub
, int source
)
235 IOInterruptSource
*interruptSources
;
237 IOInterruptVector
*vector
;
240 interruptSources
= nub
->_interruptSources
;
241 vectorData
= interruptSources
[source
].vectorData
;
242 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
243 vector
= &vectors
[vectorNumber
];
245 if (vector
->interruptDisabledSoft
) {
246 vector
->interruptDisabledSoft
= 0;
248 if (vector
->interruptDisabledHard
) {
249 vector
->interruptDisabledHard
= 0;
251 enableVector(vectorNumber
, vector
);
255 return kIOReturnSuccess
;
258 IOReturn
IOInterruptController::disableInterrupt(IOService
*nub
, int source
)
260 IOInterruptSource
*interruptSources
;
262 IOInterruptVector
*vector
;
265 interruptSources
= nub
->_interruptSources
;
266 vectorData
= interruptSources
[source
].vectorData
;
267 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
268 vector
= &vectors
[vectorNumber
];
270 vector
->interruptDisabledSoft
= 1;
276 if (!getPlatform()->atInterruptLevel()) {
277 while (vector
->interruptActive
);
283 return kIOReturnSuccess
;
286 IOReturn
IOInterruptController::causeInterrupt(IOService
*nub
, int source
)
288 IOInterruptSource
*interruptSources
;
290 IOInterruptVector
*vector
;
293 interruptSources
= nub
->_interruptSources
;
294 vectorData
= interruptSources
[source
].vectorData
;
295 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
296 vector
= &vectors
[vectorNumber
];
298 causeVector(vectorNumber
, vector
);
300 return kIOReturnSuccess
;
303 IOInterruptAction
IOInterruptController::getInterruptHandlerAddress(void)
308 IOReturn
IOInterruptController::handleInterrupt(void *refCon
, IOService
*nub
,
311 return kIOReturnInvalid
;
315 // Methods to be overridden for simplifed interrupt controller subclasses.
317 bool IOInterruptController::vectorCanBeShared(long /*vectorNumber*/,
318 IOInterruptVector */
*vector*/
)
323 void IOInterruptController::initVector(long /*vectorNumber*/,
324 IOInterruptVector */
*vector*/
)
328 int IOInterruptController::getVectorType(long /*vectorNumber*/,
329 IOInterruptVector */
*vector*/
)
331 return kIOInterruptTypeEdge
;
334 void IOInterruptController::disableVectorHard(long /*vectorNumber*/,
335 IOInterruptVector */
*vector*/
)
339 void IOInterruptController::enableVector(long /*vectorNumber*/,
340 IOInterruptVector */
*vector*/
)
344 void IOInterruptController::causeVector(long /*vectorNumber*/,
345 IOInterruptVector */
*vector*/
)
350 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
353 #define super IOInterruptController
355 OSDefineMetaClassAndStructors(IOSharedInterruptController
, IOInterruptController
);
357 OSMetaClassDefineReservedUnused(IOSharedInterruptController
, 0);
358 OSMetaClassDefineReservedUnused(IOSharedInterruptController
, 1);
359 OSMetaClassDefineReservedUnused(IOSharedInterruptController
, 2);
360 OSMetaClassDefineReservedUnused(IOSharedInterruptController
, 3);
362 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
364 IOReturn
IOSharedInterruptController::initInterruptController(IOInterruptController
*parentController
, OSData
*parentSource
)
366 int cnt
, interruptType
;
370 return kIOReturnNoResources
;
372 // Set provider to this so enable/disable nub stuff works.
375 // Allocate the IOInterruptSource so this can act like a nub.
376 _interruptSources
= (IOInterruptSource
*)IOMalloc(sizeof(IOInterruptSource
));
377 if (_interruptSources
== 0) return kIOReturnNoMemory
;
378 _numInterruptSources
= 1;
380 // Set up the IOInterruptSource to point at this.
381 _interruptSources
[0].interruptController
= parentController
;
382 _interruptSources
[0].vectorData
= parentSource
;
384 sourceIsLevel
= false;
385 error
= provider
->getInterruptType(0, &interruptType
);
386 if (error
== kIOReturnSuccess
) {
387 if (interruptType
& kIOInterruptTypeLevel
)
388 sourceIsLevel
= true;
391 // Allocate the memory for the vectors
392 numVectors
= 8; // For now a constant number.
393 vectors
= (IOInterruptVector
*)IOMalloc(numVectors
* sizeof(IOInterruptVector
));
394 if (vectors
== NULL
) {
395 IOFree(_interruptSources
, sizeof(IOInterruptSource
));
396 return kIOReturnNoMemory
;
398 bzero(vectors
, numVectors
* sizeof(IOInterruptVector
));
400 // Allocate the lock for the controller.
401 controllerLock
= IOSimpleLockAlloc();
402 if (controllerLock
== 0) return kIOReturnNoResources
;
404 // Allocate locks for the vectors.
405 for (cnt
= 0; cnt
< numVectors
; cnt
++) {
406 vectors
[cnt
].interruptLock
= IOLockAlloc();
407 if (vectors
[cnt
].interruptLock
== NULL
) {
408 for (cnt
= 0; cnt
< numVectors
; cnt
++) {
409 if (vectors
[cnt
].interruptLock
!= NULL
)
410 IOLockFree(vectors
[cnt
].interruptLock
);
412 return kIOReturnNoResources
;
416 vectorsRegistered
= 0;
418 controllerDisabled
= 1;
420 return kIOReturnSuccess
;
423 IOReturn
IOSharedInterruptController::registerInterrupt(IOService
*nub
,
426 IOInterruptHandler handler
,
429 IOInterruptSource
*interruptSources
;
431 IOInterruptVector
*vector
= 0;
433 IOInterruptState interruptState
;
435 interruptSources
= nub
->_interruptSources
;
437 // Find a free vector.
438 vectorNumber
= numVectors
;
439 while (vectorsRegistered
!= numVectors
) {
440 for (vectorNumber
= 0; vectorNumber
< numVectors
; vectorNumber
++) {
441 vector
= &vectors
[vectorNumber
];
443 // Get the lock for this vector.
444 IOTakeLock(vector
->interruptLock
);
446 // Is it unregistered?
447 if (!vector
->interruptRegistered
) break;
449 // Move along to the next one.
450 IOUnlock(vector
->interruptLock
);
453 if (vectorNumber
!= numVectors
) break;
456 // Could not find a free one, so give up.
457 if (vectorNumber
== numVectors
) {
458 return kIOReturnNoResources
;
461 // Create the vectorData for the IOInterruptSource.
462 vectorData
= OSData::withBytes(&vectorNumber
, sizeof(vectorNumber
));
463 if (vectorData
== 0) {
464 return kIOReturnNoMemory
;
467 // Fill in the IOInterruptSource with the controller's info.
468 interruptSources
[source
].interruptController
= this;
469 interruptSources
[source
].vectorData
= vectorData
;
471 // Fill in vector with the client's info.
472 vector
->handler
= handler
;
474 vector
->source
= source
;
475 vector
->target
= target
;
476 vector
->refCon
= refCon
;
478 // Get the vector ready. It start soft disabled.
479 vector
->interruptDisabledSoft
= 1;
480 vector
->interruptRegistered
= 1;
482 interruptState
= IOSimpleLockLockDisableInterrupt(controllerLock
);
484 IOSimpleLockUnlockEnableInterrupt(controllerLock
, interruptState
);
486 IOUnlock(vector
->interruptLock
);
487 return kIOReturnSuccess
;
490 IOReturn
IOSharedInterruptController::unregisterInterrupt(IOService
*nub
,
493 IOInterruptSource
*interruptSources
;
495 IOInterruptVector
*vector
;
497 IOInterruptState interruptState
;;
499 interruptSources
= nub
->_interruptSources
;
500 vectorData
= interruptSources
[source
].vectorData
;
501 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
502 vector
= &vectors
[vectorNumber
];
504 // Get the lock for this vector.
505 IOTakeLock(vector
->interruptLock
);
507 // Return success if it is not already registered
508 if (!vector
->interruptRegistered
) {
509 IOUnlock(vector
->interruptLock
);
510 return kIOReturnSuccess
;
513 // Soft disable the source.
514 disableInterrupt(nub
, source
);
516 // Clear all the storage for the vector except for interruptLock.
517 vector
->interruptActive
= 0;
518 vector
->interruptDisabledSoft
= 0;
519 vector
->interruptDisabledHard
= 0;
520 vector
->interruptRegistered
= 0;
527 interruptState
= IOSimpleLockLockDisableInterrupt(controllerLock
);
529 IOSimpleLockUnlockEnableInterrupt(controllerLock
, interruptState
);
531 IOUnlock(vector
->interruptLock
);
532 return kIOReturnSuccess
;
535 IOReturn
IOSharedInterruptController::getInterruptType(IOService */
*nub*/
,
539 return provider
->getInterruptType(0, interruptType
);
542 IOReturn
IOSharedInterruptController::enableInterrupt(IOService
*nub
,
545 IOInterruptSource
*interruptSources
;
547 IOInterruptVector
*vector
;
549 IOInterruptState interruptState
;;
551 interruptSources
= nub
->_interruptSources
;
552 vectorData
= interruptSources
[source
].vectorData
;
553 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
554 vector
= &vectors
[vectorNumber
];
556 if (vector
->interruptDisabledSoft
) {
557 vector
->interruptDisabledSoft
= 0;
559 interruptState
= IOSimpleLockLockDisableInterrupt(controllerLock
);
561 IOSimpleLockUnlockEnableInterrupt(controllerLock
, interruptState
);
563 if (controllerDisabled
&& (vectorsEnabled
== vectorsRegistered
)) {
564 controllerDisabled
= 0;
565 provider
->enableInterrupt(0);
569 return kIOReturnSuccess
;
572 IOReturn
IOSharedInterruptController::disableInterrupt(IOService
*nub
,
575 IOInterruptSource
*interruptSources
;
577 IOInterruptVector
*vector
;
579 IOInterruptState interruptState
;;
581 interruptSources
= nub
->_interruptSources
;
582 vectorData
= interruptSources
[source
].vectorData
;
583 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
584 vector
= &vectors
[vectorNumber
];
586 if (!vector
->interruptDisabledSoft
) {
587 vector
->interruptDisabledSoft
= 1;
593 interruptState
= IOSimpleLockLockDisableInterrupt(controllerLock
);
595 IOSimpleLockUnlockEnableInterrupt(controllerLock
, interruptState
);
598 if (!getPlatform()->atInterruptLevel()) {
599 while (vector
->interruptActive
);
605 return kIOReturnSuccess
;
608 IOInterruptAction
IOSharedInterruptController::getInterruptHandlerAddress(void)
610 return (IOInterruptAction
)&IOSharedInterruptController::handleInterrupt
;
613 IOReturn
IOSharedInterruptController::handleInterrupt(void * /*refCon*/,
618 IOInterruptVector
*vector
;
620 for (vectorNumber
= 0; vectorNumber
< numVectors
; vectorNumber
++) {
621 vector
= &vectors
[vectorNumber
];
623 vector
->interruptActive
= 1;
628 if (!vector
->interruptDisabledSoft
) {
633 // Call the handler if it exists.
634 if (vector
->interruptRegistered
) {
635 vector
->handler(vector
->target
, vector
->refCon
,
636 vector
->nub
, vector
->source
);
640 vector
->interruptActive
= 0;
643 // if any of the vectors are dissabled, then dissable this controller.
644 IOSimpleLockLock(controllerLock
);
645 if (vectorsEnabled
!= vectorsRegistered
) {
646 nub
->disableInterrupt(0);
647 controllerDisabled
= 1;
649 IOSimpleLockUnlock(controllerLock
);
651 return kIOReturnSuccess
;