2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
39 #include <ppc/proc_reg.h>
42 #include <IOKit/IOLib.h>
43 #include <IOKit/IOService.h>
44 #include <IOKit/IOPlatformExpert.h>
45 #include <IOKit/IODeviceTreeSupport.h>
46 #include <IOKit/IOInterrupts.h>
47 #include <IOKit/IOInterruptController.h>
50 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
52 #define super IOService
54 OSDefineMetaClassAndAbstractStructors(IOInterruptController
, IOService
);
56 OSMetaClassDefineReservedUnused(IOInterruptController
, 0);
57 OSMetaClassDefineReservedUnused(IOInterruptController
, 1);
58 OSMetaClassDefineReservedUnused(IOInterruptController
, 2);
59 OSMetaClassDefineReservedUnused(IOInterruptController
, 3);
60 OSMetaClassDefineReservedUnused(IOInterruptController
, 4);
61 OSMetaClassDefineReservedUnused(IOInterruptController
, 5);
63 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
65 IOReturn
IOInterruptController::registerInterrupt(IOService
*nub
, int source
,
67 IOInterruptHandler handler
,
70 IOInterruptSource
*interruptSources
;
72 IOInterruptVector
*vector
;
76 IOService
*originalNub
;
79 bool canBeShared
, shouldBeShared
, wasAlreadyRegisterd
;
81 interruptSources
= nub
->_interruptSources
;
82 vectorData
= interruptSources
[source
].vectorData
;
83 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
84 vector
= &vectors
[vectorNumber
];
86 // Get the lock for this vector.
87 IOTakeLock(vector
->interruptLock
);
89 // Check if the interrupt source can/should be shared.
90 canBeShared
= vectorCanBeShared(vectorNumber
, vector
);
91 IODTGetInterruptOptions(nub
, source
, &options
);
92 shouldBeShared
= canBeShared
&& (options
& kIODTInterruptShared
);
93 wasAlreadyRegisterd
= vector
->interruptRegistered
;
95 // If the vector is registered and can not be shared return error.
96 if (wasAlreadyRegisterd
&& !canBeShared
) {
97 IOUnlock(vector
->interruptLock
);
98 return kIOReturnNoResources
;
101 // If this vector is already in use, and can be shared (implied),
102 // or it is not registered and should be shared,
103 // register as a shared interrupt.
104 if (wasAlreadyRegisterd
|| shouldBeShared
) {
105 // If this vector is not already shared, break it out.
106 if (vector
->sharedController
== 0) {
107 // Make the IOShareInterruptController instance
108 vector
->sharedController
= new IOSharedInterruptController
;
109 if (vector
->sharedController
== 0) {
110 IOUnlock(vector
->interruptLock
);
111 return kIOReturnNoMemory
;
114 if (wasAlreadyRegisterd
) {
115 // Save the nub and source for the original consumer.
116 originalNub
= vector
->nub
;
117 originalSource
= vector
->source
;
119 // Physically disable the interrupt, but mark it as being enabled in the hardware.
120 // The interruptDisabledSoft now indicates the driver's request for enablement.
121 disableVectorHard(vectorNumber
, vector
);
122 vector
->interruptDisabledHard
= 0;
125 // Initialize the new shared interrupt controller.
126 error
= vector
->sharedController
->initInterruptController(this, vectorData
);
127 // If the IOSharedInterruptController could not be initalized,
128 // if needed, put the original consumer's interrupt back to normal and
129 // get rid of whats left of the shared controller.
130 if (error
!= kIOReturnSuccess
) {
131 if (wasAlreadyRegisterd
) enableInterrupt(originalNub
, originalSource
);
132 vector
->sharedController
->release();
133 vector
->sharedController
= 0;
134 IOUnlock(vector
->interruptLock
);
138 // If there was an original consumer try to register it on the shared controller.
139 if (wasAlreadyRegisterd
) {
140 error
= vector
->sharedController
->registerInterrupt(originalNub
,
145 // If the original consumer could not be moved to the shared controller,
146 // put the original consumor's interrupt back to normal and
147 // get rid of whats left of the shared controller.
148 if (error
!= kIOReturnSuccess
) {
149 // Save the driver's interrupt enablement state.
150 wasDisabledSoft
= vector
->interruptDisabledSoft
;
152 // Make the interrupt really hard disabled.
153 vector
->interruptDisabledSoft
= 1;
154 vector
->interruptDisabledHard
= 1;
156 // Enable the original consumer's interrupt if needed.
157 if (!wasDisabledSoft
) originalNub
->enableInterrupt(originalSource
);
158 enableInterrupt(originalNub
, originalSource
);
160 vector
->sharedController
->release();
161 vector
->sharedController
= 0;
162 IOUnlock(vector
->interruptLock
);
167 // Fill in vector with the shared controller's info.
168 vector
->handler
= (IOInterruptHandler
)vector
->sharedController
->getInterruptHandlerAddress();
169 vector
->nub
= vector
->sharedController
;
171 vector
->target
= vector
->sharedController
;
174 // If the interrupt was already registered,
175 // save the driver's interrupt enablement state.
176 if (wasAlreadyRegisterd
) wasDisabledSoft
= vector
->interruptDisabledSoft
;
177 else wasDisabledSoft
= true;
179 // Do any specific initalization for this vector if it has not yet been used.
180 if (!wasAlreadyRegisterd
) initVector(vectorNumber
, vector
);
182 // Make the interrupt really hard disabled.
183 vector
->interruptDisabledSoft
= 1;
184 vector
->interruptDisabledHard
= 1;
185 vector
->interruptRegistered
= 1;
187 // Enable the original consumer's interrupt if needed.
188 if (!wasDisabledSoft
) originalNub
->enableInterrupt(originalSource
);
191 error
= vector
->sharedController
->registerInterrupt(nub
, source
, target
,
193 IOUnlock(vector
->interruptLock
);
197 // Fill in vector with the client's info.
198 vector
->handler
= handler
;
200 vector
->source
= source
;
201 vector
->target
= target
;
202 vector
->refCon
= refCon
;
204 // Do any specific initalization for this vector.
205 initVector(vectorNumber
, vector
);
207 // Get the vector ready. It starts hard disabled.
208 vector
->interruptDisabledHard
= 1;
209 vector
->interruptDisabledSoft
= 1;
210 vector
->interruptRegistered
= 1;
212 IOUnlock(vector
->interruptLock
);
213 return kIOReturnSuccess
;
216 IOReturn
IOInterruptController::unregisterInterrupt(IOService
*nub
, int source
)
218 IOInterruptSource
*interruptSources
;
220 IOInterruptVector
*vector
;
223 interruptSources
= nub
->_interruptSources
;
224 vectorData
= interruptSources
[source
].vectorData
;
225 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
226 vector
= &vectors
[vectorNumber
];
228 // Get the lock for this vector.
229 IOTakeLock(vector
->interruptLock
);
231 // Return success if it is not already registered
232 if (!vector
->interruptRegistered
) {
233 IOUnlock(vector
->interruptLock
);
234 return kIOReturnSuccess
;
237 // Soft disable the source.
238 disableInterrupt(nub
, source
);
240 // Turn the source off at hardware.
241 disableVectorHard(vectorNumber
, vector
);
243 // Clear all the storage for the vector except for interruptLock.
244 vector
->interruptActive
= 0;
245 vector
->interruptDisabledSoft
= 0;
246 vector
->interruptDisabledHard
= 0;
247 vector
->interruptRegistered
= 0;
254 IOUnlock(vector
->interruptLock
);
255 return kIOReturnSuccess
;
258 IOReturn
IOInterruptController::getInterruptType(IOService
*nub
, int source
,
261 IOInterruptSource
*interruptSources
;
263 IOInterruptVector
*vector
;
266 if (interruptType
== 0) return kIOReturnBadArgument
;
268 interruptSources
= nub
->_interruptSources
;
269 vectorData
= interruptSources
[source
].vectorData
;
270 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
271 vector
= &vectors
[vectorNumber
];
273 *interruptType
= getVectorType(vectorNumber
, vector
);
275 return kIOReturnSuccess
;
278 IOReturn
IOInterruptController::enableInterrupt(IOService
*nub
, int source
)
280 IOInterruptSource
*interruptSources
;
282 IOInterruptVector
*vector
;
285 interruptSources
= nub
->_interruptSources
;
286 vectorData
= interruptSources
[source
].vectorData
;
287 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
288 vector
= &vectors
[vectorNumber
];
290 if (vector
->interruptDisabledSoft
) {
291 vector
->interruptDisabledSoft
= 0;
297 if (!getPlatform()->atInterruptLevel()) {
298 while (vector
->interruptActive
);
303 if (vector
->interruptDisabledHard
) {
304 vector
->interruptDisabledHard
= 0;
306 enableVector(vectorNumber
, vector
);
310 return kIOReturnSuccess
;
313 IOReturn
IOInterruptController::disableInterrupt(IOService
*nub
, int source
)
315 IOInterruptSource
*interruptSources
;
317 IOInterruptVector
*vector
;
320 interruptSources
= nub
->_interruptSources
;
321 vectorData
= interruptSources
[source
].vectorData
;
322 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
323 vector
= &vectors
[vectorNumber
];
325 vector
->interruptDisabledSoft
= 1;
331 if (!getPlatform()->atInterruptLevel()) {
332 while (vector
->interruptActive
);
338 return kIOReturnSuccess
;
341 IOReturn
IOInterruptController::causeInterrupt(IOService
*nub
, int source
)
343 IOInterruptSource
*interruptSources
;
345 IOInterruptVector
*vector
;
348 interruptSources
= nub
->_interruptSources
;
349 vectorData
= interruptSources
[source
].vectorData
;
350 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
351 vector
= &vectors
[vectorNumber
];
353 causeVector(vectorNumber
, vector
);
355 return kIOReturnSuccess
;
358 IOInterruptAction
IOInterruptController::getInterruptHandlerAddress(void)
363 IOReturn
IOInterruptController::handleInterrupt(void *refCon
, IOService
*nub
,
366 return kIOReturnInvalid
;
370 // Methods to be overridden for simplifed interrupt controller subclasses.
372 bool IOInterruptController::vectorCanBeShared(long /*vectorNumber*/,
373 IOInterruptVector */
*vector*/
)
378 void IOInterruptController::initVector(long /*vectorNumber*/,
379 IOInterruptVector */
*vector*/
)
383 int IOInterruptController::getVectorType(long /*vectorNumber*/,
384 IOInterruptVector */
*vector*/
)
386 return kIOInterruptTypeEdge
;
389 void IOInterruptController::disableVectorHard(long /*vectorNumber*/,
390 IOInterruptVector */
*vector*/
)
394 void IOInterruptController::enableVector(long /*vectorNumber*/,
395 IOInterruptVector */
*vector*/
)
399 void IOInterruptController::causeVector(long /*vectorNumber*/,
400 IOInterruptVector */
*vector*/
)
405 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
408 #define super IOInterruptController
410 OSDefineMetaClassAndStructors(IOSharedInterruptController
, IOInterruptController
);
412 OSMetaClassDefineReservedUnused(IOSharedInterruptController
, 0);
413 OSMetaClassDefineReservedUnused(IOSharedInterruptController
, 1);
414 OSMetaClassDefineReservedUnused(IOSharedInterruptController
, 2);
415 OSMetaClassDefineReservedUnused(IOSharedInterruptController
, 3);
417 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
419 #define kIOSharedInterruptControllerDefaultVectors (128)
421 IOReturn
IOSharedInterruptController::initInterruptController(IOInterruptController
*parentController
, OSData
*parentSource
)
423 int cnt
, interruptType
;
427 return kIOReturnNoResources
;
429 // Set provider to this so enable/disable nub stuff works.
432 // Allocate the IOInterruptSource so this can act like a nub.
433 _interruptSources
= (IOInterruptSource
*)IOMalloc(sizeof(IOInterruptSource
));
434 if (_interruptSources
== 0) return kIOReturnNoMemory
;
435 _numInterruptSources
= 1;
437 // Set up the IOInterruptSource to point at this.
438 parentController
->retain();
439 parentSource
->retain();
440 _interruptSources
[0].interruptController
= parentController
;
441 _interruptSources
[0].vectorData
= parentSource
;
443 sourceIsLevel
= false;
444 error
= provider
->getInterruptType(0, &interruptType
);
445 if (error
== kIOReturnSuccess
) {
446 if (interruptType
& kIOInterruptTypeLevel
)
447 sourceIsLevel
= true;
450 // Allocate the memory for the vectors
451 numVectors
= kIOSharedInterruptControllerDefaultVectors
; // For now a constant number.
452 vectors
= (IOInterruptVector
*)IOMalloc(numVectors
* sizeof(IOInterruptVector
));
453 if (vectors
== NULL
) {
454 IOFree(_interruptSources
, sizeof(IOInterruptSource
));
455 return kIOReturnNoMemory
;
457 bzero(vectors
, numVectors
* sizeof(IOInterruptVector
));
459 // Allocate the lock for the controller.
460 controllerLock
= IOSimpleLockAlloc();
461 if (controllerLock
== 0) return kIOReturnNoResources
;
463 // Allocate locks for the vectors.
464 for (cnt
= 0; cnt
< numVectors
; cnt
++) {
465 vectors
[cnt
].interruptLock
= IOLockAlloc();
466 if (vectors
[cnt
].interruptLock
== NULL
) {
467 for (cnt
= 0; cnt
< numVectors
; cnt
++) {
468 if (vectors
[cnt
].interruptLock
!= NULL
)
469 IOLockFree(vectors
[cnt
].interruptLock
);
471 return kIOReturnNoResources
;
475 numVectors
= 0; // reset the high water mark for used vectors
476 vectorsRegistered
= 0;
478 controllerDisabled
= 1;
480 return kIOReturnSuccess
;
483 IOReturn
IOSharedInterruptController::registerInterrupt(IOService
*nub
,
486 IOInterruptHandler handler
,
489 IOInterruptSource
*interruptSources
;
491 IOInterruptVector
*vector
= 0;
493 IOInterruptState interruptState
;
495 interruptSources
= nub
->_interruptSources
;
497 // Find a free vector.
498 vectorNumber
= kIOSharedInterruptControllerDefaultVectors
;
499 while (vectorsRegistered
!= kIOSharedInterruptControllerDefaultVectors
) {
500 for (vectorNumber
= 0; vectorNumber
< kIOSharedInterruptControllerDefaultVectors
; vectorNumber
++) {
501 vector
= &vectors
[vectorNumber
];
503 // Get the lock for this vector.
504 IOTakeLock(vector
->interruptLock
);
506 // Is it unregistered?
507 if (!vector
->interruptRegistered
) break;
509 // Move along to the next one.
510 IOUnlock(vector
->interruptLock
);
513 if (vectorNumber
!= kIOSharedInterruptControllerDefaultVectors
) break;
516 // Could not find a free one, so give up.
517 if (vectorNumber
== kIOSharedInterruptControllerDefaultVectors
) {
518 return kIOReturnNoResources
;
521 // Create the vectorData for the IOInterruptSource.
522 vectorData
= OSData::withBytes(&vectorNumber
, sizeof(vectorNumber
));
523 if (vectorData
== 0) {
524 return kIOReturnNoMemory
;
527 // Fill in the IOInterruptSource with the controller's info.
528 interruptSources
[source
].interruptController
= this;
529 interruptSources
[source
].vectorData
= vectorData
;
531 // Fill in vector with the client's info.
532 vector
->handler
= handler
;
534 vector
->source
= source
;
535 vector
->target
= target
;
536 vector
->refCon
= refCon
;
538 // Get the vector ready. It starts off soft disabled.
539 vector
->interruptDisabledSoft
= 1;
540 vector
->interruptRegistered
= 1;
542 interruptState
= IOSimpleLockLockDisableInterrupt(controllerLock
);
543 // Move the high water mark if needed
544 if (++vectorsRegistered
> numVectors
) numVectors
= vectorsRegistered
;
545 IOSimpleLockUnlockEnableInterrupt(controllerLock
, interruptState
);
547 IOUnlock(vector
->interruptLock
);
548 return kIOReturnSuccess
;
551 IOReturn
IOSharedInterruptController::unregisterInterrupt(IOService
*nub
,
554 IOInterruptSource
*interruptSources
;
556 IOInterruptVector
*vector
;
558 IOInterruptState interruptState
;
560 interruptSources
= nub
->_interruptSources
;
561 vectorData
= interruptSources
[source
].vectorData
;
562 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
563 vector
= &vectors
[vectorNumber
];
565 // Get the lock for this vector.
566 IOTakeLock(vector
->interruptLock
);
568 // Return success if it is not already registered
569 if (!vector
->interruptRegistered
) {
570 IOUnlock(vector
->interruptLock
);
571 return kIOReturnSuccess
;
574 // Soft disable the source and the controller too.
575 disableInterrupt(nub
, source
);
577 // Clear all the storage for the vector except for interruptLock.
578 vector
->interruptActive
= 0;
579 vector
->interruptDisabledSoft
= 0;
580 vector
->interruptDisabledHard
= 0;
581 vector
->interruptRegistered
= 0;
588 interruptState
= IOSimpleLockLockDisableInterrupt(controllerLock
);
590 IOSimpleLockUnlockEnableInterrupt(controllerLock
, interruptState
);
592 IOUnlock(vector
->interruptLock
);
594 // Re-enable the controller if all vectors are enabled.
595 if (vectorsEnabled
== vectorsRegistered
) {
596 controllerDisabled
= 0;
597 provider
->enableInterrupt(0);
600 return kIOReturnSuccess
;
603 IOReturn
IOSharedInterruptController::getInterruptType(IOService */
*nub*/
,
607 return provider
->getInterruptType(0, interruptType
);
610 IOReturn
IOSharedInterruptController::enableInterrupt(IOService
*nub
,
613 IOInterruptSource
*interruptSources
;
615 IOInterruptVector
*vector
;
617 IOInterruptState interruptState
;
619 interruptSources
= nub
->_interruptSources
;
620 vectorData
= interruptSources
[source
].vectorData
;
621 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
622 vector
= &vectors
[vectorNumber
];
624 interruptState
= IOSimpleLockLockDisableInterrupt(controllerLock
);
625 if (!vector
->interruptDisabledSoft
) {
626 IOSimpleLockUnlockEnableInterrupt(controllerLock
, interruptState
);
627 return kIOReturnSuccess
;
630 vector
->interruptDisabledSoft
= 0;
632 IOSimpleLockUnlockEnableInterrupt(controllerLock
, interruptState
);
634 if (controllerDisabled
&& (vectorsEnabled
== vectorsRegistered
)) {
635 controllerDisabled
= 0;
636 provider
->enableInterrupt(0);
639 return kIOReturnSuccess
;
642 IOReturn
IOSharedInterruptController::disableInterrupt(IOService
*nub
,
645 IOInterruptSource
*interruptSources
;
647 IOInterruptVector
*vector
;
649 IOInterruptState interruptState
;
651 interruptSources
= nub
->_interruptSources
;
652 vectorData
= interruptSources
[source
].vectorData
;
653 vectorNumber
= *(long *)vectorData
->getBytesNoCopy();
654 vector
= &vectors
[vectorNumber
];
656 interruptState
= IOSimpleLockLockDisableInterrupt(controllerLock
);
657 if (!vector
->interruptDisabledSoft
) {
658 vector
->interruptDisabledSoft
= 1;
665 IOSimpleLockUnlockEnableInterrupt(controllerLock
, interruptState
);
667 if (!getPlatform()->atInterruptLevel()) {
668 while (vector
->interruptActive
);
674 return kIOReturnSuccess
;
677 IOInterruptAction
IOSharedInterruptController::getInterruptHandlerAddress(void)
679 return OSMemberFunctionCast(IOInterruptAction
,
680 this, &IOSharedInterruptController::handleInterrupt
);
683 IOReturn
IOSharedInterruptController::handleInterrupt(void * /*refCon*/,
688 IOInterruptVector
*vector
;
690 for (vectorNumber
= 0; vectorNumber
< numVectors
; vectorNumber
++) {
691 vector
= &vectors
[vectorNumber
];
693 vector
->interruptActive
= 1;
698 if (!vector
->interruptDisabledSoft
) {
703 // Call the handler if it exists.
704 if (vector
->interruptRegistered
) {
705 vector
->handler(vector
->target
, vector
->refCon
,
706 vector
->nub
, vector
->source
);
710 vector
->interruptActive
= 0;
713 // if any of the vectors are dissabled, then dissable this controller.
714 IOSimpleLockLock(controllerLock
);
715 if (vectorsEnabled
!= vectorsRegistered
) {
716 nub
->disableInterrupt(0);
717 controllerDisabled
= 1;
719 IOSimpleLockUnlock(controllerLock
);
721 return kIOReturnSuccess
;