]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOInterruptController.cpp
c41df7e8cc5accd57960e7dd0a33f355f8e93ee1
[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 // Save the dis/enable state for the original consumer's interrupt.
100 // Then disable the source
101 wasDisabledSoft = vector->interruptDisabledSoft;
102 disableInterrupt(originalNub, originalSource);
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 enableInterrupt(originalNub, originalSource);
129 vector->sharedController->release();
130 vector->sharedController = 0;
131 IOUnlock(vector->interruptLock);
132 return error;
133 }
134
135 // Fill in vector with the shared controller's info.
136 vector->handler = (IOInterruptHandler)vector->sharedController->getInterruptHandlerAddress();
137 vector->nub = vector->sharedController;
138 vector->source = 0;
139 vector->target = vector->sharedController;
140 vector->refCon = 0;
141
142 // Enable the original consumer's interrupt if needed.
143 if (!wasDisabledSoft) originalNub->enableInterrupt(originalSource);
144 }
145
146 error = vector->sharedController->registerInterrupt(nub, source, target,
147 handler, refCon);
148 IOUnlock(vector->interruptLock);
149 return error;
150 }
151
152 // Fill in vector with the client's info.
153 vector->handler = handler;
154 vector->nub = nub;
155 vector->source = source;
156 vector->target = target;
157 vector->refCon = refCon;
158
159 // Do any specific initalization for this vector.
160 initVector(vectorNumber, vector);
161
162 // Get the vector ready. It starts hard disabled.
163 vector->interruptDisabledHard = 1;
164 vector->interruptDisabledSoft = 1;
165 vector->interruptRegistered = 1;
166
167 IOUnlock(vector->interruptLock);
168 return kIOReturnSuccess;
169 }
170
171 IOReturn IOInterruptController::unregisterInterrupt(IOService *nub, int source)
172 {
173 IOInterruptSource *interruptSources;
174 long vectorNumber;
175 IOInterruptVector *vector;
176 OSData *vectorData;
177
178 interruptSources = nub->_interruptSources;
179 vectorData = interruptSources[source].vectorData;
180 vectorNumber = *(long *)vectorData->getBytesNoCopy();
181 vector = &vectors[vectorNumber];
182
183 // Get the lock for this vector.
184 IOTakeLock(vector->interruptLock);
185
186 // Return success if it is not already registered
187 if (!vector->interruptRegistered) {
188 IOUnlock(vector->interruptLock);
189 return kIOReturnSuccess;
190 }
191
192 // Soft disable the source.
193 disableInterrupt(nub, source);
194
195 // Turn the source off at hardware.
196 disableVectorHard(vectorNumber, vector);
197
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;
203 vector->nub = 0;
204 vector->source = 0;
205 vector->handler = 0;
206 vector->target = 0;
207 vector->refCon = 0;
208
209 IOUnlock(vector->interruptLock);
210 return kIOReturnSuccess;
211 }
212
213 IOReturn IOInterruptController::getInterruptType(IOService *nub, int source,
214 int *interruptType)
215 {
216 IOInterruptSource *interruptSources;
217 long vectorNumber;
218 IOInterruptVector *vector;
219 OSData *vectorData;
220
221 if (interruptType == 0) return kIOReturnBadArgument;
222
223 interruptSources = nub->_interruptSources;
224 vectorData = interruptSources[source].vectorData;
225 vectorNumber = *(long *)vectorData->getBytesNoCopy();
226 vector = &vectors[vectorNumber];
227
228 *interruptType = getVectorType(vectorNumber, vector);
229
230 return kIOReturnSuccess;
231 }
232
233 IOReturn IOInterruptController::enableInterrupt(IOService *nub, int source)
234 {
235 IOInterruptSource *interruptSources;
236 long vectorNumber;
237 IOInterruptVector *vector;
238 OSData *vectorData;
239
240 interruptSources = nub->_interruptSources;
241 vectorData = interruptSources[source].vectorData;
242 vectorNumber = *(long *)vectorData->getBytesNoCopy();
243 vector = &vectors[vectorNumber];
244
245 if (vector->interruptDisabledSoft) {
246 vector->interruptDisabledSoft = 0;
247
248 if (vector->interruptDisabledHard) {
249 vector->interruptDisabledHard = 0;
250
251 enableVector(vectorNumber, vector);
252 }
253 }
254
255 return kIOReturnSuccess;
256 }
257
258 IOReturn IOInterruptController::disableInterrupt(IOService *nub, int source)
259 {
260 IOInterruptSource *interruptSources;
261 long vectorNumber;
262 IOInterruptVector *vector;
263 OSData *vectorData;
264
265 interruptSources = nub->_interruptSources;
266 vectorData = interruptSources[source].vectorData;
267 vectorNumber = *(long *)vectorData->getBytesNoCopy();
268 vector = &vectors[vectorNumber];
269
270 vector->interruptDisabledSoft = 1;
271 #if __ppc__
272 sync();
273 isync();
274 #endif
275
276 if (!getPlatform()->atInterruptLevel()) {
277 while (vector->interruptActive);
278 #if __ppc__
279 isync();
280 #endif
281 }
282
283 return kIOReturnSuccess;
284 }
285
286 IOReturn IOInterruptController::causeInterrupt(IOService *nub, int source)
287 {
288 IOInterruptSource *interruptSources;
289 long vectorNumber;
290 IOInterruptVector *vector;
291 OSData *vectorData;
292
293 interruptSources = nub->_interruptSources;
294 vectorData = interruptSources[source].vectorData;
295 vectorNumber = *(long *)vectorData->getBytesNoCopy();
296 vector = &vectors[vectorNumber];
297
298 causeVector(vectorNumber, vector);
299
300 return kIOReturnSuccess;
301 }
302
303 IOInterruptAction IOInterruptController::getInterruptHandlerAddress(void)
304 {
305 return 0;
306 }
307
308 IOReturn IOInterruptController::handleInterrupt(void *refCon, IOService *nub,
309 int source)
310 {
311 return kIOReturnInvalid;
312 }
313
314
315 // Methods to be overridden for simplifed interrupt controller subclasses.
316
317 bool IOInterruptController::vectorCanBeShared(long /*vectorNumber*/,
318 IOInterruptVector */*vector*/)
319 {
320 return false;
321 }
322
323 void IOInterruptController::initVector(long /*vectorNumber*/,
324 IOInterruptVector */*vector*/)
325 {
326 }
327
328 int IOInterruptController::getVectorType(long /*vectorNumber*/,
329 IOInterruptVector */*vector*/)
330 {
331 return kIOInterruptTypeEdge;
332 }
333
334 void IOInterruptController::disableVectorHard(long /*vectorNumber*/,
335 IOInterruptVector */*vector*/)
336 {
337 }
338
339 void IOInterruptController::enableVector(long /*vectorNumber*/,
340 IOInterruptVector */*vector*/)
341 {
342 }
343
344 void IOInterruptController::causeVector(long /*vectorNumber*/,
345 IOInterruptVector */*vector*/)
346 {
347 }
348
349
350 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
351
352 #undef super
353 #define super IOInterruptController
354
355 OSDefineMetaClassAndStructors(IOSharedInterruptController, IOInterruptController);
356
357 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 0);
358 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 1);
359 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 2);
360 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 3);
361
362 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
363
364 IOReturn IOSharedInterruptController::initInterruptController(IOInterruptController *parentController, OSData *parentSource)
365 {
366 int cnt, interruptType;
367 IOReturn error;
368
369 if (!super::init())
370 return kIOReturnNoResources;
371
372 // Set provider to this so enable/disable nub stuff works.
373 provider = this;
374
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;
379
380 // Set up the IOInterruptSource to point at this.
381 _interruptSources[0].interruptController = parentController;
382 _interruptSources[0].vectorData = parentSource;
383
384 sourceIsLevel = false;
385 error = provider->getInterruptType(0, &interruptType);
386 if (error == kIOReturnSuccess) {
387 if (interruptType & kIOInterruptTypeLevel)
388 sourceIsLevel = true;
389 }
390
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;
397 }
398 bzero(vectors, numVectors * sizeof(IOInterruptVector));
399
400 // Allocate the lock for the controller.
401 controllerLock = IOSimpleLockAlloc();
402 if (controllerLock == 0) return kIOReturnNoResources;
403
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);
411 }
412 return kIOReturnNoResources;
413 }
414 }
415
416 vectorsRegistered = 0;
417 vectorsEnabled = 0;
418 controllerDisabled = 1;
419
420 return kIOReturnSuccess;
421 }
422
423 IOReturn IOSharedInterruptController::registerInterrupt(IOService *nub,
424 int source,
425 void *target,
426 IOInterruptHandler handler,
427 void *refCon)
428 {
429 IOInterruptSource *interruptSources;
430 long vectorNumber;
431 IOInterruptVector *vector = 0;
432 OSData *vectorData;
433 IOInterruptState interruptState;
434
435 interruptSources = nub->_interruptSources;
436
437 // Find a free vector.
438 vectorNumber = numVectors;
439 while (vectorsRegistered != numVectors) {
440 for (vectorNumber = 0; vectorNumber < numVectors; vectorNumber++) {
441 vector = &vectors[vectorNumber];
442
443 // Get the lock for this vector.
444 IOTakeLock(vector->interruptLock);
445
446 // Is it unregistered?
447 if (!vector->interruptRegistered) break;
448
449 // Move along to the next one.
450 IOUnlock(vector->interruptLock);
451 }
452
453 if (vectorNumber != numVectors) break;
454 }
455
456 // Could not find a free one, so give up.
457 if (vectorNumber == numVectors) {
458 return kIOReturnNoResources;
459 }
460
461 // Create the vectorData for the IOInterruptSource.
462 vectorData = OSData::withBytes(&vectorNumber, sizeof(vectorNumber));
463 if (vectorData == 0) {
464 return kIOReturnNoMemory;
465 }
466
467 // Fill in the IOInterruptSource with the controller's info.
468 interruptSources[source].interruptController = this;
469 interruptSources[source].vectorData = vectorData;
470
471 // Fill in vector with the client's info.
472 vector->handler = handler;
473 vector->nub = nub;
474 vector->source = source;
475 vector->target = target;
476 vector->refCon = refCon;
477
478 // Get the vector ready. It start soft disabled.
479 vector->interruptDisabledSoft = 1;
480 vector->interruptRegistered = 1;
481
482 interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
483 vectorsRegistered++;
484 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
485
486 IOUnlock(vector->interruptLock);
487 return kIOReturnSuccess;
488 }
489
490 IOReturn IOSharedInterruptController::unregisterInterrupt(IOService *nub,
491 int source)
492 {
493 IOInterruptSource *interruptSources;
494 long vectorNumber;
495 IOInterruptVector *vector;
496 OSData *vectorData;
497 IOInterruptState interruptState;;
498
499 interruptSources = nub->_interruptSources;
500 vectorData = interruptSources[source].vectorData;
501 vectorNumber = *(long *)vectorData->getBytesNoCopy();
502 vector = &vectors[vectorNumber];
503
504 // Get the lock for this vector.
505 IOTakeLock(vector->interruptLock);
506
507 // Return success if it is not already registered
508 if (!vector->interruptRegistered) {
509 IOUnlock(vector->interruptLock);
510 return kIOReturnSuccess;
511 }
512
513 // Soft disable the source.
514 disableInterrupt(nub, source);
515
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;
521 vector->nub = 0;
522 vector->source = 0;
523 vector->handler = 0;
524 vector->target = 0;
525 vector->refCon = 0;
526
527 interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
528 vectorsRegistered--;
529 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
530
531 IOUnlock(vector->interruptLock);
532 return kIOReturnSuccess;
533 }
534
535 IOReturn IOSharedInterruptController::getInterruptType(IOService */*nub*/,
536 int /*source*/,
537 int *interruptType)
538 {
539 return provider->getInterruptType(0, interruptType);
540 }
541
542 IOReturn IOSharedInterruptController::enableInterrupt(IOService *nub,
543 int source)
544 {
545 IOInterruptSource *interruptSources;
546 long vectorNumber;
547 IOInterruptVector *vector;
548 OSData *vectorData;
549 IOInterruptState interruptState;;
550
551 interruptSources = nub->_interruptSources;
552 vectorData = interruptSources[source].vectorData;
553 vectorNumber = *(long *)vectorData->getBytesNoCopy();
554 vector = &vectors[vectorNumber];
555
556 if (vector->interruptDisabledSoft) {
557 vector->interruptDisabledSoft = 0;
558
559 interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
560 vectorsEnabled++;
561 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
562
563 if (controllerDisabled && (vectorsEnabled == vectorsRegistered)) {
564 controllerDisabled = 0;
565 provider->enableInterrupt(0);
566 }
567 }
568
569 return kIOReturnSuccess;
570 }
571
572 IOReturn IOSharedInterruptController::disableInterrupt(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 if (!vector->interruptDisabledSoft) {
587 vector->interruptDisabledSoft = 1;
588 #if __ppc__
589 sync();
590 isync();
591 #endif
592
593 interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
594 vectorsEnabled--;
595 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
596 }
597
598 if (!getPlatform()->atInterruptLevel()) {
599 while (vector->interruptActive);
600 #if __ppc__
601 isync();
602 #endif
603 }
604
605 return kIOReturnSuccess;
606 }
607
608 IOInterruptAction IOSharedInterruptController::getInterruptHandlerAddress(void)
609 {
610 return (IOInterruptAction)&IOSharedInterruptController::handleInterrupt;
611 }
612
613 IOReturn IOSharedInterruptController::handleInterrupt(void * /*refCon*/,
614 IOService * nub,
615 int /*source*/)
616 {
617 long vectorNumber;
618 IOInterruptVector *vector;
619
620 for (vectorNumber = 0; vectorNumber < numVectors; vectorNumber++) {
621 vector = &vectors[vectorNumber];
622
623 vector->interruptActive = 1;
624 #if __ppc__
625 sync();
626 isync();
627 #endif
628 if (!vector->interruptDisabledSoft) {
629 #if __ppc__
630 isync();
631 #endif
632
633 // Call the handler if it exists.
634 if (vector->interruptRegistered) {
635 vector->handler(vector->target, vector->refCon,
636 vector->nub, vector->source);
637 }
638 }
639
640 vector->interruptActive = 0;
641 }
642
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;
648 }
649 IOSimpleLockUnlock(controllerLock);
650
651 return kIOReturnSuccess;
652 }
653