]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOInterruptController.cpp
xnu-344.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 * 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 #if __ppc__
248 sync();
249 isync();
250 #endif
251
252 if (!getPlatform()->atInterruptLevel()) {
253 while (vector->interruptActive);
254 #if __ppc__
255 isync();
256 #endif
257 }
258 if (vector->interruptDisabledHard) {
259 vector->interruptDisabledHard = 0;
260
261 enableVector(vectorNumber, vector);
262 }
263 }
264
265 return kIOReturnSuccess;
266 }
267
268 IOReturn IOInterruptController::disableInterrupt(IOService *nub, int source)
269 {
270 IOInterruptSource *interruptSources;
271 long vectorNumber;
272 IOInterruptVector *vector;
273 OSData *vectorData;
274
275 interruptSources = nub->_interruptSources;
276 vectorData = interruptSources[source].vectorData;
277 vectorNumber = *(long *)vectorData->getBytesNoCopy();
278 vector = &vectors[vectorNumber];
279
280 vector->interruptDisabledSoft = 1;
281 #if __ppc__
282 sync();
283 isync();
284 #endif
285
286 if (!getPlatform()->atInterruptLevel()) {
287 while (vector->interruptActive);
288 #if __ppc__
289 isync();
290 #endif
291 }
292
293 return kIOReturnSuccess;
294 }
295
296 IOReturn IOInterruptController::causeInterrupt(IOService *nub, int source)
297 {
298 IOInterruptSource *interruptSources;
299 long vectorNumber;
300 IOInterruptVector *vector;
301 OSData *vectorData;
302
303 interruptSources = nub->_interruptSources;
304 vectorData = interruptSources[source].vectorData;
305 vectorNumber = *(long *)vectorData->getBytesNoCopy();
306 vector = &vectors[vectorNumber];
307
308 causeVector(vectorNumber, vector);
309
310 return kIOReturnSuccess;
311 }
312
313 IOInterruptAction IOInterruptController::getInterruptHandlerAddress(void)
314 {
315 return 0;
316 }
317
318 IOReturn IOInterruptController::handleInterrupt(void *refCon, IOService *nub,
319 int source)
320 {
321 return kIOReturnInvalid;
322 }
323
324
325 // Methods to be overridden for simplifed interrupt controller subclasses.
326
327 bool IOInterruptController::vectorCanBeShared(long /*vectorNumber*/,
328 IOInterruptVector */*vector*/)
329 {
330 return false;
331 }
332
333 void IOInterruptController::initVector(long /*vectorNumber*/,
334 IOInterruptVector */*vector*/)
335 {
336 }
337
338 int IOInterruptController::getVectorType(long /*vectorNumber*/,
339 IOInterruptVector */*vector*/)
340 {
341 return kIOInterruptTypeEdge;
342 }
343
344 void IOInterruptController::disableVectorHard(long /*vectorNumber*/,
345 IOInterruptVector */*vector*/)
346 {
347 }
348
349 void IOInterruptController::enableVector(long /*vectorNumber*/,
350 IOInterruptVector */*vector*/)
351 {
352 }
353
354 void IOInterruptController::causeVector(long /*vectorNumber*/,
355 IOInterruptVector */*vector*/)
356 {
357 }
358
359
360 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
361
362 #undef super
363 #define super IOInterruptController
364
365 OSDefineMetaClassAndStructors(IOSharedInterruptController, IOInterruptController);
366
367 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 0);
368 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 1);
369 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 2);
370 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 3);
371
372 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
373
374 IOReturn IOSharedInterruptController::initInterruptController(IOInterruptController *parentController, OSData *parentSource)
375 {
376 int cnt, interruptType;
377 IOReturn error;
378
379 if (!super::init())
380 return kIOReturnNoResources;
381
382 // Set provider to this so enable/disable nub stuff works.
383 provider = this;
384
385 // Allocate the IOInterruptSource so this can act like a nub.
386 _interruptSources = (IOInterruptSource *)IOMalloc(sizeof(IOInterruptSource));
387 if (_interruptSources == 0) return kIOReturnNoMemory;
388 _numInterruptSources = 1;
389
390 // Set up the IOInterruptSource to point at this.
391 _interruptSources[0].interruptController = parentController;
392 _interruptSources[0].vectorData = parentSource;
393
394 sourceIsLevel = false;
395 error = provider->getInterruptType(0, &interruptType);
396 if (error == kIOReturnSuccess) {
397 if (interruptType & kIOInterruptTypeLevel)
398 sourceIsLevel = true;
399 }
400
401 // Allocate the memory for the vectors
402 numVectors = 8; // For now a constant number.
403 vectors = (IOInterruptVector *)IOMalloc(numVectors * sizeof(IOInterruptVector));
404 if (vectors == NULL) {
405 IOFree(_interruptSources, sizeof(IOInterruptSource));
406 return kIOReturnNoMemory;
407 }
408 bzero(vectors, numVectors * sizeof(IOInterruptVector));
409
410 // Allocate the lock for the controller.
411 controllerLock = IOSimpleLockAlloc();
412 if (controllerLock == 0) return kIOReturnNoResources;
413
414 // Allocate locks for the vectors.
415 for (cnt = 0; cnt < numVectors; cnt++) {
416 vectors[cnt].interruptLock = IOLockAlloc();
417 if (vectors[cnt].interruptLock == NULL) {
418 for (cnt = 0; cnt < numVectors; cnt++) {
419 if (vectors[cnt].interruptLock != NULL)
420 IOLockFree(vectors[cnt].interruptLock);
421 }
422 return kIOReturnNoResources;
423 }
424 }
425
426 vectorsRegistered = 0;
427 vectorsEnabled = 0;
428 controllerDisabled = 1;
429
430 return kIOReturnSuccess;
431 }
432
433 IOReturn IOSharedInterruptController::registerInterrupt(IOService *nub,
434 int source,
435 void *target,
436 IOInterruptHandler handler,
437 void *refCon)
438 {
439 IOInterruptSource *interruptSources;
440 long vectorNumber;
441 IOInterruptVector *vector = 0;
442 OSData *vectorData;
443 IOInterruptState interruptState;
444
445 interruptSources = nub->_interruptSources;
446
447 // Find a free vector.
448 vectorNumber = numVectors;
449 while (vectorsRegistered != numVectors) {
450 for (vectorNumber = 0; vectorNumber < numVectors; vectorNumber++) {
451 vector = &vectors[vectorNumber];
452
453 // Get the lock for this vector.
454 IOTakeLock(vector->interruptLock);
455
456 // Is it unregistered?
457 if (!vector->interruptRegistered) break;
458
459 // Move along to the next one.
460 IOUnlock(vector->interruptLock);
461 }
462
463 if (vectorNumber != numVectors) break;
464 }
465
466 // Could not find a free one, so give up.
467 if (vectorNumber == numVectors) {
468 return kIOReturnNoResources;
469 }
470
471 // Create the vectorData for the IOInterruptSource.
472 vectorData = OSData::withBytes(&vectorNumber, sizeof(vectorNumber));
473 if (vectorData == 0) {
474 return kIOReturnNoMemory;
475 }
476
477 // Fill in the IOInterruptSource with the controller's info.
478 interruptSources[source].interruptController = this;
479 interruptSources[source].vectorData = vectorData;
480
481 // Fill in vector with the client's info.
482 vector->handler = handler;
483 vector->nub = nub;
484 vector->source = source;
485 vector->target = target;
486 vector->refCon = refCon;
487
488 // Get the vector ready. It start soft disabled.
489 vector->interruptDisabledSoft = 1;
490 vector->interruptRegistered = 1;
491
492 interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
493 vectorsRegistered++;
494 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
495
496 IOUnlock(vector->interruptLock);
497 return kIOReturnSuccess;
498 }
499
500 IOReturn IOSharedInterruptController::unregisterInterrupt(IOService *nub,
501 int source)
502 {
503 IOInterruptSource *interruptSources;
504 long vectorNumber;
505 IOInterruptVector *vector;
506 OSData *vectorData;
507 IOInterruptState interruptState;;
508
509 interruptSources = nub->_interruptSources;
510 vectorData = interruptSources[source].vectorData;
511 vectorNumber = *(long *)vectorData->getBytesNoCopy();
512 vector = &vectors[vectorNumber];
513
514 // Get the lock for this vector.
515 IOTakeLock(vector->interruptLock);
516
517 // Return success if it is not already registered
518 if (!vector->interruptRegistered) {
519 IOUnlock(vector->interruptLock);
520 return kIOReturnSuccess;
521 }
522
523 // Soft disable the source.
524 disableInterrupt(nub, source);
525
526 // Clear all the storage for the vector except for interruptLock.
527 vector->interruptActive = 0;
528 vector->interruptDisabledSoft = 0;
529 vector->interruptDisabledHard = 0;
530 vector->interruptRegistered = 0;
531 vector->nub = 0;
532 vector->source = 0;
533 vector->handler = 0;
534 vector->target = 0;
535 vector->refCon = 0;
536
537 interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
538 vectorsRegistered--;
539 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
540
541 IOUnlock(vector->interruptLock);
542 return kIOReturnSuccess;
543 }
544
545 IOReturn IOSharedInterruptController::getInterruptType(IOService */*nub*/,
546 int /*source*/,
547 int *interruptType)
548 {
549 return provider->getInterruptType(0, interruptType);
550 }
551
552 IOReturn IOSharedInterruptController::enableInterrupt(IOService *nub,
553 int source)
554 {
555 IOInterruptSource *interruptSources;
556 long vectorNumber;
557 IOInterruptVector *vector;
558 OSData *vectorData;
559 IOInterruptState interruptState;
560
561 interruptSources = nub->_interruptSources;
562 vectorData = interruptSources[source].vectorData;
563 vectorNumber = *(long *)vectorData->getBytesNoCopy();
564 vector = &vectors[vectorNumber];
565
566 interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
567 if (!vector->interruptDisabledSoft) {
568 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
569 return kIOReturnSuccess;
570 }
571
572 vector->interruptDisabledSoft = 0;
573 vectorsEnabled++;
574 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
575
576 if (controllerDisabled && (vectorsEnabled == vectorsRegistered)) {
577 controllerDisabled = 0;
578 provider->enableInterrupt(0);
579 }
580
581 return kIOReturnSuccess;
582 }
583
584 IOReturn IOSharedInterruptController::disableInterrupt(IOService *nub,
585 int source)
586 {
587 IOInterruptSource *interruptSources;
588 long vectorNumber;
589 IOInterruptVector *vector;
590 OSData *vectorData;
591 IOInterruptState interruptState;
592
593 interruptSources = nub->_interruptSources;
594 vectorData = interruptSources[source].vectorData;
595 vectorNumber = *(long *)vectorData->getBytesNoCopy();
596 vector = &vectors[vectorNumber];
597
598 interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
599 if (!vector->interruptDisabledSoft) {
600 vector->interruptDisabledSoft = 1;
601 #if __ppc__
602 sync();
603 isync();
604 #endif
605 vectorsEnabled--;
606 }
607 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
608
609 if (!getPlatform()->atInterruptLevel()) {
610 while (vector->interruptActive);
611 #if __ppc__
612 isync();
613 #endif
614 }
615
616 return kIOReturnSuccess;
617 }
618
619 IOInterruptAction IOSharedInterruptController::getInterruptHandlerAddress(void)
620 {
621 return (IOInterruptAction)&IOSharedInterruptController::handleInterrupt;
622 }
623
624 IOReturn IOSharedInterruptController::handleInterrupt(void * /*refCon*/,
625 IOService * nub,
626 int /*source*/)
627 {
628 long vectorNumber;
629 IOInterruptVector *vector;
630
631 for (vectorNumber = 0; vectorNumber < numVectors; vectorNumber++) {
632 vector = &vectors[vectorNumber];
633
634 vector->interruptActive = 1;
635 #if __ppc__
636 sync();
637 isync();
638 #endif
639 if (!vector->interruptDisabledSoft) {
640 #if __ppc__
641 isync();
642 #endif
643
644 // Call the handler if it exists.
645 if (vector->interruptRegistered) {
646 vector->handler(vector->target, vector->refCon,
647 vector->nub, vector->source);
648 }
649 }
650
651 vector->interruptActive = 0;
652 }
653
654 // if any of the vectors are dissabled, then dissable this controller.
655 IOSimpleLockLock(controllerLock);
656 if (vectorsEnabled != vectorsRegistered) {
657 nub->disableInterrupt(0);
658 controllerDisabled = 1;
659 }
660 IOSimpleLockUnlock(controllerLock);
661
662 return kIOReturnSuccess;
663 }
664