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