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