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