2 * Copyright (c) 1998-2008 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
37 #include <ppc/proc_reg.h>
40 #include <IOKit/IOLib.h>
41 #include <IOKit/IOService.h>
42 #include <IOKit/IOPlatformExpert.h>
43 #include <IOKit/IODeviceTreeSupport.h>
44 #include <IOKit/IOInterrupts.h>
45 #include <IOKit/IOInterruptController.h>
47 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
49 #define super IOService
51 OSDefineMetaClassAndAbstractStructors(IOInterruptController
, IOService
);
53 OSMetaClassDefineReservedUnused(IOInterruptController
, 0);
54 OSMetaClassDefineReservedUnused(IOInterruptController
, 1);
55 OSMetaClassDefineReservedUnused(IOInterruptController
, 2);
56 OSMetaClassDefineReservedUnused(IOInterruptController
, 3);
57 OSMetaClassDefineReservedUnused(IOInterruptController
, 4);
58 OSMetaClassDefineReservedUnused(IOInterruptController
, 5);
60 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
62 IOReturn
IOInterruptController::registerInterrupt(IOService
*nub
, int source
,
64 IOInterruptHandler handler
,
67 IOInterruptSource
*interruptSources
;
68 IOInterruptVectorNumber vectorNumber
;
69 IOInterruptVector
*vector
;
74 bool canBeShared
, shouldBeShared
, wasAlreadyRegisterd
;
76 IOService
*originalNub
= NULL
; // Protected by wasAlreadyRegisterd
77 int originalSource
= 0; // Protected by wasAlreadyRegisterd
80 interruptSources
= nub
->_interruptSources
;
81 vectorData
= interruptSources
[source
].vectorData
;
82 vectorNumber
= *(IOInterruptVectorNumber
*)vectorData
->getBytesNoCopy();
83 vector
= &vectors
[vectorNumber
];
85 // Get the lock for this vector.
86 IOTakeLock(vector
->interruptLock
);
88 // Check if the interrupt source can/should be shared.
89 canBeShared
= vectorCanBeShared(vectorNumber
, vector
);
90 IODTGetInterruptOptions(nub
, source
, &options
);
91 #if defined(__i386__) || defined(__x86_64__)
93 if (OSDynamicCast(IOPlatformDevice
, getProvider()) &&
94 (getInterruptType(nub
, source
, &interruptType
) == kIOReturnSuccess
) &&
95 (kIOInterruptTypeLevel
& interruptType
))
97 options
|= kIODTInterruptShared
;
100 shouldBeShared
= canBeShared
&& (options
& kIODTInterruptShared
);
101 wasAlreadyRegisterd
= vector
->interruptRegistered
;
103 // If the vector is registered and can not be shared return error.
104 if (wasAlreadyRegisterd
&& !canBeShared
) {
105 IOUnlock(vector
->interruptLock
);
106 return kIOReturnNoResources
;
109 // If this vector is already in use, and can be shared (implied),
110 // or it is not registered and should be shared,
111 // register as a shared interrupt.
112 if (wasAlreadyRegisterd
|| shouldBeShared
) {
113 // If this vector is not already shared, break it out.
114 if (vector
->sharedController
== 0) {
115 // Make the IOShareInterruptController instance
116 vector
->sharedController
= new IOSharedInterruptController
;
117 if (vector
->sharedController
== 0) {
118 IOUnlock(vector
->interruptLock
);
119 return kIOReturnNoMemory
;
122 if (wasAlreadyRegisterd
) {
123 // Save the nub and source for the original consumer.
124 originalNub
= vector
->nub
;
125 originalSource
= vector
->source
;
127 // Physically disable the interrupt, but mark it as being enabled in the hardware.
128 // The interruptDisabledSoft now indicates the driver's request for enablement.
129 disableVectorHard(vectorNumber
, vector
);
130 vector
->interruptDisabledHard
= 0;
133 // Initialize the new shared interrupt controller.
134 error
= vector
->sharedController
->initInterruptController(this, vectorData
);
135 // If the IOSharedInterruptController could not be initalized,
136 // if needed, put the original consumer's interrupt back to normal and
137 // get rid of whats left of the shared controller.
138 if (error
!= kIOReturnSuccess
) {
139 if (wasAlreadyRegisterd
) enableInterrupt(originalNub
, originalSource
);
140 vector
->sharedController
->release();
141 vector
->sharedController
= 0;
142 IOUnlock(vector
->interruptLock
);
146 // If there was an original consumer try to register it on the shared controller.
147 if (wasAlreadyRegisterd
) {
148 error
= vector
->sharedController
->registerInterrupt(originalNub
,
153 // If the original consumer could not be moved to the shared controller,
154 // put the original consumor's interrupt back to normal and
155 // get rid of whats left of the shared controller.
156 if (error
!= kIOReturnSuccess
) {
157 // Save the driver's interrupt enablement state.
158 wasDisabledSoft
= vector
->interruptDisabledSoft
;
160 // Make the interrupt really hard disabled.
161 vector
->interruptDisabledSoft
= 1;
162 vector
->interruptDisabledHard
= 1;
164 // Enable the original consumer's interrupt if needed.
165 if (!wasDisabledSoft
) originalNub
->enableInterrupt(originalSource
);
166 enableInterrupt(originalNub
, originalSource
);
168 vector
->sharedController
->release();
169 vector
->sharedController
= 0;
170 IOUnlock(vector
->interruptLock
);
175 // Fill in vector with the shared controller's info.
176 vector
->handler
= (IOInterruptHandler
)vector
->sharedController
->getInterruptHandlerAddress();
177 vector
->nub
= vector
->sharedController
;
179 vector
->target
= vector
->sharedController
;
182 // If the interrupt was already registered,
183 // save the driver's interrupt enablement state.
184 if (wasAlreadyRegisterd
) wasDisabledSoft
= vector
->interruptDisabledSoft
;
185 else wasDisabledSoft
= true;
187 // Do any specific initalization for this vector if it has not yet been used.
188 if (!wasAlreadyRegisterd
) initVector(vectorNumber
, vector
);
190 // Make the interrupt really hard disabled.
191 vector
->interruptDisabledSoft
= 1;
192 vector
->interruptDisabledHard
= 1;
193 vector
->interruptRegistered
= 1;
195 // Enable the original consumer's interrupt if needed.
196 // originalNub is protected by wasAlreadyRegisterd here (see line 184).
197 if (!wasDisabledSoft
) originalNub
->enableInterrupt(originalSource
);
200 error
= vector
->sharedController
->registerInterrupt(nub
, source
, target
,
202 IOUnlock(vector
->interruptLock
);
206 // Fill in vector with the client's info.
207 vector
->handler
= handler
;
209 vector
->source
= source
;
210 vector
->target
= target
;
211 vector
->refCon
= refCon
;
213 // Do any specific initalization for this vector.
214 initVector(vectorNumber
, vector
);
216 // Get the vector ready. It starts hard disabled.
217 vector
->interruptDisabledHard
= 1;
218 vector
->interruptDisabledSoft
= 1;
219 vector
->interruptRegistered
= 1;
221 IOUnlock(vector
->interruptLock
);
222 return kIOReturnSuccess
;
225 IOReturn
IOInterruptController::unregisterInterrupt(IOService
*nub
, int source
)
227 IOInterruptSource
*interruptSources
;
228 IOInterruptVectorNumber vectorNumber
;
229 IOInterruptVector
*vector
;
232 interruptSources
= nub
->_interruptSources
;
233 vectorData
= interruptSources
[source
].vectorData
;
234 vectorNumber
= *(IOInterruptVectorNumber
*)vectorData
->getBytesNoCopy();
235 vector
= &vectors
[vectorNumber
];
237 // Get the lock for this vector.
238 IOTakeLock(vector
->interruptLock
);
240 // Return success if it is not already registered
241 if (!vector
->interruptRegistered
) {
242 IOUnlock(vector
->interruptLock
);
243 return kIOReturnSuccess
;
246 // Soft disable the source.
247 disableInterrupt(nub
, source
);
249 // Turn the source off at hardware.
250 disableVectorHard(vectorNumber
, vector
);
252 // Clear all the storage for the vector except for interruptLock.
253 vector
->interruptActive
= 0;
254 vector
->interruptDisabledSoft
= 0;
255 vector
->interruptDisabledHard
= 0;
256 vector
->interruptRegistered
= 0;
263 IOUnlock(vector
->interruptLock
);
264 return kIOReturnSuccess
;
267 IOReturn
IOInterruptController::getInterruptType(IOService
*nub
, int source
,
270 IOInterruptSource
*interruptSources
;
271 IOInterruptVectorNumber vectorNumber
;
272 IOInterruptVector
*vector
;
275 if (interruptType
== 0) return kIOReturnBadArgument
;
277 interruptSources
= nub
->_interruptSources
;
278 vectorData
= interruptSources
[source
].vectorData
;
279 vectorNumber
= *(IOInterruptVectorNumber
*)vectorData
->getBytesNoCopy();
280 vector
= &vectors
[vectorNumber
];
282 *interruptType
= getVectorType(vectorNumber
, vector
);
284 return kIOReturnSuccess
;
287 IOReturn
IOInterruptController::enableInterrupt(IOService
*nub
, int source
)
289 IOInterruptSource
*interruptSources
;
290 IOInterruptVectorNumber vectorNumber
;
291 IOInterruptVector
*vector
;
294 interruptSources
= nub
->_interruptSources
;
295 vectorData
= interruptSources
[source
].vectorData
;
296 vectorNumber
= *(IOInterruptVectorNumber
*)vectorData
->getBytesNoCopy();
297 vector
= &vectors
[vectorNumber
];
299 if (vector
->interruptDisabledSoft
) {
300 vector
->interruptDisabledSoft
= 0;
306 if (!getPlatform()->atInterruptLevel()) {
307 while (vector
->interruptActive
)
313 if (vector
->interruptDisabledHard
) {
314 vector
->interruptDisabledHard
= 0;
316 enableVector(vectorNumber
, vector
);
320 return kIOReturnSuccess
;
323 IOReturn
IOInterruptController::disableInterrupt(IOService
*nub
, int source
)
325 IOInterruptSource
*interruptSources
;
326 IOInterruptVectorNumber vectorNumber
;
327 IOInterruptVector
*vector
;
330 interruptSources
= nub
->_interruptSources
;
331 vectorData
= interruptSources
[source
].vectorData
;
332 vectorNumber
= *(IOInterruptVectorNumber
*)vectorData
->getBytesNoCopy();
333 vector
= &vectors
[vectorNumber
];
335 vector
->interruptDisabledSoft
= 1;
341 if (!getPlatform()->atInterruptLevel()) {
342 while (vector
->interruptActive
)
349 return kIOReturnSuccess
;
352 IOReturn
IOInterruptController::causeInterrupt(IOService
*nub
, int source
)
354 IOInterruptSource
*interruptSources
;
355 IOInterruptVectorNumber vectorNumber
;
356 IOInterruptVector
*vector
;
359 interruptSources
= nub
->_interruptSources
;
360 vectorData
= interruptSources
[source
].vectorData
;
361 vectorNumber
= *(IOInterruptVectorNumber
*)vectorData
->getBytesNoCopy();
362 vector
= &vectors
[vectorNumber
];
364 causeVector(vectorNumber
, vector
);
366 return kIOReturnSuccess
;
369 IOInterruptAction
IOInterruptController::getInterruptHandlerAddress(void)
374 IOReturn
IOInterruptController::handleInterrupt(void *refCon
, IOService
*nub
,
377 return kIOReturnInvalid
;
381 // Methods to be overridden for simplifed interrupt controller subclasses.
383 bool IOInterruptController::vectorCanBeShared(IOInterruptVectorNumber
/*vectorNumber*/,
384 IOInterruptVector */
*vector*/
)
389 void IOInterruptController::initVector(IOInterruptVectorNumber
/*vectorNumber*/,
390 IOInterruptVector */
*vector*/
)
394 int IOInterruptController::getVectorType(IOInterruptVectorNumber
/*vectorNumber*/,
395 IOInterruptVector */
*vector*/
)
397 return kIOInterruptTypeEdge
;
400 void IOInterruptController::disableVectorHard(IOInterruptVectorNumber
/*vectorNumber*/,
401 IOInterruptVector */
*vector*/
)
405 void IOInterruptController::enableVector(IOInterruptVectorNumber
/*vectorNumber*/,
406 IOInterruptVector */
*vector*/
)
410 void IOInterruptController::causeVector(IOInterruptVectorNumber
/*vectorNumber*/,
411 IOInterruptVector */
*vector*/
)
416 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
419 #define super IOInterruptController
421 OSDefineMetaClassAndStructors(IOSharedInterruptController
, IOInterruptController
);
423 OSMetaClassDefineReservedUnused(IOSharedInterruptController
, 0);
424 OSMetaClassDefineReservedUnused(IOSharedInterruptController
, 1);
425 OSMetaClassDefineReservedUnused(IOSharedInterruptController
, 2);
426 OSMetaClassDefineReservedUnused(IOSharedInterruptController
, 3);
428 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
430 #define kIOSharedInterruptControllerDefaultVectors (128)
432 IOReturn
IOSharedInterruptController::initInterruptController(IOInterruptController
*parentController
, OSData
*parentSource
)
434 int cnt
, interruptType
;
438 return kIOReturnNoResources
;
440 // Set provider to this so enable/disable nub stuff works.
443 // Allocate the IOInterruptSource so this can act like a nub.
444 _interruptSources
= (IOInterruptSource
*)IOMalloc(sizeof(IOInterruptSource
));
445 if (_interruptSources
== 0) return kIOReturnNoMemory
;
446 _numInterruptSources
= 1;
448 // Set up the IOInterruptSource to point at this.
449 parentController
->retain();
450 parentSource
->retain();
451 _interruptSources
[0].interruptController
= parentController
;
452 _interruptSources
[0].vectorData
= parentSource
;
454 sourceIsLevel
= false;
455 error
= provider
->getInterruptType(0, &interruptType
);
456 if (error
== kIOReturnSuccess
) {
457 if (interruptType
& kIOInterruptTypeLevel
)
458 sourceIsLevel
= true;
461 // Allocate the memory for the vectors
462 numVectors
= kIOSharedInterruptControllerDefaultVectors
; // For now a constant number.
463 vectors
= (IOInterruptVector
*)IOMalloc(numVectors
* sizeof(IOInterruptVector
));
464 if (vectors
== NULL
) {
465 IOFree(_interruptSources
, sizeof(IOInterruptSource
));
466 return kIOReturnNoMemory
;
468 bzero(vectors
, numVectors
* sizeof(IOInterruptVector
));
470 // Allocate the lock for the controller.
471 controllerLock
= IOSimpleLockAlloc();
472 if (controllerLock
== 0) return kIOReturnNoResources
;
474 // Allocate locks for the vectors.
475 for (cnt
= 0; cnt
< numVectors
; cnt
++) {
476 vectors
[cnt
].interruptLock
= IOLockAlloc();
477 if (vectors
[cnt
].interruptLock
== NULL
) {
478 for (cnt
= 0; cnt
< numVectors
; cnt
++) {
479 if (vectors
[cnt
].interruptLock
!= NULL
)
480 IOLockFree(vectors
[cnt
].interruptLock
);
482 return kIOReturnNoResources
;
486 numVectors
= 0; // reset the high water mark for used vectors
487 vectorsRegistered
= 0;
489 controllerDisabled
= 1;
491 return kIOReturnSuccess
;
494 IOReturn
IOSharedInterruptController::registerInterrupt(IOService
*nub
,
497 IOInterruptHandler handler
,
500 IOInterruptSource
*interruptSources
;
501 IOInterruptVectorNumber vectorNumber
;
502 IOInterruptVector
*vector
= 0;
504 IOInterruptState interruptState
;
506 interruptSources
= nub
->_interruptSources
;
508 // Find a free vector.
509 vectorNumber
= kIOSharedInterruptControllerDefaultVectors
;
510 while (vectorsRegistered
!= kIOSharedInterruptControllerDefaultVectors
) {
511 for (vectorNumber
= 0; vectorNumber
< kIOSharedInterruptControllerDefaultVectors
; vectorNumber
++) {
512 vector
= &vectors
[vectorNumber
];
514 // Get the lock for this vector.
515 IOTakeLock(vector
->interruptLock
);
517 // Is it unregistered?
518 if (!vector
->interruptRegistered
) break;
520 // Move along to the next one.
521 IOUnlock(vector
->interruptLock
);
524 if (vectorNumber
!= kIOSharedInterruptControllerDefaultVectors
) break;
527 // Could not find a free one, so give up.
528 if (vectorNumber
== kIOSharedInterruptControllerDefaultVectors
) {
529 return kIOReturnNoResources
;
532 // Create the vectorData for the IOInterruptSource.
533 vectorData
= OSData::withBytes(&vectorNumber
, sizeof(vectorNumber
));
534 if (vectorData
== 0) {
535 return kIOReturnNoMemory
;
538 // Fill in the IOInterruptSource with the controller's info.
539 interruptSources
[source
].interruptController
= this;
540 interruptSources
[source
].vectorData
= vectorData
;
542 // Fill in vector with the client's info.
543 vector
->handler
= handler
;
545 vector
->source
= source
;
546 vector
->target
= target
;
547 vector
->refCon
= refCon
;
549 // Get the vector ready. It starts off soft disabled.
550 vector
->interruptDisabledSoft
= 1;
551 vector
->interruptRegistered
= 1;
553 interruptState
= IOSimpleLockLockDisableInterrupt(controllerLock
);
554 // Move the high water mark if needed
555 if (++vectorsRegistered
> numVectors
) numVectors
= vectorsRegistered
;
556 IOSimpleLockUnlockEnableInterrupt(controllerLock
, interruptState
);
558 IOUnlock(vector
->interruptLock
);
559 return kIOReturnSuccess
;
562 IOReturn
IOSharedInterruptController::unregisterInterrupt(IOService
*nub
,
565 IOInterruptVectorNumber vectorNumber
;
566 IOInterruptVector
*vector
;
567 IOInterruptState interruptState
;
569 for (vectorNumber
= 0; vectorNumber
< kIOSharedInterruptControllerDefaultVectors
; vectorNumber
++) {
570 vector
= &vectors
[vectorNumber
];
572 // Get the lock for this vector.
573 IOTakeLock(vector
->interruptLock
);
575 // Return success if it is not already registered
576 if (!vector
->interruptRegistered
577 || (vector
->nub
!= nub
) || (vector
->source
!= source
)) {
578 IOUnlock(vector
->interruptLock
);
582 // Soft disable the source and the controller too.
583 disableInterrupt(nub
, source
);
585 // Clear all the storage for the vector except for interruptLock.
586 vector
->interruptActive
= 0;
587 vector
->interruptDisabledSoft
= 0;
588 vector
->interruptDisabledHard
= 0;
589 vector
->interruptRegistered
= 0;
596 interruptState
= IOSimpleLockLockDisableInterrupt(controllerLock
);
598 IOSimpleLockUnlockEnableInterrupt(controllerLock
, interruptState
);
600 // Move along to the next one.
601 IOUnlock(vector
->interruptLock
);
604 // Re-enable the controller if all vectors are enabled.
605 if (vectorsEnabled
== vectorsRegistered
) {
606 controllerDisabled
= 0;
607 provider
->enableInterrupt(0);
610 return kIOReturnSuccess
;
613 IOReturn
IOSharedInterruptController::getInterruptType(IOService */
*nub*/
,
617 return provider
->getInterruptType(0, interruptType
);
620 IOReturn
IOSharedInterruptController::enableInterrupt(IOService
*nub
,
623 IOInterruptSource
*interruptSources
;
624 IOInterruptVectorNumber vectorNumber
;
625 IOInterruptVector
*vector
;
627 IOInterruptState interruptState
;
629 interruptSources
= nub
->_interruptSources
;
630 vectorData
= interruptSources
[source
].vectorData
;
631 vectorNumber
= *(IOInterruptVectorNumber
*)vectorData
->getBytesNoCopy();
632 vector
= &vectors
[vectorNumber
];
634 interruptState
= IOSimpleLockLockDisableInterrupt(controllerLock
);
635 if (!vector
->interruptDisabledSoft
) {
636 IOSimpleLockUnlockEnableInterrupt(controllerLock
, interruptState
);
637 return kIOReturnSuccess
;
640 vector
->interruptDisabledSoft
= 0;
642 IOSimpleLockUnlockEnableInterrupt(controllerLock
, interruptState
);
644 if (controllerDisabled
&& (vectorsEnabled
== vectorsRegistered
)) {
645 controllerDisabled
= 0;
646 provider
->enableInterrupt(0);
649 return kIOReturnSuccess
;
652 IOReturn
IOSharedInterruptController::disableInterrupt(IOService
*nub
,
655 IOInterruptSource
*interruptSources
;
656 IOInterruptVectorNumber vectorNumber
;
657 IOInterruptVector
*vector
;
659 IOInterruptState interruptState
;
661 interruptSources
= nub
->_interruptSources
;
662 vectorData
= interruptSources
[source
].vectorData
;
663 vectorNumber
= *(IOInterruptVectorNumber
*)vectorData
->getBytesNoCopy();
664 vector
= &vectors
[vectorNumber
];
666 interruptState
= IOSimpleLockLockDisableInterrupt(controllerLock
);
667 if (!vector
->interruptDisabledSoft
) {
668 vector
->interruptDisabledSoft
= 1;
675 IOSimpleLockUnlockEnableInterrupt(controllerLock
, interruptState
);
677 if (!getPlatform()->atInterruptLevel()) {
678 while (vector
->interruptActive
)
685 return kIOReturnSuccess
;
688 IOInterruptAction
IOSharedInterruptController::getInterruptHandlerAddress(void)
690 return OSMemberFunctionCast(IOInterruptAction
,
691 this, &IOSharedInterruptController::handleInterrupt
);
694 IOReturn
IOSharedInterruptController::handleInterrupt(void * /*refCon*/,
698 IOInterruptVectorNumber vectorNumber
;
699 IOInterruptVector
*vector
;
701 for (vectorNumber
= 0; vectorNumber
< numVectors
; vectorNumber
++) {
702 vector
= &vectors
[vectorNumber
];
704 vector
->interruptActive
= 1;
709 if (!vector
->interruptDisabledSoft
) {
714 // Call the handler if it exists.
715 if (vector
->interruptRegistered
) {
716 vector
->handler(vector
->target
, vector
->refCon
,
717 vector
->nub
, vector
->source
);
721 vector
->interruptActive
= 0;
724 // if any of the vectors are dissabled, then dissable this controller.
725 IOSimpleLockLock(controllerLock
);
726 if (vectorsEnabled
!= vectorsRegistered
) {
727 nub
->disableInterrupt(0);
728 controllerDisabled
= 1;
730 IOSimpleLockUnlock(controllerLock
);
732 return kIOReturnSuccess
;