]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
43866e37 | 6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
1c79356b | 7 | * |
43866e37 A |
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 | |
1c79356b A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
43866e37 A |
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. | |
1c79356b A |
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 | ||
ac5ea4a9 A |
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; | |
1c79356b A |
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) { | |
ac5ea4a9 A |
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); | |
1c79356b | 140 | enableInterrupt(originalNub, originalSource); |
ac5ea4a9 | 141 | |
1c79356b A |
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 | ||
ac5ea4a9 A |
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 | ||
1c79356b A |
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; | |
0b4e3aa0 A |
267 | #if __ppc__ |
268 | sync(); | |
269 | isync(); | |
270 | #endif | |
1c79356b | 271 | |
0b4e3aa0 A |
272 | if (!getPlatform()->atInterruptLevel()) { |
273 | while (vector->interruptActive); | |
274 | #if __ppc__ | |
275 | isync(); | |
276 | #endif | |
277 | } | |
1c79356b A |
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 | |
ac5ea4a9 | 422 | numVectors = 32; // For now a constant number. |
1c79356b A |
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; | |
14353aa8 | 579 | IOInterruptState interruptState; |
1c79356b A |
580 | |
581 | interruptSources = nub->_interruptSources; | |
582 | vectorData = interruptSources[source].vectorData; | |
583 | vectorNumber = *(long *)vectorData->getBytesNoCopy(); | |
584 | vector = &vectors[vectorNumber]; | |
585 | ||
14353aa8 A |
586 | interruptState = IOSimpleLockLockDisableInterrupt(controllerLock); |
587 | if (!vector->interruptDisabledSoft) { | |
1c79356b | 588 | IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState); |
14353aa8 A |
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); | |
1c79356b A |
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; | |
14353aa8 | 611 | IOInterruptState interruptState; |
1c79356b A |
612 | |
613 | interruptSources = nub->_interruptSources; | |
614 | vectorData = interruptSources[source].vectorData; | |
615 | vectorNumber = *(long *)vectorData->getBytesNoCopy(); | |
616 | vector = &vectors[vectorNumber]; | |
617 | ||
14353aa8 | 618 | interruptState = IOSimpleLockLockDisableInterrupt(controllerLock); |
1c79356b A |
619 | if (!vector->interruptDisabledSoft) { |
620 | vector->interruptDisabledSoft = 1; | |
621 | #if __ppc__ | |
622 | sync(); | |
623 | isync(); | |
624 | #endif | |
1c79356b | 625 | vectorsEnabled--; |
1c79356b | 626 | } |
14353aa8 | 627 | IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState); |
1c79356b A |
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 |