]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOInterruptController.cpp
xnu-201.tar.gz
[apple/xnu.git] / iokit / Kernel / IOInterruptController.cpp
CommitLineData
1c79356b
A
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
45OSDefineMetaClassAndAbstractStructors(IOInterruptController, IOService);
46
47OSMetaClassDefineReservedUnused(IOInterruptController, 0);
48OSMetaClassDefineReservedUnused(IOInterruptController, 1);
49OSMetaClassDefineReservedUnused(IOInterruptController, 2);
50OSMetaClassDefineReservedUnused(IOInterruptController, 3);
51OSMetaClassDefineReservedUnused(IOInterruptController, 4);
52OSMetaClassDefineReservedUnused(IOInterruptController, 5);
53
54/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
55
56IOReturn 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
171IOReturn 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
213IOReturn 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
233IOReturn 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;
0b4e3aa0
A
247#if __ppc__
248 sync();
249 isync();
250#endif
1c79356b 251
0b4e3aa0
A
252 if (!getPlatform()->atInterruptLevel()) {
253 while (vector->interruptActive);
254#if __ppc__
255 isync();
256#endif
257 }
1c79356b
A
258 if (vector->interruptDisabledHard) {
259 vector->interruptDisabledHard = 0;
260
261 enableVector(vectorNumber, vector);
262 }
263 }
264
265 return kIOReturnSuccess;
266}
267
268IOReturn 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
296IOReturn 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
313IOInterruptAction IOInterruptController::getInterruptHandlerAddress(void)
314{
315 return 0;
316}
317
318IOReturn 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
327bool IOInterruptController::vectorCanBeShared(long /*vectorNumber*/,
328 IOInterruptVector */*vector*/)
329{
330 return false;
331}
332
333void IOInterruptController::initVector(long /*vectorNumber*/,
334 IOInterruptVector */*vector*/)
335{
336}
337
338int IOInterruptController::getVectorType(long /*vectorNumber*/,
339 IOInterruptVector */*vector*/)
340{
341 return kIOInterruptTypeEdge;
342}
343
344void IOInterruptController::disableVectorHard(long /*vectorNumber*/,
345 IOInterruptVector */*vector*/)
346{
347}
348
349void IOInterruptController::enableVector(long /*vectorNumber*/,
350 IOInterruptVector */*vector*/)
351{
352}
353
354void IOInterruptController::causeVector(long /*vectorNumber*/,
355 IOInterruptVector */*vector*/)
356{
357}
358
359
360/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
361
362#undef super
363#define super IOInterruptController
364
365OSDefineMetaClassAndStructors(IOSharedInterruptController, IOInterruptController);
366
367OSMetaClassDefineReservedUnused(IOSharedInterruptController, 0);
368OSMetaClassDefineReservedUnused(IOSharedInterruptController, 1);
369OSMetaClassDefineReservedUnused(IOSharedInterruptController, 2);
370OSMetaClassDefineReservedUnused(IOSharedInterruptController, 3);
371
372/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
373
374IOReturn 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
433IOReturn 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
500IOReturn 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
545IOReturn IOSharedInterruptController::getInterruptType(IOService */*nub*/,
546 int /*source*/,
547 int *interruptType)
548{
549 return provider->getInterruptType(0, interruptType);
550}
551
552IOReturn 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 if (vector->interruptDisabledSoft) {
1c79356b 567 interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
0b4e3aa0 568 vector->interruptDisabledSoft = 0;
1c79356b
A
569 vectorsEnabled++;
570 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
571
572 if (controllerDisabled && (vectorsEnabled == vectorsRegistered)) {
573 controllerDisabled = 0;
574 provider->enableInterrupt(0);
575 }
576 }
577
578 return kIOReturnSuccess;
579}
580
581IOReturn IOSharedInterruptController::disableInterrupt(IOService *nub,
582 int source)
583{
584 IOInterruptSource *interruptSources;
585 long vectorNumber;
586 IOInterruptVector *vector;
587 OSData *vectorData;
588 IOInterruptState interruptState;;
589
590 interruptSources = nub->_interruptSources;
591 vectorData = interruptSources[source].vectorData;
592 vectorNumber = *(long *)vectorData->getBytesNoCopy();
593 vector = &vectors[vectorNumber];
594
595 if (!vector->interruptDisabledSoft) {
0b4e3aa0 596 interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
1c79356b
A
597 vector->interruptDisabledSoft = 1;
598#if __ppc__
599 sync();
600 isync();
601#endif
1c79356b
A
602 vectorsEnabled--;
603 IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
604 }
605
606 if (!getPlatform()->atInterruptLevel()) {
607 while (vector->interruptActive);
608#if __ppc__
609 isync();
610#endif
611 }
612
613 return kIOReturnSuccess;
614}
615
616IOInterruptAction IOSharedInterruptController::getInterruptHandlerAddress(void)
617{
618 return (IOInterruptAction)&IOSharedInterruptController::handleInterrupt;
619}
620
621IOReturn IOSharedInterruptController::handleInterrupt(void * /*refCon*/,
622 IOService * nub,
623 int /*source*/)
624{
625 long vectorNumber;
626 IOInterruptVector *vector;
627
628 for (vectorNumber = 0; vectorNumber < numVectors; vectorNumber++) {
629 vector = &vectors[vectorNumber];
630
631 vector->interruptActive = 1;
632#if __ppc__
633 sync();
634 isync();
635#endif
636 if (!vector->interruptDisabledSoft) {
637#if __ppc__
638 isync();
639#endif
640
641 // Call the handler if it exists.
642 if (vector->interruptRegistered) {
643 vector->handler(vector->target, vector->refCon,
644 vector->nub, vector->source);
645 }
646 }
647
648 vector->interruptActive = 0;
649 }
650
651 // if any of the vectors are dissabled, then dissable this controller.
652 IOSimpleLockLock(controllerLock);
653 if (vectorsEnabled != vectorsRegistered) {
654 nub->disableInterrupt(0);
655 controllerDisabled = 1;
656 }
657 IOSimpleLockUnlock(controllerLock);
658
659 return kIOReturnSuccess;
660}
661