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