]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOInterruptController.cpp
xnu-344.49.tar.gz
[apple/xnu.git] / iokit / Kernel / IOInterruptController.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
27 *
28 * DRI: Josh de Cesare
29 *
30 */
31
32
33 #if __ppc__
34 #include <ppc/proc_reg.h>
35 #endif
36
37 #include <IOKit/IOLib.h>
38 #include <IOKit/IOService.h>
39 #include <IOKit/IOPlatformExpert.h>
40 #include <IOKit/IOInterrupts.h>
41 #include <IOKit/IOInterruptController.h>
42
43
44 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
45
46 #define super IOService
47
48 OSDefineMetaClassAndAbstractStructors(IOInterruptController, IOService);
49
50 OSMetaClassDefineReservedUnused(IOInterruptController, 0);
51 OSMetaClassDefineReservedUnused(IOInterruptController, 1);
52 OSMetaClassDefineReservedUnused(IOInterruptController, 2);
53 OSMetaClassDefineReservedUnused(IOInterruptController, 3);
54 OSMetaClassDefineReservedUnused(IOInterruptController, 4);
55 OSMetaClassDefineReservedUnused(IOInterruptController, 5);
56
57 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
58
59 IOReturn IOInterruptController::registerInterrupt(IOService *nub, int source,
60 void *target,
61 IOInterruptHandler handler,
62 void *refCon)
63 {
64 IOInterruptSource *interruptSources;
65 long vectorNumber;
66 IOInterruptVector *vector;
67 long wasDisabledSoft;
68 IOReturn error;
69 OSData *vectorData;
70 IOService *originalNub;
71 int originalSource;
72
73 interruptSources = nub->_interruptSources;
74 vectorData = interruptSources[source].vectorData;
75 vectorNumber = *(long *)vectorData->getBytesNoCopy();
76 vector = &vectors[vectorNumber];
77
78 // Get the lock for this vector.
79 IOTakeLock(vector->interruptLock);
80
81 // If this vector is already in use, and can be shared,
82 // register as a shared interrupt.
83 if (vector->interruptRegistered) {
84 if (!vectorCanBeShared(vectorNumber, vector)) {
85 IOUnlock(vector->interruptLock);
86 return kIOReturnNoResources;
87 }
88
89 // If this vector is not already shared, break it out.
90 if (vector->sharedController == 0) {
91 // Make the IOShareInterruptController instance
92 vector->sharedController = new IOSharedInterruptController;
93 if (vector->sharedController == 0) {
94 IOUnlock(vector->interruptLock);
95 return kIOReturnNoMemory;
96 }
97
98 // Save the nub and source for the original consumer.
99 originalNub = vector->nub;
100 originalSource = vector->source;
101
102 // Physically disable the interrupt, but mark it as being enables in the hardware.
103 // The interruptDisabledSoft now indicates the driver's request for enablement.
104 disableVectorHard(vectorNumber, vector);
105 vector->interruptDisabledHard = 0;
106
107 // Initialize the new shared interrupt controller.
108 error = vector->sharedController->initInterruptController(this,
109 vectorData);
110 // If the IOSharedInterruptController could not be initalized,
111 // put the original consumor's interrupt back to normal and
112 // get rid of whats left of the shared controller.
113 if (error != kIOReturnSuccess) {
114 enableInterrupt(originalNub, originalSource);
115 vector->sharedController->release();
116 vector->sharedController = 0;
117 IOUnlock(vector->interruptLock);
118 return error;
119 }
120
121 // Try to register the original consumer on the shared controller.
122 error = vector->sharedController->registerInterrupt(originalNub,
123 originalSource,
124 vector->target,
125 vector->handler,
126 vector->refCon);
127 // If the original consumer could not be moved to the shared controller,
128 // put the original consumor's interrupt back to normal and
129 // get rid of whats left of the shared controller.
130 if (error != kIOReturnSuccess) {
131 // Save the driver's interrupt enablement state.
132 wasDisabledSoft = vector->interruptDisabledSoft;
133
134 // Make the interrupt really hard disabled.
135 vector->interruptDisabledSoft = 1;
136 vector->interruptDisabledHard = 1;
137
138 // Enable the original consumer's interrupt if needed.
139 if (!wasDisabledSoft) originalNub->enableInterrupt(originalSource);
140 enableInterrupt(originalNub, originalSource);
141
142 vector->sharedController->release();
143 vector->sharedController = 0;
144 IOUnlock(vector->interruptLock);
145 return error;
146 }
147
148 // Fill in vector with the shared controller's info.
149 vector->handler = (IOInterruptHandler)vector->sharedController->getInterruptHandlerAddress();
150 vector->nub = vector->sharedController;
151 vector->source = 0;
152 vector->target = vector->sharedController;
153 vector->refCon = 0;
154
155 // Save the driver's interrupt enablement state.
156 wasDisabledSoft = vector->interruptDisabledSoft;
157
158 // Make the interrupt really hard disabled.
159 vector->interruptDisabledSoft = 1;
160 vector->interruptDisabledHard = 1;
161
162 // Enable the original consumer's interrupt if needed.
163 if (!wasDisabledSoft) originalNub->enableInterrupt(originalSource);
164 }
165
166 error = vector->sharedController->registerInterrupt(nub, source, target,
167 handler, refCon);
168 IOUnlock(vector->interruptLock);
169 return error;
170 }
171
172 // Fill in vector with the client's info.
173 vector->handler = handler;
174 vector->nub = nub;
175 vector->source = source;
176 vector->target = target;
177 vector->refCon = refCon;
178
179 // Do any specific initalization for this vector.
180 initVector(vectorNumber, vector);
181
182 // Get the vector ready. It starts hard disabled.
183 vector->interruptDisabledHard = 1;
184 vector->interruptDisabledSoft = 1;
185 vector->interruptRegistered = 1;
186
187 IOUnlock(vector->interruptLock);
188 return kIOReturnSuccess;
189 }
190
191 IOReturn IOInterruptController::unregisterInterrupt(IOService *nub, int source)
192 {
193 IOInterruptSource *interruptSources;
194 long vectorNumber;
195 IOInterruptVector *vector;
196 OSData *vectorData;
197
198 interruptSources = nub->_interruptSources;
199 vectorData = interruptSources[source].vectorData;
200 vectorNumber = *(long *)vectorData->getBytesNoCopy();
201 vector = &vectors[vectorNumber];
202
203 // Get the lock for this vector.
204 IOTakeLock(vector->interruptLock);
205
206 // Return success if it is not already registered
207 if (!vector->interruptRegistered) {
208 IOUnlock(vector->interruptLock);
209 return kIOReturnSuccess;
210 }
211
212 // Soft disable the source.
213 disableInterrupt(nub, source);
214
215 // Turn the source off at hardware.
216 disableVectorHard(vectorNumber, vector);
217
218 // Clear all the storage for the vector except for interruptLock.
219 vector->interruptActive = 0;
220 vector->interruptDisabledSoft = 0;
221 vector->interruptDisabledHard = 0;
222 vector->interruptRegistered = 0;
223 vector->nub = 0;
224 vector->source = 0;
225 vector->handler = 0;
226 vector->target = 0;
227 vector->refCon = 0;
228
229 IOUnlock(vector->interruptLock);
230 return kIOReturnSuccess;
231 }
232
233 IOReturn IOInterruptController::getInterruptType(IOService *nub, int source,
234 int *interruptType)
235 {
236 IOInterruptSource *interruptSources;
237 long vectorNumber;
238 IOInterruptVector *vector;
239 OSData *vectorData;
240
241 if (interruptType == 0) return kIOReturnBadArgument;
242
243 interruptSources = nub->_interruptSources;
244 vectorData = interruptSources[source].vectorData;
245 vectorNumber = *(long *)vectorData->getBytesNoCopy();
246 vector = &vectors[vectorNumber];
247
248 *interruptType = getVectorType(vectorNumber, vector);
249
250 return kIOReturnSuccess;
251 }
252
253 IOReturn IOInterruptController::enableInterrupt(IOService *nub, int source)
254 {
255 IOInterruptSource *interruptSources;
256 long vectorNumber;
257 IOInterruptVector *vector;
258 OSData *vectorData;
259
260 interruptSources = nub->_interruptSources;
261 vectorData = interruptSources[source].vectorData;
262 vectorNumber = *(long *)vectorData->getBytesNoCopy();
263 vector = &vectors[vectorNumber];
264
265 if (vector->interruptDisabledSoft) {
266 vector->interruptDisabledSoft = 0;
267 #if __ppc__
268 sync();
269 isync();
270 #endif
271
272 if (!getPlatform()->atInterruptLevel()) {
273 while (vector->interruptActive);
274 #if __ppc__
275 isync();
276 #endif
277 }
278 if (vector->interruptDisabledHard) {
279 vector->interruptDisabledHard = 0;
280
281 enableVector(vectorNumber, vector);
282 }
283 }
284
285 return kIOReturnSuccess;
286 }
287
288 IOReturn IOInterruptController::disableInterrupt(IOService *nub, int source)
289 {
290 IOInterruptSource *interruptSources;
291 long vectorNumber;
292 IOInterruptVector *vector;
293 OSData *vectorData;
294
295 interruptSources = nub->_interruptSources;
296 vectorData = interruptSources[source].vectorData;
297 vectorNumber = *(long *)vectorData->getBytesNoCopy();
298 vector = &vectors[vectorNumber];
299
300 vector->interruptDisabledSoft = 1;
301 #if __ppc__
302 sync();
303 isync();
304 #endif
305
306 if (!getPlatform()->atInterruptLevel()) {
307 while (vector->interruptActive);
308 #if __ppc__
309 isync();
310 #endif
311 }
312
313 return kIOReturnSuccess;
314 }
315
316 IOReturn IOInterruptController::causeInterrupt(IOService *nub, int source)
317 {
318 IOInterruptSource *interruptSources;
319 long vectorNumber;
320 IOInterruptVector *vector;
321 OSData *vectorData;
322
323 interruptSources = nub->_interruptSources;
324 vectorData = interruptSources[source].vectorData;
325 vectorNumber = *(long *)vectorData->getBytesNoCopy();
326 vector = &vectors[vectorNumber];
327
328 causeVector(vectorNumber, vector);
329
330 return kIOReturnSuccess;
331 }
332
333 IOInterruptAction IOInterruptController::getInterruptHandlerAddress(void)
334 {
335 return 0;
336 }
337
338 IOReturn IOInterruptController::handleInterrupt(void *refCon, IOService *nub,
339 int source)
340 {
341 return kIOReturnInvalid;
342 }
343
344
345 // Methods to be overridden for simplifed interrupt controller subclasses.
346
347 bool IOInterruptController::vectorCanBeShared(long /*vectorNumber*/,
348 IOInterruptVector */*vector*/)
349 {
350 return false;
351 }
352
353 void IOInterruptController::initVector(long /*vectorNumber*/,
354 IOInterruptVector */*vector*/)
355 {
356 }
357
358 int IOInterruptController::getVectorType(long /*vectorNumber*/,
359 IOInterruptVector */*vector*/)
360 {
361 return kIOInterruptTypeEdge;
362 }
363
364 void IOInterruptController::disableVectorHard(long /*vectorNumber*/,
365 IOInterruptVector */*vector*/)
366 {
367 }
368
369 void IOInterruptController::enableVector(long /*vectorNumber*/,
370 IOInterruptVector */*vector*/)
371 {
372 }
373
374 void IOInterruptController::causeVector(long /*vectorNumber*/,
375 IOInterruptVector */*vector*/)
376 {
377 }
378
379
380 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
381
382 #undef super
383 #define super IOInterruptController
384
385 OSDefineMetaClassAndStructors(IOSharedInterruptController, IOInterruptController);
386
387 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 0);
388 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 1);
389 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 2);
390 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 3);
391
392 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
393
394 IOReturn IOSharedInterruptController::initInterruptController(IOInterruptController *parentController, OSData *parentSource)
395 {
396 int cnt, interruptType;
397 IOReturn error;
398
399 if (!super::init())
400 return kIOReturnNoResources;
401
402 // Set provider to this so enable/disable nub stuff works.
403 provider = this;
404
405 // Allocate the IOInterruptSource so this can act like a nub.
406 _interruptSources = (IOInterruptSource *)IOMalloc(sizeof(IOInterruptSource));
407 if (_interruptSources == 0) return kIOReturnNoMemory;
408 _numInterruptSources = 1;
409
410 // Set up the IOInterruptSource to point at this.
411 _interruptSources[0].interruptController = parentController;
412 _interruptSources[0].vectorData = parentSource;
413
414 sourceIsLevel = false;
415 error = provider->getInterruptType(0, &interruptType);
416 if (error == kIOReturnSuccess) {
417 if (interruptType & kIOInterruptTypeLevel)
418 sourceIsLevel = true;
419 }
420
421 // Allocate the memory for the vectors
422 numVectors = 32; // For now a constant number.
423 vectors = (IOInterruptVector *)IOMalloc(numVectors * sizeof(IOInterruptVector));
424 if (vectors == NULL) {
425 IOFree(_interruptSources, sizeof(IOInterruptSource));
426 return kIOReturnNoMemory;
427 }
428 bzero(vectors, numVectors * sizeof(IOInterruptVector));
429
430 // Allocate the lock for the controller.
431 controllerLock = IOSimpleLockAlloc();
432 if (controllerLock == 0) return kIOReturnNoResources;
433
434 // Allocate locks for the vectors.
435 for (cnt = 0; cnt < numVectors; cnt++) {
436 vectors[cnt].interruptLock = IOLockAlloc();
437 if (vectors[cnt].interruptLock == NULL) {
438 for (cnt = 0; cnt < numVectors; cnt++) {
439 if (vectors[cnt].interruptLock != NULL)
440 IOLockFree(vectors[cnt].interruptLock);
441 }
442 return kIOReturnNoResources;
443 }
444 }
445
446 vectorsRegistered = 0;
447 vectorsEnabled = 0;
448 controllerDisabled = 1;
449
450 return kIOReturnSuccess;
451 }
452
453 IOReturn IOSharedInterruptController::registerInterrupt(IOService *nub,
454 int source,
455 void *target,
456 IOInterruptHandler handler,
457 void *refCon)
458 {
459 IOInterruptSource *interruptSources;
460 long vectorNumber;
461 IOInterruptVector *vector = 0;
462 OSData *vectorData;
463 IOInterruptState interruptState;
464
465 interruptSources = nub->_interruptSources;
466
467 // Find a free vector.
468 vectorNumber = numVectors;
469 while (vectorsRegistered != numVectors) {
470 for (vectorNumber = 0; vectorNumber < numVectors; vectorNumber++) {
471 vector = &vectors[vectorNumber];
472
473 // Get the lock for this vector.
474 IOTakeLock(vector->interruptLock);
475
476 // Is it unregistered?
477 if (!vector->interruptRegistered) break;
478
479 // Move along to the next one.
480 IOUnlock(vector->interruptLock);
481 }
482
483 if (vectorNumber != numVectors) break;
484 }
485
486 // Could not find a free one, so give up.
487 if (vectorNumber == numVectors) {
488 return kIOReturnNoResources;
489 }
490
491 // Create the vectorData for the IOInterruptSource.
492 vectorData = OSData::withBytes(&vectorNumber, sizeof(vectorNumber));
493 if (vectorData == 0) {
494 return kIOReturnNoMemory;
495 }
496
497 // Fill in the IOInterruptSource with the controller's info.
498 interruptSources[source].interruptController = this;
499 interruptSources[source].vectorData = vectorData;
500
501 // Fill in vector with the client's info.
502 vector->handler = handler;
503 vector->nub = nub;
504 vector->source = source;
505 vector->target = target;
506 vector->refCon = refCon;
507
508 // Get the vector ready. It start soft disabled.
509 vector->interruptDisabledSoft = 1;
510 vector->interruptRegistered = 1;
511
512 interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
513 vectorsRegistered++;
514 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
515
516 IOUnlock(vector->interruptLock);
517 return kIOReturnSuccess;
518 }
519
520 IOReturn IOSharedInterruptController::unregisterInterrupt(IOService *nub,
521 int source)
522 {
523 IOInterruptSource *interruptSources;
524 long vectorNumber;
525 IOInterruptVector *vector;
526 OSData *vectorData;
527 IOInterruptState interruptState;;
528
529 interruptSources = nub->_interruptSources;
530 vectorData = interruptSources[source].vectorData;
531 vectorNumber = *(long *)vectorData->getBytesNoCopy();
532 vector = &vectors[vectorNumber];
533
534 // Get the lock for this vector.
535 IOTakeLock(vector->interruptLock);
536
537 // Return success if it is not already registered
538 if (!vector->interruptRegistered) {
539 IOUnlock(vector->interruptLock);
540 return kIOReturnSuccess;
541 }
542
543 // Soft disable the source.
544 disableInterrupt(nub, source);
545
546 // Clear all the storage for the vector except for interruptLock.
547 vector->interruptActive = 0;
548 vector->interruptDisabledSoft = 0;
549 vector->interruptDisabledHard = 0;
550 vector->interruptRegistered = 0;
551 vector->nub = 0;
552 vector->source = 0;
553 vector->handler = 0;
554 vector->target = 0;
555 vector->refCon = 0;
556
557 interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
558 vectorsRegistered--;
559 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
560
561 IOUnlock(vector->interruptLock);
562 return kIOReturnSuccess;
563 }
564
565 IOReturn IOSharedInterruptController::getInterruptType(IOService */*nub*/,
566 int /*source*/,
567 int *interruptType)
568 {
569 return provider->getInterruptType(0, interruptType);
570 }
571
572 IOReturn IOSharedInterruptController::enableInterrupt(IOService *nub,
573 int source)
574 {
575 IOInterruptSource *interruptSources;
576 long vectorNumber;
577 IOInterruptVector *vector;
578 OSData *vectorData;
579 IOInterruptState interruptState;
580
581 interruptSources = nub->_interruptSources;
582 vectorData = interruptSources[source].vectorData;
583 vectorNumber = *(long *)vectorData->getBytesNoCopy();
584 vector = &vectors[vectorNumber];
585
586 interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
587 if (!vector->interruptDisabledSoft) {
588 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
589 return kIOReturnSuccess;
590 }
591
592 vector->interruptDisabledSoft = 0;
593 vectorsEnabled++;
594 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
595
596 if (controllerDisabled && (vectorsEnabled == vectorsRegistered)) {
597 controllerDisabled = 0;
598 provider->enableInterrupt(0);
599 }
600
601 return kIOReturnSuccess;
602 }
603
604 IOReturn IOSharedInterruptController::disableInterrupt(IOService *nub,
605 int source)
606 {
607 IOInterruptSource *interruptSources;
608 long vectorNumber;
609 IOInterruptVector *vector;
610 OSData *vectorData;
611 IOInterruptState interruptState;
612
613 interruptSources = nub->_interruptSources;
614 vectorData = interruptSources[source].vectorData;
615 vectorNumber = *(long *)vectorData->getBytesNoCopy();
616 vector = &vectors[vectorNumber];
617
618 interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
619 if (!vector->interruptDisabledSoft) {
620 vector->interruptDisabledSoft = 1;
621 #if __ppc__
622 sync();
623 isync();
624 #endif
625 vectorsEnabled--;
626 }
627 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
628
629 if (!getPlatform()->atInterruptLevel()) {
630 while (vector->interruptActive);
631 #if __ppc__
632 isync();
633 #endif
634 }
635
636 return kIOReturnSuccess;
637 }
638
639 IOInterruptAction IOSharedInterruptController::getInterruptHandlerAddress(void)
640 {
641 return (IOInterruptAction)&IOSharedInterruptController::handleInterrupt;
642 }
643
644 IOReturn IOSharedInterruptController::handleInterrupt(void * /*refCon*/,
645 IOService * nub,
646 int /*source*/)
647 {
648 long vectorNumber;
649 IOInterruptVector *vector;
650
651 for (vectorNumber = 0; vectorNumber < numVectors; vectorNumber++) {
652 vector = &vectors[vectorNumber];
653
654 vector->interruptActive = 1;
655 #if __ppc__
656 sync();
657 isync();
658 #endif
659 if (!vector->interruptDisabledSoft) {
660 #if __ppc__
661 isync();
662 #endif
663
664 // Call the handler if it exists.
665 if (vector->interruptRegistered) {
666 vector->handler(vector->target, vector->refCon,
667 vector->nub, vector->source);
668 }
669 }
670
671 vector->interruptActive = 0;
672 }
673
674 // if any of the vectors are dissabled, then dissable this controller.
675 IOSimpleLockLock(controllerLock);
676 if (vectorsEnabled != vectorsRegistered) {
677 nub->disableInterrupt(0);
678 controllerDisabled = 1;
679 }
680 IOSimpleLockUnlock(controllerLock);
681
682 return kIOReturnSuccess;
683 }
684