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