|
|
1.1 root 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) 1991-1999 Apple Computer, Inc. All rights reserved.
24: *
25: * HISTORY
26: *
27: * 29-Jan-91 Portions from IODevice.m, Doug Mitchell at NeXT, Created.
28: * 18-Jun-98 start IOKit objc
29: * 10-Nov-98 start iokit cpp
30: * 25-Feb-99 sdouglas, add threads and locks to ensure deadlock
31: *
32: */
33:
34: #include <IOKit/system.h>
35:
36: #include <IOKit/IOService.h>
37: #include <libkern/c++/OSContainers.h>
38: #include <libkern/c++/OSUnserialize.h>
39: #include <IOKit/IOCatalogue.h>
40: #include <IOKit/IODeviceMemory.h>
41: #include <IOKit/IOInterrupts.h>
42: #include <IOKit/IOInterruptController.h>
43: #include <IOKit/IOPlatformExpert.h>
44: #include <IOKit/IOMessage.h>
45: #include <IOKit/IOLib.h>
46: #include <IOKit/IOKitKeys.h>
47: #include <IOKit/IOBSD.h>
48: #include <IOKit/IOUserClient.h>
49:
50: //#define LESS_THREAD_CREATE
51: //#define LOG kprintf
52: #define LOG IOLog
53:
54: #include "IOServicePrivate.h"
55: #include <mach/sync_policy.h>
56:
57: #include <IOKit/assert.h>
58:
59: #include <sys/errno.h>
60:
61: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
62:
63: #define super IORegistryEntry
64:
65: OSDefineMetaClassAndStructors(IOService, IORegistryEntry)
66:
67: OSDefineMetaClassAndStructors(_IOServiceNotifier, IONotifier)
68:
69: OSDefineMetaClassAndStructors(_IOServiceInterestNotifier, IONotifier)
70:
71: OSDefineMetaClassAndStructors(_IOConfigThread, OSObject)
72:
73: OSDefineMetaClassAndStructors(_IOServiceJob, OSObject)
74:
75: OSDefineMetaClassAndStructors(IOResources, IOService)
76:
77: OSDefineMetaClassAndStructors(_IOOpenServiceIterator, OSIterator)
78:
79: OSDefineMetaClass(IONotifier, OSObject)
80: OSDefineAbstractStructors(IONotifier, OSObject)
81:
82: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
83:
84: static IOPlatformExpert * gIOPlatform;
85: const IORegistryPlane * gIOServicePlane;
86: const IORegistryPlane * gIOPowerPlane;
87: const OSSymbol * gIODeviceMemoryKey;
88: const OSSymbol * gIOInterruptControllersKey;
89: const OSSymbol * gIOInterruptSpecifiersKey;
90:
91: const OSSymbol * gIOResourcesKey;
92: const OSSymbol * gIOResourceMatchKey;
93: const OSSymbol * gIOProviderClassKey;
94: const OSSymbol * gIONameMatchKey;
95: const OSSymbol * gIONameMatchedKey;
96: const OSSymbol * gIOLocationMatchKey;
97: const OSSymbol * gIOPathMatchKey;
98: const OSSymbol * gIOMatchCategoryKey;
99: const OSSymbol * gIODefaultMatchCategoryKey;
100: const OSSymbol * gIOKitDebugKey;
101:
102: static int gIOResourceGenerationCount;
103:
104: const OSSymbol * gIOServiceKey;
105: const OSSymbol * gIOPublishNotification;
106: const OSSymbol * gIOFirstPublishNotification;
107: const OSSymbol * gIOMatchedNotification;
108: const OSSymbol * gIOFirstMatchNotification;
109: const OSSymbol * gIOTerminatedNotification;
110:
111: const OSSymbol * gIOGeneralInterest;
112: const OSSymbol * gIOBusyInterest;
113:
114: static OSDictionary * gNotifications;
115: static IORecursiveLock * gNotificationLock;
116:
117: static IOService * gIOResources;
118: static IOService * gIOServiceRoot;
119:
120: static OSOrderedSet * gJobs;
121: static semaphore_port_t gJobsSemaphore;
122: static IOLock * gJobsLock;
123: static int gOutstandingJobs;
124: static int gNumConfigThreads;
125: static int gNumWaitingThreads;
126: static IOLock * gIOServiceBusyLock;
127:
128: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
129:
130: #define LOCKREADNOTIFY() \
131: IORecursiveLockLock( gNotificationLock )
132: #define LOCKWRITENOTIFY() \
133: IORecursiveLockLock( gNotificationLock )
134: #define LOCKWRITE2READNOTIFY()
135: #define UNLOCKNOTIFY() \
136: IORecursiveLockUnlock( gNotificationLock )
137:
138: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
139:
140: struct ArbitrationLockQueueElement {
141: queue_chain_t link;
142: IOThread thread;
143: IOService * service;
144: unsigned count;
145: bool required;
146: bool aborted;
147: };
148:
149: static queue_head_t gArbitrationLockQueueActive;
150: static queue_head_t gArbitrationLockQueueWaiting;
151: static queue_head_t gArbitrationLockQueueFree;
152: static IOLock * gArbitrationLockQueueLock;
153:
154: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
155:
156: void IOService::initialize( void )
157: {
158: kern_return_t err;
159:
160: gIOServicePlane = IORegistryEntry::makePlane( kIOServicePlane );
161: gIOPowerPlane = IORegistryEntry::makePlane( kIOPowerPlane );
162:
163: gIOProviderClassKey = OSSymbol::withCStringNoCopy( kIOProviderClassKey );
164: gIONameMatchKey = OSSymbol::withCStringNoCopy( kIONameMatchKey );
165: gIONameMatchedKey = OSSymbol::withCStringNoCopy( kIONameMatchedKey );
166: gIOPathMatchKey = OSSymbol::withCStringNoCopy( kIOPathMatchKey );
167: gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey );
168:
169: gIOMatchCategoryKey = OSSymbol::withCStringNoCopy( kIOMatchCategoryKey );
170: gIODefaultMatchCategoryKey = OSSymbol::withCStringNoCopy(
171: kIODefaultMatchCategoryKey );
172:
173: gIOResourcesKey = OSSymbol::withCStringNoCopy( kIOResourcesClass );
174: gIOResourceMatchKey = OSSymbol::withCStringNoCopy( kIOResourceMatchKey );
175:
176: gIODeviceMemoryKey = OSSymbol::withCStringNoCopy( "IODeviceMemory" );
177: gIOInterruptControllersKey
178: = OSSymbol::withCStringNoCopy("IOInterruptControllers");
179: gIOInterruptSpecifiersKey
180: = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
181:
182: gIOKitDebugKey = OSSymbol::withCStringNoCopy( kIOKitDebugKey );
183:
184: gIOGeneralInterest = OSSymbol::withCStringNoCopy( kIOGeneralInterest );
185: gIOBusyInterest = OSSymbol::withCStringNoCopy( kIOBusyInterest );
186:
187: gNotifications = OSDictionary::withCapacity( 1 );
188: gIOPublishNotification = OSSymbol::withCStringNoCopy(
189: kIOPublishNotification );
190: gIOFirstPublishNotification = OSSymbol::withCStringNoCopy(
191: kIOFirstPublishNotification );
192: gIOMatchedNotification = OSSymbol::withCStringNoCopy(
193: kIOMatchedNotification );
194: gIOFirstMatchNotification = OSSymbol::withCStringNoCopy(
195: kIOFirstMatchNotification );
196: gIOTerminatedNotification = OSSymbol::withCStringNoCopy(
197: kIOTerminatedNotification );
198: gIOServiceKey = OSSymbol::withCStringNoCopy( kIOServiceClass);
199:
200: gNotificationLock = IORecursiveLockAlloc();
201:
202: assert( gIOServicePlane && gIODeviceMemoryKey
203: && gIOInterruptControllersKey && gIOInterruptSpecifiersKey
204: && gIOResourcesKey && gNotifications && gNotificationLock
205: && gIOProviderClassKey && gIONameMatchKey && gIONameMatchedKey
206: && gIOMatchCategoryKey && gIODefaultMatchCategoryKey
207: && gIOPublishNotification && gIOMatchedNotification
208: && gIOTerminatedNotification && gIOServiceKey );
209:
210: gJobsLock = IOLockAlloc();
211: gJobs = OSOrderedSet::withCapacity( 10 );
212:
213: gIOServiceBusyLock = IOLockAlloc();
214:
215: err = semaphore_create(kernel_task, &gJobsSemaphore, SYNC_POLICY_FIFO, 0);
216:
217: assert( gIOServiceBusyLock && gJobs && gJobsLock && (err == KERN_SUCCESS) );
218:
219: gIOResources = IOResources::resources();
220: assert( gIOResources );
221:
222: gArbitrationLockQueueLock = IOLockAlloc();
223: queue_init(&gArbitrationLockQueueActive);
224: queue_init(&gArbitrationLockQueueWaiting);
225: queue_init(&gArbitrationLockQueueFree);
226:
227: assert( gArbitrationLockQueueLock );
228:
229: #ifdef LESS_THREAD_CREATE
230: for( int i = 0; i < kMaxConfigThreads; i++)
231: _IOConfigThread::configThread();
232: #endif
233:
234: }
235:
236: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
237:
238: #ifdef DEBUG
239: static UInt64 getDebugFlags( OSDictionary * props )
240: {
241: OSNumber * debugProp;
242: UInt64 debugFlags;
243:
244: debugProp = OSDynamicCast( OSNumber,
245: props->getObject( gIOKitDebugKey ));
246: if( debugProp)
247: debugFlags = debugProp->unsigned64BitValue();
248: else
249: debugFlags = gIOKitDebug;
250:
251: return( debugFlags );
252: }
253: #endif
254:
255: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
256:
257: // Probe a matched service and return an instance to be started.
258: // The default score is from the property table, & may be altered
259: // during probe to change the start order.
260:
261: IOService * IOService::probe( IOService * /* provider */,
262: SInt32 * /* score */)
263: {
264: return( this );
265: }
266:
267: bool IOService::start( IOService * provider )
268: {
269: return( true );
270: }
271:
272: void IOService::stop( IOService * /* provider */ )
273: {
274: }
275:
276: /*
277: * Attach in service plane
278: */
279: bool IOService::attach( IOService * provider )
280: {
281: bool ok;
282:
283: if( provider) {
284:
285: if( gIOKitDebug & kIOLogAttach)
286: LOG( "%s::attach(%s)\n", getName(),
287: provider->getName());
288:
289: provider->lockForArbitration();
290: if( provider->__state[0] & kIOServiceInactiveState)
291: ok = false;
292: else
293: ok = attachToParent( provider, gIOServicePlane);
294: provider->unlockForArbitration();
295:
296: } else {
297:
298: gIOServiceRoot = this;
299: ok = attachToParent( getRegistryRoot(), gIOServicePlane);
300: gIOResources->attachToParent( getRegistryRoot(),
301: gIOServicePlane );
302: publishResource("IOKit");
303: }
304:
305: return( ok );
306: }
307:
308: IOService * IOService::getServiceRoot( void )
309: {
310: return( gIOServiceRoot );
311: }
312:
313: void IOService::detach( IOService * provider )
314: {
315: if( gIOKitDebug & kIOLogAttach)
316: LOG("%s::detach(%s)\n", getName(), provider->getName());
317:
318: detachFromParent( provider, gIOServicePlane );
319: }
320:
321: /*
322: * Register instance - publish it for matching
323: */
324:
325: void IOService::registerService( IOOptionBits options = 0 )
326: {
327: char * pathBuf;
328: const char * path;
329: char * skip;
330: int len;
331: enum { kMaxPathLen = 256 };
332: enum { kMaxChars = 63 };
333:
334: // Allow the Platform Expert to adjust this node.
335: if (gIOPlatform)
336: if (!gIOPlatform->platformAdjustService(this))
337: return;
338:
339: if( (this != gIOResources)
340: && (kIOLogRegister & gIOKitDebug)) {
341:
342: pathBuf = (char *) IOMalloc( kMaxPathLen );
343:
344: IOLog( "Registering: " );
345:
346: len = kMaxPathLen;
347: if( pathBuf && getPath( pathBuf, &len, gIOServicePlane)) {
348:
349: path = pathBuf;
350: if( len > kMaxChars) {
351: IOLog("..");
352: len -= kMaxChars;
353: path += len;
354: if( (skip = strchr( path, '/')))
355: path = skip;
356: }
357: } else
358: path = getName();
359:
360: IOLog( "%s\n", path );
361:
362: if( pathBuf)
363: IOFree( pathBuf, kMaxPathLen );
364: }
365:
366: startMatching( options );
367: }
368:
369: void IOService::startMatching( IOOptionBits options = 0 )
370: {
371: IOService * provider;
372: bool needConfig;
373: bool ok;
374: bool sync;
375:
376: lockForArbitration();
377:
378: sync = (options & kIOServiceSynchronous)
379: || ((provider = getProvider())
380: && (provider->__state[1] & kIOServiceSynchronousState));
381: if( sync)
382: __state[1] |= kIOServiceSynchronousState;
383: else
384: __state[1] &= ~kIOServiceSynchronousState;
385:
386: needConfig = (0 == (__state[1] & kIOServiceConfigState))
387: && (0 == (__state[0] & kIOServiceInactiveState))
388: && (kIOServiceRegisteredState !=
389: (__state[0] & (kIOServiceRegisteredState
390: | kIOServiceMatchedState)));
391: __state[1] |= kIOServiceConfigState;
392: // __state[0] &= ~kIOServiceInactiveState;
393:
394: // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
395: // OSKernelStackRemaining(), getName());
396:
397: unlockForArbitration();
398:
399: if( needConfig) {
400: adjustBusy( 1 );
401: if( sync) {
402: doServiceMatch();
403: waitQuiet();
404: } else
405: ok = (0 != _IOServiceJob::startJob( this, kMatchNubJob ));
406: }
407: }
408:
409: IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables )
410: {
411: OSDictionary * table;
412: OSIterator * iter;
413: IOService * service;
414: #ifdef DEBUG
415: SInt32 count = 0;
416: #endif
417:
418: newTables->retain();
419:
420: while( (table = (OSDictionary *) newTables->getFirstObject())) {
421:
422: LOCKWRITENOTIFY();
423: iter = (OSIterator *) getExistingServices( table,
424: kIOServiceMatchedState );
425: UNLOCKNOTIFY();
426: if( iter) {
427: while( (service = (IOService *) iter->getNextObject())) {
428: service->startMatching();
429: #ifdef DEBUG
430: count++;
431: #endif
432: }
433: iter->release();
434: }
435: #ifdef DEBUG
436: if( getDebugFlags( table ) & kIOLogMatch)
437: LOG("Matching service count = %ld\n", count);
438: #endif
439: newTables->removeObject(table);
440: }
441:
442: newTables->release();
443:
444: return( kIOReturnSuccess );
445: }
446:
447: _IOServiceJob * _IOServiceJob::startJob( IOService * nub, int type,
448: IOOptionBits options = 0 )
449: {
450: _IOServiceJob * job;
451:
452: job = new _IOServiceJob;
453: if( job && !job->init()) {
454: job->release();
455: job = 0;
456: }
457:
458: if( job) {
459: job->type = type;
460: job->nub = nub;
461: job->options = options;
462: nub->retain(); // thread will release()
463: pingConfig( job );
464: }
465:
466: return( job );
467: }
468:
469: /*
470: * Called on a registered service to see if it matches
471: * a property table.
472: */
473:
474: bool IOService::matchPropertyTable( OSDictionary * table )
475: {
476: return( true );
477: }
478:
479: /*
480: * Called on a matched service to allocate resources
481: * before first driver is attached.
482: */
483:
484: IOReturn IOService::getResources( void )
485: {
486: return( kIOReturnSuccess);
487: }
488:
489: /*
490: * Client/provider accessors
491: */
492:
493: IOService * IOService::getProvider( void ) const
494: {
495: IOService * self = (IOService *) this;
496: IOService * parent;
497: SInt32 generation;
498:
499: parent = __provider;
500: generation = getGenerationCount();
501: if( __providerGeneration == generation)
502: return( parent );
503:
504: parent = (IOService *) getParentEntry( gIOServicePlane);
505: if( parent == IORegistryEntry::getRegistryRoot())
506: /* root is not an IOService */
507: parent = 0;
508:
509: self->__provider = parent;
510: // save the count before getParentEntry()
511: self->__providerGeneration = generation;
512:
513: return( parent );
514: }
515:
516: IOWorkLoop * IOService::getWorkLoop() const
517: {
518: return getProvider()->getWorkLoop();
519: }
520:
521: OSIterator * IOService::getProviderIterator( void ) const
522: {
523: return( getParentIterator( gIOServicePlane));
524: }
525:
526: IOService * IOService::getClient( void ) const
527: {
528: return( (IOService *) getChildEntry( gIOServicePlane));
529: }
530:
531: OSIterator * IOService::getClientIterator( void ) const
532: {
533: return( getChildIterator( gIOServicePlane));
534: }
535:
536: OSIterator * _IOOpenServiceIterator::iterator( OSIterator * _iter,
537: const IOService * client,
538: const IOService * provider )
539: {
540: _IOOpenServiceIterator * inst;
541:
542: if( !_iter)
543: return( 0 );
544:
545: inst = new _IOOpenServiceIterator;
546:
547: if( inst && !inst->init()) {
548: inst->release();
549: inst = 0;
550: }
551: if( inst) {
552: inst->iter = _iter;
553: inst->client = client;
554: inst->provider = provider;
555: }
556:
557: return( inst );
558: }
559:
560: void _IOOpenServiceIterator::free()
561: {
562: iter->release();
563: if( last)
564: last->unlockForArbitration();
565: OSIterator::free();
566: }
567:
568: OSObject * _IOOpenServiceIterator::getNextObject()
569: {
570: IOService * next;
571:
572: if( last)
573: last->unlockForArbitration();
574:
575: while( (next = (IOService *) iter->getNextObject())) {
576:
577: next->lockForArbitration();
578: if( (client && (next->isOpen( client )))
579: || (provider && (provider->isOpen( next ))) )
580: break;
581: next->unlockForArbitration();
582: }
583:
584: last = next;
585:
586: return( next );
587: }
588:
589: bool _IOOpenServiceIterator::isValid()
590: {
591: return( iter->isValid() );
592: }
593:
594: void _IOOpenServiceIterator::reset()
595: {
596: if( last) {
597: last->unlockForArbitration();
598: last = 0;
599: }
600: iter->reset();
601: }
602:
603: OSIterator * IOService::getOpenProviderIterator( void ) const
604: {
605: return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
606: }
607:
608: OSIterator * IOService::getOpenClientIterator( void ) const
609: {
610: return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
611: }
612:
613:
614: /*
615: * Platform expert accessors
616: */
617:
618: IOPlatformExpert * IOService::getPlatform( void )
619: {
620: return( gIOPlatform);
621: }
622:
623: void IOService::setPlatform( IOPlatformExpert * platform)
624: {
625: gIOPlatform = platform;
626: }
627:
628: /*
629: * Stacking change
630: */
631:
632: bool IOService::lockForArbitration( bool isSuccessRequired = true )
633: {
634: bool found;
635: bool success;
636: ArbitrationLockQueueElement * element;
637: ArbitrationLockQueueElement * active;
638: ArbitrationLockQueueElement * waiting;
639:
640: enum { kPutOnFreeQueue, kPutOnActiveQueue, kPutOnWaitingQueue } action;
641:
642: // lock global access
643: IOTakeLock( gArbitrationLockQueueLock );
644:
645: // obtain an unused queue element
646: if( !queue_empty( &gArbitrationLockQueueFree )) {
647: queue_remove_first( &gArbitrationLockQueueFree,
648: element,
649: ArbitrationLockQueueElement *,
650: link );
651: } else {
652: element = IONew( ArbitrationLockQueueElement, 1 );
653: assert( element );
654: }
655:
656: // prepare the queue element
657: element->thread = IOThreadSelf();
658: element->service = this;
659: element->count = 1;
660: element->required = isSuccessRequired;
661: element->aborted = false;
662:
663: // determine whether this object is already locked (ie. on active queue)
664: found = false;
665: queue_iterate( &gArbitrationLockQueueActive,
666: active,
667: ArbitrationLockQueueElement *,
668: link )
669: {
670: if( active->service == element->service ) {
671: found = true;
672: break;
673: }
674: }
675:
676: if( found ) { // this object is already locked
677:
678: // determine whether it is the same or a different thread trying to lock
679: if( active->thread != element->thread ) { // it is a different thread
680:
681: ArbitrationLockQueueElement * victim = 0;
682:
683: // before placing this new thread on the waiting queue, we look for
684: // a deadlock cycle...
685:
686: while( 1 ) {
687: // determine whether the active thread holding the object we
688: // want is waiting for another object to be unlocked
689: found = false;
690: queue_iterate( &gArbitrationLockQueueWaiting,
691: waiting,
692: ArbitrationLockQueueElement *,
693: link )
694: {
695: if( waiting->thread == active->thread ) {
696: assert( false == waiting->aborted );
697: found = true;
698: break;
699: }
700: }
701:
702: if( found ) { // yes, active thread waiting for another object
703:
704: // this may be a candidate for rejection if the required
705: // flag is not set, should we detect a deadlock later on
706: if( false == waiting->required )
707: victim = waiting;
708:
709: // find the thread that is holding this other object, that
710: // is blocking the active thread from proceeding (fun :-)
711: found = false;
712: queue_iterate( &gArbitrationLockQueueActive,
713: active, // (reuse active queue element)
714: ArbitrationLockQueueElement *,
715: link )
716: {
717: if( active->service == waiting->service ) {
718: found = true;
719: break;
720: }
721: }
722:
723: // someone must be holding it or it wouldn't be waiting
724: assert( found );
725:
726: if( active->service == element->service ) {
727:
728: // doh, it's waiting for the thread that originated
729: // this whole lock (ie. current thread) -> deadlock
730: if( false == element->required ) { // willing to fail?
731:
732: // the originating thread doesn't have the required
733: // flag, so it can fail
734: success = false; // (fail originating lock request)
735: break; // (out of while)
736:
737: } else { // originating thread is not willing to fail
738:
739: // see if we came across a waiting thread that did
740: // not have the 'required' flag set: we'll fail it
741: if( victim ) {
742:
743: // we do have a willing victim, fail it's lock
744: victim->aborted = true;
745:
746: // take the victim off the waiting queue
747: queue_remove( &gArbitrationLockQueueWaiting,
748: victim,
749: ArbitrationLockQueueElement *,
750: link );
751:
752: // wake the victim
753: thread_wakeup_one(victim);
754:
755: // allow this thread to proceed (ie. wait)
756: success = true; // (put request on wait queue)
757: break; // (out of while)
758: } else {
759:
760: // all the waiting threads we came across in
761: // finding this loop had the 'required' flag
762: // set, so we've got a deadlock we can't avoid
763: panic("I/O Kit: Unrecoverable deadlock.");
764: }
765: }
766: } else {
767: // repeat while loop, redefining active thread to be the
768: // thread holding "this other object" (see above), and
769: // looking for threads waiting on it; note the active
770: // variable points to "this other object" already... so
771: // there nothing to do in this else clause.
772: }
773: } else { // no, active thread is not waiting for another object
774:
775: success = true; // (put request on wait queue)
776: break; // (out of while)
777: }
778: } // while forever
779:
780: if( success ) { // put the request on the waiting queue?
781:
782: // place this thread on the waiting queue and put it to sleep;
783: // we place it at the tail of the queue...
784: queue_enter( &gArbitrationLockQueueWaiting,
785: element,
786: ArbitrationLockQueueElement *,
787: link );
788:
789: // declare that this thread will wait for an given event
790: assert_wait(element, THREAD_UNINT);
791:
792: // unlock global access
793: IOUnlock( gArbitrationLockQueueLock );
794:
795: // put thread to sleep, waiting for the our event to fire...
796: thread_block((void (*)(void)) 0);
797:
798: assert( THREAD_AWAKENED == thread_wait_result() );
799:
800: // ...and we've been woken up; we might be one of two states:
801: // (a) we've been aborted and our queue element is not on
802: // any of the three queues, but is floating around
803: // (b) we're allowed to proceed with the lock and we have
804: // already been moved from the waiting queue to the
805: // active queue.
806:
807: // determine whether we've been aborted while we were asleep
808: if( element->aborted ) {
809: assert( false == element->required );
810:
811: // re-lock global access
812: IOTakeLock( gArbitrationLockQueueLock );
813:
814: action = kPutOnFreeQueue;
815: success = false;
816: } else { // we weren't aborted, so we must be ready to go :-)
817:
818: // we've already been moved from waiting to active queue
819: return true;
820: }
821:
822: } else { // the lock request is to be failed
823:
824: // return unused queue element to queue
825: action = kPutOnFreeQueue;
826: }
827: } else { // it is the same thread, recursive access is allowed
828:
829: // add one level of recursion
830: active->count++;
831:
832: // return unused queue element to queue
833: action = kPutOnFreeQueue;
834: success = true;
835: }
836: } else { // this object is not already locked, so let this thread through
837: action = kPutOnActiveQueue;
838: success = true;
839: }
840:
841: // put the new element on a queue
842: if( kPutOnActiveQueue == action ) {
843: queue_enter( &gArbitrationLockQueueActive,
844: element,
845: ArbitrationLockQueueElement *,
846: link );
847: } else if( kPutOnFreeQueue == action ) {
848: queue_enter( &gArbitrationLockQueueFree,
849: element,
850: ArbitrationLockQueueElement *,
851: link );
852: } else {
853: assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
854: }
855:
856: // unlock global access
857: IOUnlock( gArbitrationLockQueueLock );
858:
859: return( success );
860: }
861:
862: void IOService::unlockForArbitration( void )
863: {
864: bool found;
865: ArbitrationLockQueueElement * element;
866:
867: // lock global access
868: IOTakeLock( gArbitrationLockQueueLock );
869:
870: // find the lock element for this object (ie. on active queue)
871: found = false;
872: queue_iterate( &gArbitrationLockQueueActive,
873: element,
874: ArbitrationLockQueueElement *,
875: link )
876: {
877: if( element->service == this ) {
878: found = true;
879: break;
880: }
881: }
882:
883: assert( found );
884:
885: // determine whether the lock has been taken recursively
886: if( element->count > 1 ) {
887: // undo one level of recursion
888: element->count--;
889:
890: } else {
891:
892: // remove it from the active queue
893: queue_remove( &gArbitrationLockQueueActive,
894: element,
895: ArbitrationLockQueueElement *,
896: link );
897:
898: // put it on the free queue
899: queue_enter( &gArbitrationLockQueueFree,
900: element,
901: ArbitrationLockQueueElement *,
902: link );
903:
904: // determine whether a thread is waiting for object (head to tail scan)
905: found = false;
906: queue_iterate( &gArbitrationLockQueueWaiting,
907: element,
908: ArbitrationLockQueueElement *,
909: link )
910: {
911: if( element->service == this ) {
912: found = true;
913: break;
914: }
915: }
916:
917: if ( found ) { // we found an interested thread on waiting queue
918:
919: // remove it from the waiting queue
920: queue_remove( &gArbitrationLockQueueWaiting,
921: element,
922: ArbitrationLockQueueElement *,
923: link );
924:
925: // put it on the active queue
926: queue_enter( &gArbitrationLockQueueActive,
927: element,
928: ArbitrationLockQueueElement *,
929: link );
930:
931: // wake the waiting thread
932: thread_wakeup_one(element);
933: }
934: }
935:
936: // unlock global access
937: IOUnlock( gArbitrationLockQueueLock );
938: }
939:
940: void IOService::applyToProviders( IOServiceApplierFunction applier,
941: void * context )
942: {
943: applyToParents( (IORegistryEntryApplierFunction) applier,
944: context, gIOServicePlane );
945: }
946:
947: void IOService::applyToClients( IOServiceApplierFunction applier,
948: void * context )
949: {
950: applyToChildren( (IORegistryEntryApplierFunction) applier,
951: context, gIOServicePlane );
952: }
953:
954:
955: /*
956: * Client messages
957: */
958:
959:
960: // send a message to a client or interested party of this service
961: IOReturn IOService::messageClient( UInt32 type, OSObject * client,
962: void * argument = 0, vm_size_t argSize = 0 )
963: {
964: IOReturn ret;
965: IOService * service;
966: _IOServiceInterestNotifier * interested;
967:
968: if( (service = OSDynamicCast( IOService, client)))
969: ret = service->message( type, this, argument );
970:
971: else if( (interested = OSDynamicCast( _IOServiceInterestNotifier, client))) {
972: if( interested->fEnable)
973: ret = (*interested->handler)( interested->target, interested->ref,
974: type, this, argument, argSize );
975: else
976: ret = kIOReturnSuccess;
977:
978: } else
979: ret = kIOReturnBadArgument;
980:
981: return( ret );
982: }
983:
984: void IOService::applyToInterested( const OSSymbol * typeOfInterest,
985: OSObjectApplierFunction applier,
986: void * context )
987: {
988: OSArray * array;
989: unsigned int index;
990: OSObject * next;
991:
992: applyToClients( (IOServiceApplierFunction) applier, context );
993:
994: array = OSDynamicCast( OSArray, getProperty( typeOfInterest ));
995: if( array) {
996: LOCKREADNOTIFY();
997: for( index = 0;
998: (next = array->getObject( index ));
999: index++) {
1000: (*applier)(next, context);
1001: }
1002: UNLOCKNOTIFY();
1003: }
1004: }
1005:
1006: struct MessageClientsContext {
1007: IOService * service;
1008: UInt32 type;
1009: void * argument;
1010: vm_size_t argSize;
1011: IOReturn ret;
1012: };
1013:
1014: static void messageClientsApplier( OSObject * object, void * ctx )
1015: {
1016: IOReturn ret;
1017: MessageClientsContext * context = (MessageClientsContext *) ctx;
1018:
1019: ret = context->service->messageClient( context->type,
1020: object, context->argument, context->argSize );
1021: if( kIOReturnSuccess != ret)
1022: context->ret = ret;
1023: }
1024:
1025: // send a message to all clients
1026: IOReturn IOService::messageClients( UInt32 type,
1027: void * argument = 0, vm_size_t argSize = 0 )
1028: {
1029: MessageClientsContext context;
1030:
1031: context.service = this;
1032: context.type = type;
1033: context.argument = argument;
1034: context.argSize = argSize;
1035: context.ret = kIOReturnSuccess;
1036:
1037: applyToInterested( gIOGeneralInterest,
1038: &messageClientsApplier, &context );
1039:
1040: return( context.ret );
1041: }
1042:
1043: IOReturn IOService::acknowledgeNotification( IONotificationRef notification,
1044: IOOptionBits response )
1045: {
1046: return( kIOReturnUnsupported );
1047: }
1048:
1049: IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest,
1050: IOServiceInterestHandler handler, void * target, void * ref )
1051: {
1052: _IOServiceInterestNotifier * notify = 0;
1053: OSArray * set;
1054:
1055: if( (typeOfInterest != gIOGeneralInterest)
1056: && (typeOfInterest != gIOBusyInterest))
1057: return( 0 );
1058:
1059: lockForArbitration();
1060: if( 0 == (__state[0] & kIOServiceInactiveState)) {
1061:
1062: notify = new _IOServiceInterestNotifier;
1063: if( notify && !notify->init()) {
1064: notify->release();
1065: notify = 0;
1066: }
1067:
1068: if( notify) {
1069: notify->handler = handler;
1070: notify->target = target;
1071: notify->ref = ref;
1072: notify->fEnable = true;
1073:
1074: ////// queue
1075:
1076: LOCKWRITENOTIFY();
1077: if( 0 == (set = (OSArray *) getProperty( typeOfInterest ))) {
1078: set = OSArray::withCapacity( 1 );
1079: if( set) {
1080: setProperty( typeOfInterest, set );
1081: set->release();
1082: }
1083: }
1084: notify->whence = set;
1085: if( set)
1086: set->setObject( notify );
1087: UNLOCKNOTIFY();
1088: }
1089: }
1090: unlockForArbitration();
1091:
1092: return( notify );
1093: }
1094:
1095: static void cleanInterestArray( OSObject * object )
1096: {
1097: OSArray * array;
1098: unsigned int index;
1099: _IOServiceInterestNotifier * next;
1100:
1101: if( (array = OSDynamicCast( OSArray, object))) {
1102: LOCKWRITENOTIFY();
1103: for( index = 0;
1104: (next = (_IOServiceInterestNotifier *)
1105: array->getObject( index ));
1106: index++) {
1107: next->whence = 0;
1108: }
1109: UNLOCKNOTIFY();
1110: }
1111: }
1112:
1113: void IOService::unregisterAllInterest( void )
1114: {
1115: cleanInterestArray( getProperty( gIOGeneralInterest ));
1116: cleanInterestArray( getProperty( gIOBusyInterest ));
1117: }
1118:
1119: /*
1120: * _IOServiceInterestNotifier
1121: */
1122:
1123: void _IOServiceInterestNotifier::remove()
1124: {
1125: LOCKWRITENOTIFY();
1126:
1127: if( whence) {
1128: whence->removeObject(whence->getNextIndexOfObject(
1129: (OSObject *) this, 0 ));
1130: whence = 0;
1131: }
1132:
1133: fEnable = false;
1134:
1135: UNLOCKNOTIFY();
1136:
1137: release();
1138: }
1139:
1140: bool _IOServiceInterestNotifier::disable()
1141: {
1142: bool ret;
1143:
1144: LOCKWRITENOTIFY();
1145: ret = fEnable;
1146: fEnable = false;
1147: UNLOCKNOTIFY();
1148:
1149: return( ret );
1150: }
1151:
1152: void _IOServiceInterestNotifier::enable( bool was )
1153: {
1154: LOCKWRITENOTIFY();
1155: fEnable = was;
1156: UNLOCKNOTIFY();
1157: }
1158:
1159: /*
1160: * Terminate
1161: */
1162:
1163: // a method in case someone needs to override it
1164: bool IOService::terminateClient( IOService * client, IOOptionBits options )
1165: {
1166: bool ok;
1167:
1168: if( client->isParent( this, gIOServicePlane, true))
1169: // we are the clients only provider
1170: ok = client->terminate( options );
1171: else
1172: ok = true;
1173:
1174: return( ok );
1175: }
1176:
1177: struct TerminateClientsContext {
1178: IOService * provider;
1179: IOOptionBits options;
1180: };
1181:
1182: static void terminateClientsApplier( OSObject * object, void * ctx )
1183: {
1184: TerminateClientsContext * context = (TerminateClientsContext *) ctx;
1185: IOService * client;
1186:
1187: context->provider->messageClient( kIOMessageServiceIsTerminated,
1188: object, (void *) context->options );
1189:
1190: if( (client = OSDynamicCast( IOService, object))){
1191: if( gIOKitDebug & kIOLogYield)
1192: LOG("%s::terminateClient(%s,%08lx)\n",
1193: context->provider->getName(),
1194: client->getName(), context->options);
1195:
1196: context->provider->terminateClient(
1197: client, ((context->options) | kIOServiceRecursing)
1198: & ~kIOServiceSynchronous );
1199: }
1200: }
1201:
1202: bool IOService::terminate( IOOptionBits options = 0 )
1203: {
1204: bool ok;
1205: bool wasClosed;
1206: bool madeInactive;
1207: TerminateClientsContext context;
1208:
1209: if( false == lockForArbitration( (options & kIOServiceRequired) ))
1210: return false;
1211:
1212: retain();
1213:
1214: ok = (options & kIOServiceRequired);
1215: wasClosed = (false == handleIsOpen( 0 ));
1216: if( !ok)
1217: ok = wasClosed;
1218:
1219: if( ok) {
1220: madeInactive = (0 == (__state[0] & kIOServiceInactiveState));
1221: if( madeInactive) {
1222: __state[0] |= kIOServiceInactiveState;
1223: __state[0] &= ~(kIOServiceRegisteredState | kIOServiceMatchedState);
1224: if( 0 == (options & kIOServiceRecursing))
1225: __state[1] |= kIOServiceTerminatedState;
1226: }
1227: } else
1228: madeInactive = false;
1229:
1230: unlockForArbitration();
1231:
1232: if( madeInactive) {
1233:
1234: adjustBusy( 1 );
1235: context.provider = this;
1236: context.options = options;
1237: applyToInterested( gIOGeneralInterest,
1238: &terminateClientsApplier, (void *) &context );
1239:
1240: if( wasClosed && (0 == (options & kIOServiceRecursing))) {
1241: if( options & kIOServiceSynchronous)
1242: doServiceTerminate( 0 );
1243: else
1244: ok = (0 != _IOServiceJob::startJob( this, kTerminateNubJob, 0 ));
1245: }
1246: if( options & kIOServiceSynchronous)
1247: waitQuiet();
1248: }
1249:
1250: release();
1251:
1252: return( ok );
1253: }
1254:
1255: void IOService::doServiceTerminate( IOOptionBits options )
1256: {
1257: IOService * next;
1258: OSIterator * iter;
1259: IOService * client;
1260: OSArray * deathList = 0;
1261: unsigned int index;
1262: bool finalize;
1263: bool ok = true;
1264:
1265: next = this;
1266: deathList = OSArray::withObjects( (OSObject **)&next, 1, 1 );
1267: assert( deathList );
1268: if( !deathList)
1269: return;
1270:
1271: index = 0;
1272: do {
1273: iter = next->getClientIterator();
1274: assert( iter );
1275: if( iter) {
1276:
1277: while( (client = (IOService *) iter->getNextObject())) {
1278:
1279: if( gIOKitDebug & kIOLogYield)
1280: LOG("%s::actionClients(%s)\n",
1281: next->getName(), client->getName());
1282:
1283: client->stop( next );
1284:
1285: if( next->isOpen( client ))
1286: next->close( client );
1287:
1288: client->detach( next );
1289:
1290: client->lockForArbitration();
1291: if( (client->__state[0] & kIOServiceInactiveState)
1292: && (0 == (client->__state[1] & kIOServiceTerminatedState))
1293: && (0 == client->getProvider()) ) {
1294: client->__state[1] |= kIOServiceTerminatedState;
1295: finalize = (false == client->handleIsOpen( 0 ));
1296: } else
1297: finalize = false;
1298: client->unlockForArbitration();
1299:
1300: if( finalize) {
1301: next->adjustBusy( -1 ); // because the client is detached now
1302: // and won't adjust its provider busy count
1303: deathList->setObject( client );
1304: }
1305: }
1306: iter->release();
1307: }
1308:
1309: } while( (next = (IOService *) deathList->getObject( ++index )) );
1310:
1311: while( index--) {
1312:
1313: next = (IOService *) deathList->getObject( index );
1314: assert( next );
1315: next->retain();
1316: deathList->removeObject( index );
1317:
1318: next->deliverNotification( gIOTerminatedNotification, 0, 0xffffffff );
1319:
1320: IOUserClient::destroyUserReferences( next );
1321:
1322: next->unregisterAllInterest();
1323:
1324: ok = next->finalize( options );
1325: assert( ok );
1326:
1327: if( gIOKitDebug & kIOLogYield)
1328: LOG("%s __state = %08lx:%08lx\n", next->getName(),
1329: next->__state[0], next->__state[1]);
1330: next->adjustBusy( -1 );
1331:
1332: next->release();
1333: }
1334:
1335: deathList->release();
1336: }
1337:
1338: bool IOService::finalize( IOOptionBits options )
1339: {
1340: OSIterator * iter;
1341: IOService * provider;
1342:
1343: iter = getProviderIterator();
1344: assert( iter );
1345:
1346: if( iter) {
1347: while( (provider = (IOService *) iter->getNextObject())) {
1348: stop( provider );
1349: if( provider->isOpen( this ))
1350: provider->close( this );
1351: detach( provider );
1352: provider->adjustBusy( -1 );
1353: }
1354: iter->release();
1355: }
1356:
1357: return( true );
1358: }
1359:
1360: /*
1361: * Open & close
1362: */
1363:
1364: bool IOService::open( IOService * forClient,
1365: IOOptionBits options = 0,
1366: void * arg = 0 )
1367: {
1368: bool ok;
1369:
1370: if( false == lockForArbitration(false) )
1371: return false;
1372:
1373: ok = (0 == (__state[0] & kIOServiceInactiveState));
1374: if( ok)
1375: ok = handleOpen( forClient, options, arg );
1376:
1377: unlockForArbitration();
1378:
1379: return( ok );
1380: }
1381:
1382: void IOService::close( IOService * forClient,
1383: IOOptionBits options = 0 )
1384: {
1385: bool ok;
1386: bool wasClosed;
1387: bool last = false;
1388: OSIterator * iter;
1389: IOService * client;
1390:
1391: lockForArbitration();
1392:
1393: wasClosed = handleIsOpen( forClient );
1394: if( wasClosed) {
1395: handleClose( forClient, options );
1396:
1397: last = ( (__state[1] & kIOServiceTerminatedState)
1398: && (false == handleIsOpen( 0 )) );
1399: }
1400:
1401: unlockForArbitration();
1402:
1403: if( last) {
1404: ok = (0 != _IOServiceJob::startJob( this, kTerminateNubJob, 0 ));
1405: assert( ok );
1406:
1407: } else if( wasClosed) {
1408:
1409: iter = getClientIterator();
1410: assert( iter );
1411:
1412: if( iter) {
1413: while( (client = (IOService *) iter->getNextObject())) {
1414: if( client != forClient)
1415: messageClient( kIOMessageServiceWasClosed, client, 0 );
1416: }
1417: iter->release();
1418: }
1419: }
1420: }
1421:
1422: bool IOService::isOpen( const IOService * forClient = 0 ) const
1423: {
1424: IOService * self = (IOService *) this;
1425: bool ok;
1426:
1427: self->lockForArbitration();
1428:
1429: ok = handleIsOpen( forClient );
1430:
1431: self->unlockForArbitration();
1432:
1433: return( ok );
1434: }
1435:
1436: bool IOService::handleOpen( IOService * forClient,
1437: IOOptionBits options,
1438: void * arg )
1439: {
1440: bool ok;
1441:
1442: ok = (0 == __owner);
1443: if( ok )
1444: __owner = forClient;
1445:
1446: else if( options & kIOServiceSeize ) {
1447: ok = (kIOReturnSuccess == messageClient( kIOMessageServiceIsRequestingClose,
1448: __owner, (void *) options ));
1449: if( ok && (0 == __owner ))
1450: __owner = forClient;
1451: }
1452:
1453: return( ok );
1454: }
1455:
1456: void IOService::handleClose( IOService * forClient,
1457: IOOptionBits options )
1458: {
1459: if( __owner == forClient)
1460: __owner = 0;
1461: }
1462:
1463: bool IOService::handleIsOpen( const IOService * forClient ) const
1464: {
1465: if( forClient)
1466: return( __owner == forClient );
1467: else
1468: return( __owner != forClient );
1469: }
1470:
1471: /*
1472: * Probing & starting
1473: */
1474:
1475: SInt32 IONotifyOrdering( OSObject * obj1, OSObject * obj2, void * ref)
1476: {
1477: SInt32 val1;
1478: SInt32 val2;
1479:
1480: val1 = 0;
1481: val2 = 0;
1482:
1483: if ( obj1 )
1484: val1 = ((_IOServiceNotifier *)obj1)->priority;
1485:
1486: if ( obj2 )
1487: val2 = ((_IOServiceNotifier *)obj2)->priority;
1488:
1489: return ( val1 - val2 );
1490: }
1491:
1492: static SInt32 IOServiceObjectOrder( OSObject * entry, void * ref)
1493: {
1494: OSDictionary * dict;
1495: IOService * service;
1496: _IOServiceNotifier * notify;
1497: OSSymbol * key = (OSSymbol *) ref;
1498: OSNumber * offset;
1499:
1500: if( (notify = OSDynamicCast( _IOServiceNotifier, entry)))
1501: return( notify->priority );
1502:
1503: else if( (service = OSDynamicCast( IOService, entry)))
1504: offset = OSDynamicCast(OSNumber, service->getProperty( key ));
1505: else if( (dict = OSDynamicCast( OSDictionary, entry)))
1506: offset = OSDynamicCast(OSNumber, dict->getObject( key ));
1507: else {
1508: assert( false );
1509: offset = 0;
1510: }
1511:
1512: if( offset)
1513: return( (SInt32) offset->unsigned32BitValue());
1514: else
1515: return( kIODefaultProbeScore );
1516: }
1517:
1518: SInt32 IOServiceOrdering( OSObject * obj1, OSObject * obj2, void * ref )
1519: {
1520: SInt32 val1;
1521: SInt32 val2;
1522:
1523: val1 = 0;
1524: val2 = 0;
1525:
1526: if ( obj1 )
1527: val1 = IOServiceObjectOrder( obj1, ref );
1528:
1529: if ( obj2 )
1530: val2 = IOServiceObjectOrder( obj2, ref );
1531:
1532: return ( val1 - val2 );
1533: }
1534:
1535: IOService * IOService::getClientWithCategory( const OSSymbol * category )
1536: {
1537: IOService * service = 0;
1538: OSIterator * iter;
1539: const OSSymbol * nextCat;
1540:
1541: iter = getClientIterator();
1542: if( iter) {
1543: while( (service = (IOService *) iter->getNextObject())) {
1544: if( kIOServiceInactiveState & service->__state[0])
1545: continue;
1546: nextCat = (const OSSymbol *) OSDynamicCast( OSSymbol,
1547: service->getProperty( gIOMatchCategoryKey ));
1548: if( category == nextCat)
1549: break;
1550: }
1551: iter->release();
1552: }
1553: return( service );
1554: }
1555:
1556: /*
1557: * Alloc and probe matching classes,
1558: * called on the provider instance
1559: */
1560:
1561: void IOService::probeCandidates( OSOrderedSet * matches )
1562: {
1563: OSDictionary * match;
1564: OSSymbol * symbol;
1565: IOService * inst;
1566: IOService * newInst;
1567: OSDictionary * props;
1568: SInt32 score;
1569: OSNumber * newPri;
1570: OSOrderedSet * startList;
1571: OSDictionary * startDict = 0;
1572: const OSSymbol * category;
1573: OSIterator * iter;
1574: _IOServiceNotifier * notify;
1575: OSObject * nextMatch;
1576: bool started;
1577: bool needReloc = false;
1578: bool needsCat;
1579: #ifdef DEBUG
1580: SInt64 debugFlags;
1581: #endif
1582:
1583: assert( matches );
1584: while( (nextMatch = matches->getFirstObject())) {
1585:
1586: nextMatch->retain();
1587: matches->removeObject(nextMatch);
1588:
1589: if( (notify = OSDynamicCast( _IOServiceNotifier, nextMatch ))) {
1590:
1591: lockForArbitration();
1592: LOCKREADNOTIFY();
1593: if( notify->fEnable
1594: && (0 == (__state[0] & kIOServiceInactiveState)))
1595: (*notify->handler)( notify->target, notify->ref, this );
1596: UNLOCKNOTIFY();
1597: unlockForArbitration();
1598: nextMatch->release();
1599: continue;
1600:
1601: } else if( !(match = OSDynamicCast( OSDictionary, nextMatch ))) {
1602: nextMatch->release();
1603: continue;
1604: }
1605:
1606: props = 0;
1607: inst = 0;
1608: newInst = 0;
1609: #ifdef DEBUG
1610: debugFlags = getDebugFlags( match );
1611: #endif
1612:
1613: do {
1614: category = OSDynamicCast( OSSymbol,
1615: match->getObject( gIOMatchCategoryKey ));
1616: needsCat = (0 == category);
1617: if( needsCat)
1618: category = gIODefaultMatchCategoryKey;
1619:
1620: if( getClientWithCategory( category )) {
1621: #ifdef DEBUG
1622: if( debugFlags & kIOLogMatch)
1623: LOG("%s: match category %s exists\n", getName(),
1624: category->getCStringNoCopy());
1625: #endif
1626: nextMatch->release();
1627: continue;
1628: }
1629:
1630: // create a copy now in case its modified during matching
1631: props = OSDictionary::withDictionary( match, match->getCount());
1632: nextMatch->release();
1633: if( 0 == props)
1634: continue;
1635: props->setCapacityIncrement(1);
1636:
1637: // check the nub matches
1638: if( false == passiveMatch( props, true ))
1639: continue;
1640:
1641: // Check to see if driver reloc has been loaded.
1642: needReloc = (false == gIOCatalogue->isModuleLoaded( match ));
1643: if( needReloc) {
1644: #ifdef DEBUG
1645: if( debugFlags & kIOLogCatalogue)
1646: LOG("%s: stalling for module\n", getName());
1647: #endif
1648: continue;
1649: }
1650:
1651: symbol = OSDynamicCast( OSSymbol,
1652: props->getObject( gIOClassKey));
1653: if( !symbol)
1654: continue;
1655:
1656: // alloc the driver instance
1657: inst = (IOService *) OSMetaClass::allocClassWithName( symbol);
1658:
1659: if( !inst) {
1660: IOLog("Couldn't alloc %s; class not ",
1661: symbol->getCStringNoCopy());
1662: if( OSMetaClass::getMetaClassWithName( symbol))
1663: IOLog("using default constructor\n");
1664: else
1665: IOLog("available\n");
1666: continue;
1667: }
1668:
1669: // init driver instance
1670: if( !(inst->init( props ))) {
1671: #ifdef DEBUG
1672: if( debugFlags & kIOLogStart)
1673: IOLog("%s::init fails\n", symbol->getCStringNoCopy());
1674: #endif
1675: continue;
1676: }
1677: if( __state[1] & kIOServiceSynchronousState)
1678: inst->__state[1] |= kIOServiceSynchronousState;
1679:
1680: // give the driver the default match category if not specified
1681: if( needsCat)
1682: inst->setProperty( gIOMatchCategoryKey, (OSObject *) category );
1683:
1684: // attach driver instance
1685: if( !(inst->attach( this )))
1686: continue;
1687:
1688: // pass in score from property table
1689: score = matches->orderObject( match );
1690:
1691: // & probe the new driver instance
1692: #ifdef DEBUG
1693: if( debugFlags & kIOLogProbe)
1694: LOG("%s::probe(%s)\n",
1695: inst->getMetaClass()->getClassName(), getName());
1696: #endif
1697:
1698: #if 1
1699: newInst = inst->probe( this, &score );
1700: inst->detach( this );
1701: if( 0 == newInst) {
1702: #ifdef DEBUG
1703: if( debugFlags & kIOLogProbe)
1704: IOLog("%s::probe fails\n", symbol->getCStringNoCopy());
1705: #endif
1706: continue;
1707: }
1708: #else
1709: if( 0 == (newInst = inst->probe( this, &score ))) {
1710: #ifdef DEBUG
1711: if( debugFlags & kIOLogProbe)
1712: IOLog("%s::probe fails\n", symbol->getCStringNoCopy());
1713: #endif
1714: inst->detach( this );
1715: continue;
1716: }
1717:
1718: if( newInst != inst) {
1719: // instance substitution
1720: inst->detach( this );
1721: // attach the returned instance
1722: if( !(newInst->attach( this )))
1723: continue;
1724: }
1725: #endif
1726:
1727: // save the score
1728: newPri = OSNumber::withNumber( score, 32 );
1729: if( newPri) {
1730: newInst->setProperty( gIOProbeScoreKey, newPri );
1731: newPri->release();
1732: }
1733:
1734: // add to start list for the match category
1735: if( 0 == startDict)
1736: startDict = OSDictionary::withCapacity( 1 );
1737: assert( startDict );
1738: startList = (OSOrderedSet *)
1739: startDict->getObject( category );
1740: if( 0 == startList) {
1741: startList = OSOrderedSet::withCapacity( 1,
1742: IOServiceOrdering, (void *) gIOProbeScoreKey );
1743: if( startDict && startList) {
1744: startDict->setObject( category, startList );
1745: startList->release();
1746: }
1747: }
1748: assert( startList );
1749: if( startList)
1750: startList->setObject( newInst );
1751:
1752: } while( false );
1753:
1754: if( props)
1755: props->release();
1756: if( inst)
1757: inst->release();
1758:
1759: // If reloc hasn't been loaded, exit out of function cleanly.
1760: // Re-probing will occur after reloc has been loaded.
1761: if( needReloc ) {
1762: if( startDict ) {
1763: startDict->release();
1764: startDict = 0;
1765: }
1766: break;
1767: }
1768: }
1769: matches->release();
1770:
1771: // start the best (until success) of each category
1772:
1773: iter = OSCollectionIterator::withCollection( startDict );
1774: if( iter) {
1775: while( (category = (const OSSymbol *) iter->getNextObject())) {
1776:
1777: startList = (OSOrderedSet *) startDict->getObject( category );
1778: assert( startList );
1779: if( !startList)
1780: continue;
1781:
1782: started = false;
1783: while( true // (!started)
1784: && (inst = (IOService *)startList->getFirstObject())) {
1785:
1786: inst->retain();
1787: startList->removeObject(inst);
1788:
1789: #ifdef DEBUG
1790: debugFlags = getDebugFlags( inst->getPropertyTable() );
1791:
1792: if( debugFlags & kIOLogStart) {
1793: if( started)
1794: LOG( "match category exists, skipping " );
1795: LOG( "%s::start(%s) <%d>\n", inst->getName(),
1796: getName(), inst->getRetainCount());
1797: }
1798: #endif
1799: if( false == started)
1800: started = startCandidate( inst );
1801: #ifdef DEBUG
1802: if( (debugFlags & kIOLogStart) && (false == started))
1803: LOG( "%s::start(%s) <%d> failed\n", inst->getName(), getName(),
1804: inst->getRetainCount());
1805: #endif
1806: inst->release();
1807: }
1808: }
1809: iter->release();
1810: }
1811:
1812: if( startDict)
1813: startDict->release();
1814: }
1815:
1816: /*
1817: * Start a previously attached & probed instance,
1818: * called on exporting object instance
1819: */
1820:
1821: bool IOService::startCandidate( IOService * service )
1822: {
1823: bool ok;
1824:
1825: ok = service->attach( this );
1826:
1827: if( ok) {
1828: // stall for any nub resources
1829: checkResources();
1830: // stall for any driver resources
1831: service->checkResources();
1832:
1833: ok = service->start( this );
1834: if( !ok)
1835: service->detach( this );
1836: }
1837: return( ok );
1838: }
1839:
1840: IOService * IOService::resources( void )
1841: {
1842: return( gIOResources );
1843: }
1844:
1845: void IOService::publishResource( const char * key, OSObject * value = 0 )
1846: {
1847: const OSSymbol * sym;
1848:
1849: if( (sym = OSSymbol::withCString( key))) {
1850: publishResource( sym, value);
1851: sym->release();
1852: }
1853: }
1854:
1855: void IOService::publishResource( const OSSymbol * key, OSObject * value = 0 )
1856: {
1857: if( 0 == value)
1858: value = (OSObject *) gIOServiceKey;
1859:
1860: gIOResources->setProperty( key, value);
1861:
1862: gIOResourceGenerationCount++;
1863: gIOResources->registerService();
1864: }
1865:
1866: bool IOService::addNeededResource( const char * key )
1867: {
1868: OSObject * resources;
1869: OSSet * set;
1870: OSString * newKey;
1871: bool ret;
1872:
1873: resources = getProperty( gIOResourceMatchKey );
1874:
1875: newKey = OSString::withCString( key );
1876: if( (0 == resources) || (0 == newKey))
1877: return( false);
1878:
1879: set = OSDynamicCast( OSSet, resources );
1880: if( !set) {
1881: set = OSSet::withCapacity( 1 );
1882: if( set)
1883: set->setObject( resources );
1884: }
1885: else
1886: set->retain();
1887:
1888: set->setObject( newKey );
1889: newKey->release();
1890: ret = setProperty( gIOResourceMatchKey, set );
1891: set->release();
1892:
1893: return( ret );
1894: }
1895:
1896: bool IOService::checkResource( OSObject * matching )
1897: {
1898: OSString * str;
1899: OSDictionary * table;
1900:
1901: if( (str = OSDynamicCast( OSString, matching ))) {
1902: if( gIOResources->getProperty( str ))
1903: return( true );
1904: }
1905:
1906: if( str)
1907: table = resourceMatching( str );
1908: else if( (table = OSDynamicCast( OSDictionary, matching )))
1909: table->retain();
1910: else {
1911: IOLog("%s: Can't match using: %s\n", getName(),
1912: matching->getMetaClass()->getClassName());
1913: /* false would stall forever */
1914: return( true );
1915: }
1916:
1917: if( gIOKitDebug & kIOLogConfig)
1918: LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName());
1919:
1920: waitForService( table );
1921:
1922: if( gIOKitDebug & kIOLogConfig)
1923: LOG("config(%x): waking\n", (int) IOThreadSelf() );
1924:
1925: return( true );
1926: }
1927:
1928: bool IOService::checkResources( void )
1929: {
1930: OSObject * resources;
1931: OSSet * set;
1932: OSIterator * iter;
1933: bool ok;
1934:
1935: resources = getProperty( gIOResourceMatchKey );
1936: if( 0 == resources)
1937: return( true );
1938:
1939: if( (set = OSDynamicCast( OSSet, resources ))) {
1940:
1941: iter = OSCollectionIterator::withCollection( set );
1942: ok = (0 != iter);
1943: while( ok && (resources = iter->getNextObject()) )
1944: ok = checkResource( resources );
1945: if( iter)
1946: iter->release();
1947:
1948: } else
1949: ok = checkResource( resources );
1950:
1951: return( ok );
1952: }
1953:
1954:
1955: _IOConfigThread * _IOConfigThread::configThread( void )
1956: {
1957: _IOConfigThread * inst;
1958:
1959: do {
1960: if( !(inst = new _IOConfigThread))
1961: continue;
1962: if( !inst->init())
1963: continue;
1964: if( !(inst->thread = IOCreateThread
1965: ( (IOThreadFunc) &_IOConfigThread::main, inst )))
1966: continue;
1967:
1968: return( inst );
1969:
1970: } while( false);
1971:
1972: if( inst)
1973: inst->release();
1974:
1975: return( 0 );
1976: }
1977:
1978: void _IOConfigThread::free( void )
1979: {
1980: OSObject::free();
1981: }
1982:
1983: void IOService::doServiceMatch( void )
1984: {
1985: _IOServiceNotifier * notify;
1986: OSIterator * iter;
1987: OSOrderedSet * matches;
1988: SInt32 catalogGeneration;
1989: bool keepGuessing = true;
1990: bool reRegistered = true;
1991:
1992: // job->nub->deliverNotification( gIOPublishNotification,
1993: // kIOServiceRegisteredState, 0xffffffff );
1994:
1995: while( keepGuessing ) {
1996:
1997: matches = gIOCatalogue->findDrivers( this, &catalogGeneration );
1998: // the matches list should always be created by findDrivers()
1999: if( matches) {
2000:
2001: lockForArbitration();
2002: if( 0 == (__state[0] & kIOServiceFirstPublishState))
2003: deliverNotification( gIOFirstPublishNotification,
2004: kIOServiceFirstPublishState, 0xffffffff );
2005: LOCKREADNOTIFY();
2006: __state[1] &= ~kIOServiceConfigState;
2007: __state[0] |= kIOServiceRegisteredState;
2008:
2009: if( reRegistered && (0 == (__state[0] & kIOServiceInactiveState))) {
2010:
2011: iter = OSCollectionIterator::withCollection( (OSOrderedSet *)
2012: gNotifications->getObject( gIOPublishNotification ) );
2013: if( iter) {
2014: while((notify = (_IOServiceNotifier *)
2015: iter->getNextObject())) {
2016: if( passiveMatch( notify->matching ))
2017: matches->setObject( notify );
2018: }
2019: iter->release();
2020: }
2021: }
2022:
2023: UNLOCKNOTIFY();
2024: unlockForArbitration();
2025:
2026: if( matches->getCount() && (kIOReturnSuccess == getResources()))
2027: probeCandidates( matches );
2028: else
2029: matches->release();
2030: }
2031:
2032: lockForArbitration();
2033: reRegistered = (0 != (__state[1] & kIOServiceConfigState));
2034: keepGuessing =
2035: (reRegistered || (catalogGeneration !=
2036: gIOCatalogue->getGenerationCount()))
2037: && (0 == (__state[0] & kIOServiceInactiveState));
2038:
2039: if( keepGuessing)
2040: unlockForArbitration();
2041: }
2042:
2043: if( 0 == (__state[0] & kIOServiceInactiveState)) {
2044: deliverNotification( gIOMatchedNotification,
2045: kIOServiceMatchedState, 0xffffffff );
2046: if( 0 == (__state[0] & kIOServiceFirstMatchState))
2047: deliverNotification( gIOFirstMatchNotification,
2048: kIOServiceFirstMatchState, 0xffffffff );
2049: }
2050:
2051: unlockForArbitration();
2052:
2053: adjustBusy( -1 );
2054: }
2055:
2056: void IOService::adjustBusy( SInt32 delta )
2057: {
2058: IOService * next;
2059: UInt32 count;
2060: bool wasQuiet, nowQuiet;
2061:
2062: if( 0 == delta)
2063: return;
2064:
2065: IOTakeLock( gIOServiceBusyLock );
2066: next = this;
2067:
2068: do {
2069: count = next->__state[1] & kIOServiceBusyStateMask;
2070: assert( count < kIOServiceBusyMax);
2071: wasQuiet = (0 == count);
2072: assert( (!wasQuiet) || (delta > 0));
2073: next->__state[1] += delta;
2074: nowQuiet = (0 == (next->__state[1] & kIOServiceBusyStateMask));
2075:
2076: if( nowQuiet)
2077: thread_wakeup( (event_t) next);
2078:
2079: if( (wasQuiet || nowQuiet) ) {
2080: OSArray * array;
2081: unsigned int index;
2082: OSObject * interested;
2083:
2084: array = OSDynamicCast( OSArray, next->getProperty( gIOBusyInterest ));
2085: if( array) {
2086: LOCKREADNOTIFY();
2087: for( index = 0;
2088: (interested = array->getObject( index ));
2089: index++) {
2090: next->messageClient(kIOMessageServiceBusyStateChange,
2091: interested, (void *) wasQuiet /* busy now */);
2092: }
2093: UNLOCKNOTIFY();
2094: }
2095: }
2096:
2097: delta = nowQuiet ? -1 : +1;
2098:
2099: } while( (wasQuiet || nowQuiet) && (next = next->getProvider()));
2100:
2101: IOUnlock( gIOServiceBusyLock );
2102: }
2103:
2104: UInt32 IOService::getBusyState( void )
2105: {
2106: return( __state[1] & kIOServiceBusyStateMask );
2107: }
2108:
2109: IOReturn IOService::waitForState( UInt32 mask, UInt32 value,
2110: mach_timespec_t * timeout = 0 )
2111: {
2112: bool wait;
2113:
2114: do {
2115: IOTakeLock( gIOServiceBusyLock );
2116: wait = (value != (__state[1] & mask));
2117: if( wait)
2118: assert_wait( (event_t) this, THREAD_UNINT );
2119: IOUnlock( gIOServiceBusyLock );
2120: if( wait)
2121: thread_block((void (*)(void)) -6);
2122:
2123: } while( wait );
2124:
2125: return( kIOReturnSuccess );
2126: }
2127:
2128: IOReturn IOService::waitQuiet( mach_timespec_t * timeout = 0 )
2129: {
2130: return( waitForState( kIOServiceBusyStateMask, 0, timeout ));
2131: }
2132:
2133: bool IOService::serializeProperties( OSSerialize * s ) const
2134: {
2135: #if 0
2136: ((IOService *)this)->setProperty( ((IOService *)this)->__state,
2137: sizeof( __state), "__state");
2138: #endif
2139: return( super::serializeProperties(s) );
2140: }
2141:
2142:
2143: void _IOConfigThread::main( _IOConfigThread * self )
2144: {
2145: _IOServiceJob * job;
2146: IOService * nub;
2147: bool alive = true;
2148:
2149: do {
2150:
2151: #if 0
2152: #define randomDelay() \
2153: int del = read_processor_clock(); \
2154: del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
2155: IOSleep( del );
2156: randomDelay();
2157: #endif
2158:
2159: semaphore_wait( gJobsSemaphore );
2160:
2161: IOTakeLock( gJobsLock );
2162: job = (_IOServiceJob *) gJobs->getFirstObject();
2163: job->retain();
2164: gJobs->removeObject(job);
2165: if( job) {
2166: gOutstandingJobs--;
2167: #ifndef LESS_THREAD_CREATE
2168: // gNumConfigThreads--; // we're out of service
2169: gNumWaitingThreads--; // we're out of service
2170: #endif
2171: }
2172: IOUnlock( gJobsLock );
2173:
2174: if( job) {
2175:
2176: nub = job->nub;
2177:
2178: if( gIOKitDebug & kIOLogConfig)
2179: LOG("config(%x): starting on %s, %d\n",
2180: (int) IOThreadSelf(), job->nub->getName(), job->type);
2181:
2182: switch( job->type) {
2183:
2184: case kMatchNubJob:
2185: nub->doServiceMatch();
2186: break;
2187:
2188: case kTerminateNubJob:
2189: nub->doServiceTerminate( job->options );
2190: break;
2191:
2192: default:
2193: LOG("config(%x): strange type (%d)\n",
2194: (int) IOThreadSelf(), job->type );
2195: break;
2196: }
2197:
2198: nub->release();
2199: job->release();
2200:
2201: IOTakeLock( gJobsLock );
2202: #ifndef LESS_THREAD_CREATE
2203: alive = (gOutstandingJobs > gNumWaitingThreads);
2204: if( alive)
2205: gNumWaitingThreads++; // back in service
2206: // gNumConfigThreads++;
2207: else
2208: gNumConfigThreads--;
2209: #endif
2210: IOUnlock( gJobsLock );
2211: }
2212:
2213: } while( alive );
2214:
2215: if( gIOKitDebug & kIOLogConfig)
2216: LOG("config(%x): terminating\n", (int) IOThreadSelf() );
2217:
2218: self->release();
2219: }
2220:
2221: void _IOServiceJob::pingConfig( _IOServiceJob * job )
2222: {
2223: int count;
2224: bool create;
2225:
2226: assert( job );
2227:
2228: IOTakeLock( gJobsLock );
2229:
2230: gOutstandingJobs++;
2231: gJobs->setLastObject( job );
2232:
2233: count = gNumWaitingThreads;
2234: // if( gNumConfigThreads) count++;// assume we're called from a config thread
2235:
2236: create = ( (gOutstandingJobs > count)
2237: && (gNumConfigThreads < kMaxConfigThreads) );
2238: if( create) {
2239: gNumConfigThreads++;
2240: gNumWaitingThreads++;
2241: }
2242:
2243: IOUnlock( gJobsLock );
2244:
2245: job->release();
2246:
2247: if( create) {
2248: if( gIOKitDebug & kIOLogConfig)
2249: LOG("config(%d): creating\n", gNumConfigThreads - 1);
2250: _IOConfigThread::configThread();
2251: }
2252:
2253: semaphore_signal( gJobsSemaphore );
2254: }
2255:
2256:
2257: // internal - call with gNotificationLock
2258: OSObject * IOService::getExistingServices( OSDictionary * matching,
2259: IOOptionBits inState, IOOptionBits options = 0 )
2260: {
2261: OSObject * current = 0;
2262: OSIterator * iter;
2263: IOService * service;
2264:
2265: if( !matching)
2266: return( 0 );
2267:
2268: iter = IORegistryIterator::iterateOver( gIOServicePlane,
2269: kIORegistryIterateRecursively );
2270: if( iter) {
2271: do {
2272: iter->reset();
2273: while( (service = (IOService *) iter->getNextObject())) {
2274: if( (inState == (service->__state[0] & inState))
2275: && (0 == (service->__state[0] & kIOServiceInactiveState))
2276: && service->passiveMatch( matching )) {
2277:
2278: if( options & kIONotifyOnce) {
2279: current = service;
2280: break;
2281: }
2282: if( current)
2283: ((OSSet *)current)->setObject( service );
2284: else
2285: current = OSSet::withObjects(
2286: (OSObject **) &service, 1, 1 );
2287: }
2288: }
2289: } while( !service && !iter->isValid());
2290: iter->release();
2291: }
2292:
2293: if( current && (0 == (options & kIONotifyOnce))) {
2294: iter = OSCollectionIterator::withCollection( (OSSet *)current );
2295: current->release();
2296: current = iter;
2297: }
2298:
2299: return( current );
2300: }
2301:
2302: // public version
2303: OSIterator * IOService::getMatchingServices( OSDictionary * matching )
2304: {
2305: OSIterator * iter;
2306:
2307: // is a lock even needed?
2308: LOCKWRITENOTIFY();
2309:
2310: iter = (OSIterator *) getExistingServices( matching,
2311: kIOServiceRegisteredState );
2312:
2313: UNLOCKNOTIFY();
2314:
2315: return( iter );
2316: }
2317:
2318:
2319: // internal - call with gNotificationLock
2320: IONotifier * IOService::setNotification(
2321: const OSSymbol * type, OSDictionary * matching,
2322: IOServiceNotificationHandler handler, void * target, void * ref,
2323: SInt32 priority = 0 )
2324: {
2325: _IOServiceNotifier * notify = 0;
2326: OSOrderedSet * set;
2327:
2328: if( !matching)
2329: return( 0 );
2330:
2331: notify = new _IOServiceNotifier;
2332: if( notify && !notify->init()) {
2333: notify->release();
2334: notify = 0;
2335: }
2336:
2337: if( notify) {
2338: notify->matching = matching;
2339: notify->handler = handler;
2340: notify->target = target;
2341: notify->ref = ref;
2342: notify->priority = priority;
2343: notify->fEnable = true;
2344:
2345: ////// queue
2346:
2347: if( 0 == (set = (OSOrderedSet *) gNotifications->getObject( type ))) {
2348: set = OSOrderedSet::withCapacity( 1,
2349: IONotifyOrdering, 0 );
2350: if( set) {
2351: gNotifications->setObject( type, set );
2352: set->release();
2353: }
2354: }
2355: notify->whence = set;
2356: if( set)
2357: set->setObject( notify );
2358: }
2359:
2360: return( notify );
2361: }
2362:
2363: // internal - call with gNotificationLock
2364: IONotifier * IOService::doInstallNotification(
2365: const OSSymbol * type, OSDictionary * matching,
2366: IOServiceNotificationHandler handler,
2367: void * target, void * ref,
2368: SInt32 priority, OSIterator ** existing )
2369: {
2370: OSIterator * exist;
2371: IONotifier * notify;
2372: IOOptionBits inState;
2373:
2374: if( !matching)
2375: return( 0 );
2376:
2377: if( (type == gIOPublishNotification)
2378: || (type == gIOFirstPublishNotification))
2379: inState = kIOServiceRegisteredState;
2380: else if( (type == gIOMatchedNotification)
2381: || (type == gIOFirstMatchNotification))
2382: inState = kIOServiceMatchedState;
2383: else if( type == gIOTerminatedNotification)
2384: inState = 0;
2385: else
2386: return( 0 );
2387:
2388: notify = setNotification( type, matching, handler, target, ref, priority );
2389:
2390: if( inState)
2391: // get the current set
2392: exist = (OSIterator *) getExistingServices( matching, inState );
2393: else
2394: exist = 0;
2395:
2396: *existing = exist;
2397:
2398: return( notify );
2399: }
2400:
2401:
2402: IONotifier * IOService::installNotification(
2403: const OSSymbol * type, OSDictionary * matching,
2404: IOServiceNotificationHandler handler,
2405: void * target, void * ref,
2406: SInt32 priority, OSIterator ** existing )
2407: {
2408: IONotifier * notify;
2409:
2410: LOCKWRITENOTIFY();
2411:
2412: notify = doInstallNotification( type, matching, handler, target, ref,
2413: priority, existing );
2414:
2415: UNLOCKNOTIFY();
2416:
2417: return( notify );
2418: }
2419:
2420: IONotifier * IOService::addNotification(
2421: const OSSymbol * type, OSDictionary * matching,
2422: IOServiceNotificationHandler handler,
2423: void * target, void * ref = 0,
2424: SInt32 priority = 0 )
2425: {
2426: OSIterator * existing;
2427: IONotifier * notify;
2428: IOService * next;
2429:
2430: notify = installNotification( type, matching,
2431: handler, target, ref, priority, &existing );
2432:
2433: // send notifications for existing set
2434: if( existing) {
2435:
2436: while( (next = (IOService *) existing->getNextObject())) {
2437:
2438: next->lockForArbitration();
2439: LOCKWRITENOTIFY();
2440: if( 0 == (next->__state[0] & kIOServiceInactiveState))
2441: (*handler)( target, ref, next );
2442: UNLOCKNOTIFY();
2443: next->unlockForArbitration();
2444: }
2445: existing->release();
2446: }
2447:
2448: return( notify );
2449: }
2450:
2451: struct SyncNotifyVars {
2452: semaphore_port_t waitHere;
2453: IOService * result;
2454: };
2455:
2456: bool IOService::syncNotificationHandler(
2457: void * /* target */, void * ref,
2458: IOService * newService )
2459: {
2460:
2461: // result may get written more than once before the
2462: // notification is removed!
2463: ((SyncNotifyVars *) ref)->result = newService;
2464: semaphore_signal( ((SyncNotifyVars *) ref)->waitHere );
2465:
2466: return( false );
2467: }
2468:
2469: IOService * IOService::waitForService( OSDictionary * matching,
2470: mach_timespec_t * timeout = 0 )
2471: {
2472: IONotifier * notify = 0;
2473: // priority doesn't help us much since we need a thread wakeup
2474: SInt32 priority = 0;
2475: SyncNotifyVars state;
2476: kern_return_t err = kIOReturnBadArgument;
2477:
2478: if( !matching)
2479: return( 0 );
2480:
2481: state.waitHere = 0;
2482: state.result = 0;
2483:
2484: LOCKWRITENOTIFY();
2485:
2486: do {
2487:
2488: state.result = (IOService *) getExistingServices( matching,
2489: kIOServiceMatchedState, kIONotifyOnce );
2490: if( state.result)
2491: continue;
2492:
2493: err = semaphore_create( kernel_task, &state.waitHere,
2494: SYNC_POLICY_FIFO, 0 );
2495: if( KERN_SUCCESS != err)
2496: continue;
2497:
2498: notify = IOService::setNotification( gIOMatchedNotification, matching,
2499: &IOService::syncNotificationHandler, (void *) 0,
2500: (void *) &state, priority );
2501:
2502: } while( false );
2503:
2504: UNLOCKNOTIFY();
2505:
2506: if( notify) {
2507: if( timeout)
2508: err = semaphore_timedwait( state.waitHere, *timeout );
2509: else
2510: err = semaphore_wait( state.waitHere );
2511: }
2512:
2513: if( notify)
2514: notify->remove(); // dequeues
2515: if( state.waitHere)
2516: semaphore_destroy( kernel_task, state.waitHere );
2517:
2518: return( state.result );
2519: }
2520:
2521: void IOService::deliverNotification( const OSSymbol * type,
2522: IOOptionBits orNewState, IOOptionBits andNewState )
2523: {
2524: _IOServiceNotifier * notify;
2525: OSIterator * iter;
2526:
2527: lockForArbitration();
2528:
2529: if( (0 == (__state[0] & kIOServiceInactiveState))
2530: || (type == gIOTerminatedNotification)) {
2531:
2532: LOCKREADNOTIFY();
2533:
2534: iter = OSCollectionIterator::withCollection( (OSOrderedSet *)
2535: gNotifications->getObject( type ) );
2536:
2537: if( iter) {
2538: while( (notify = (_IOServiceNotifier *) iter->getNextObject())) {
2539:
2540: if( passiveMatch( notify->matching)
2541: && notify->fEnable)
2542: (*notify->handler)( notify->target, notify->ref, this );
2543: }
2544: iter->release();
2545: }
2546:
2547: __state[0] = (__state[0] | orNewState) & andNewState;
2548:
2549: UNLOCKNOTIFY();
2550: }
2551:
2552: unlockForArbitration();
2553: }
2554:
2555: IOOptionBits IOService::getState( void ) const
2556: {
2557: return( __state[0] );
2558: }
2559:
2560: /*
2561: * Helpers to make matching objects for simple cases
2562: */
2563:
2564: OSDictionary * IOService::serviceMatching( const OSString * name,
2565: OSDictionary * table = 0 )
2566: {
2567: if( !table)
2568: table = OSDictionary::withCapacity( 2 );
2569: if( table)
2570: table->setObject(gIOProviderClassKey, (OSObject *)name );
2571:
2572: return( table );
2573: }
2574:
2575: OSDictionary * IOService::serviceMatching( const char * name,
2576: OSDictionary * table = 0 )
2577: {
2578: const OSString * str;
2579:
2580: str = OSSymbol::withCString( name );
2581: if( !str)
2582: return( 0 );
2583:
2584: table = serviceMatching( str, table );
2585: str->release();
2586: return( table );
2587: }
2588:
2589: OSDictionary * IOService::nameMatching( const OSString * name,
2590: OSDictionary * table = 0 )
2591: {
2592: if( !table)
2593: table = OSDictionary::withCapacity( 2 );
2594: if( table)
2595: table->setObject( gIONameMatchKey, (OSObject *)name );
2596:
2597: return( table );
2598: }
2599:
2600: OSDictionary * IOService::nameMatching( const char * name,
2601: OSDictionary * table = 0 )
2602: {
2603: const OSString * str;
2604:
2605: str = OSSymbol::withCString( name );
2606: if( !str)
2607: return( 0 );
2608:
2609: table = nameMatching( str, table );
2610: str->release();
2611: return( table );
2612: }
2613:
2614: OSDictionary * IOService::resourceMatching( const OSString * str,
2615: OSDictionary * table = 0 )
2616: {
2617: table = serviceMatching( gIOResourcesKey, table );
2618: if( table)
2619: table->setObject( gIOResourceMatchKey, (OSObject *) str );
2620:
2621: return( table );
2622: }
2623:
2624: OSDictionary * IOService::resourceMatching( const char * name,
2625: OSDictionary * table = 0 )
2626: {
2627: const OSSymbol * str;
2628:
2629: str = OSSymbol::withCString( name );
2630: if( !str)
2631: return( 0 );
2632:
2633: table = resourceMatching( str, table );
2634: str->release();
2635:
2636: return( table );
2637: }
2638:
2639: /*
2640: * _IOServiceNotifier
2641: */
2642:
2643: void _IOServiceNotifier::remove()
2644: {
2645: LOCKWRITENOTIFY();
2646:
2647: if( whence) {
2648: whence->removeObject( (OSObject *) this );
2649: whence = 0;
2650: }
2651: if( matching) {
2652: matching->release();
2653: matching = 0;
2654: }
2655:
2656: fEnable = false;
2657:
2658: UNLOCKNOTIFY();
2659:
2660: release();
2661: }
2662:
2663: bool _IOServiceNotifier::disable()
2664: {
2665: bool ret;
2666:
2667: LOCKWRITENOTIFY();
2668: ret = fEnable;
2669: fEnable = false;
2670: UNLOCKNOTIFY();
2671:
2672: return( ret );
2673: }
2674:
2675: void _IOServiceNotifier::enable( bool was )
2676: {
2677: LOCKWRITENOTIFY();
2678: fEnable = was;
2679: UNLOCKNOTIFY();
2680: }
2681:
2682: /*
2683: * IOResources
2684: */
2685:
2686: IOService * IOResources::resources( void )
2687: {
2688: IOResources * inst;
2689:
2690: inst = new IOResources;
2691: if( inst && !inst->init()) {
2692: inst->release();
2693: inst = 0;
2694: }
2695:
2696: return( inst );
2697: }
2698:
2699: bool IOResources::matchPropertyTable( OSDictionary * table )
2700: {
2701: OSObject * prop;
2702: OSString * str;
2703: OSSet * set;
2704: OSIterator * iter;
2705: bool ok = false;
2706:
2707: prop = table->getObject( gIOResourceMatchKey );
2708: str = OSDynamicCast( OSString, prop );
2709: if( str)
2710: ok = (0 != getProperty( str ));
2711:
2712: else if( (set = OSDynamicCast( OSSet, prop))) {
2713:
2714: iter = OSCollectionIterator::withCollection( set );
2715: ok = (iter != 0);
2716: while( ok && (str = OSDynamicCast( OSString, iter->getNextObject()) ))
2717: ok = (0 != getProperty( str ));
2718:
2719: if( iter)
2720: iter->release();
2721: }
2722:
2723: return( ok );
2724: }
2725:
2726: /*
2727: * Helpers for matching dictionaries.
2728: * Keys existing in matching are checked in properties.
2729: * Keys may be a string or OSCollection of IOStrings
2730: */
2731:
2732: bool IOService::compareProperty( OSDictionary * matching,
2733: const char * key )
2734: {
2735: OSObject * value;
2736: bool ok;
2737:
2738: value = matching->getObject( key );
2739: if( value)
2740: ok = value->isEqualTo( getProperty( key ));
2741: else
2742: ok = true;
2743:
2744: return( ok );
2745: }
2746:
2747:
2748: bool IOService::compareProperty( OSDictionary * matching,
2749: const OSString * key )
2750: {
2751: OSObject * value;
2752: bool ok;
2753:
2754: value = matching->getObject( key );
2755: if( value)
2756: ok = value->isEqualTo( getProperty( key ));
2757: else
2758: ok = true;
2759:
2760: return( ok );
2761: }
2762:
2763: bool IOService::compareProperties( OSDictionary * matching,
2764: OSCollection * keys )
2765: {
2766: OSCollectionIterator * iter;
2767: const OSString * key;
2768: bool ok = true;
2769:
2770: if( !matching || !keys)
2771: return( false );
2772:
2773: iter = OSCollectionIterator::withCollection( keys );
2774:
2775: if( iter) {
2776: while( ok && (key = OSDynamicCast( OSString, iter->getNextObject())))
2777: ok = compareProperty( matching, key );
2778:
2779: iter->release();
2780: }
2781: keys->release(); // !! consume a ref !!
2782:
2783: return( ok );
2784: }
2785:
2786: /* Helper to add a location matching dict to the table */
2787:
2788: OSDictionary * IOService::addLocation( OSDictionary * table )
2789: {
2790: OSDictionary * dict;
2791:
2792: if( !table)
2793: return( 0 );
2794:
2795: dict = OSDictionary::withCapacity( 1 );
2796: if( dict) {
2797: table->setObject( gIOLocationMatchKey, dict );
2798: dict->release();
2799: }
2800:
2801: return( dict );
2802: }
2803:
2804: /*
2805: * Go looking for a provider to match a location dict.
2806: */
2807:
2808: IOService * IOService::matchLocation( IOService * /* client */ )
2809: {
2810: IOService * parent;
2811:
2812: parent = getProvider();
2813:
2814: if( parent)
2815: parent = parent->matchLocation( this );
2816:
2817: return( parent );
2818: }
2819:
2820: bool IOService::passiveMatch( OSDictionary * table, bool changesOK )
2821: {
2822: IOService * where;
2823: OSString * matched;
2824: OSObject * nameMatch;
2825: OSString * str1;
2826: OSString * str2;
2827: IORegistryEntry * entry;
2828: bool match = true;
2829:
2830: assert( table );
2831:
2832: where = this;
2833:
2834: do {
2835: entry = 0;
2836: str1 = OSDynamicCast( OSString, table->getObject( gIOProviderClassKey));
2837: if( str1 && !(match = (0 != where->metaCast( str1 ))))
2838: break;
2839:
2840: nameMatch = table->getObject( gIONameMatchKey );
2841: if( nameMatch && !(match = compareNames( nameMatch,
2842: changesOK ? &matched : 0 )))
2843: break;
2844: if( changesOK && nameMatch && matched) {
2845: // leave a hint as to which name matched
2846: table->setObject( gIONameMatchedKey, matched );
2847: matched->release();
2848: }
2849:
2850: str2 = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey ));
2851: if( str2) {
2852: entry = IORegistryEntry::fromPath( str2->getCStringNoCopy() );
2853: match = (where == entry);
2854: if( entry)
2855: entry->release();
2856: if( !match)
2857: break;
2858: }
2859:
2860: if( (str1 || str2 || nameMatch) && (1 == table->getCount()))
2861: // only do the imports/path check - don't call family.
2862: break;
2863:
2864: // do family specific matching
2865: match = where->matchPropertyTable( table );
2866:
2867: if( !match) {
2868: #ifdef DEBUG
2869: if( kIOLogMatch & getDebugFlags( table ))
2870: LOG("%s: family specific matching fails\n", where->getName());
2871: #endif
2872: break;
2873: }
2874:
2875: if( !(match = where->compareProperty( table, kIOBSDName )))
2876: break;
2877:
2878: table = OSDynamicCast( OSDictionary,
2879: table->getObject( gIOLocationMatchKey ));
2880: if( table) {
2881: match = false;
2882: where = where->getProvider();
2883: if( where)
2884: where = where->matchLocation( where );
2885: }
2886:
2887: } while( table && where );
2888:
2889: if( kIOLogMatch & gIOKitDebug)
2890: if( where != this)
2891: LOG("match location @ %s = %d\n",
2892: where->getName(), match );
2893:
2894: return( match );
2895: }
2896:
2897:
2898: IOReturn IOService::newUserClient( task_t /* owningTask */,
2899: void * /* security_id */,
2900: UInt32 /* type */,
2901: IOUserClient ** /* handler */ )
2902: {
2903: return( kIOReturnUnsupported);
2904: }
2905:
2906: IOReturn IOService::requestProbe( IOOptionBits options )
2907: {
2908: return( kIOReturnUnsupported);
2909: }
2910:
2911: /*
2912: * Convert an IOReturn to text. Subclasses which add additional
2913: * IOReturn's should override this method and call
2914: * [super stringFromReturn] if the desired value is not found.
2915: */
2916:
2917: const char * IOService::stringFromReturn( IOReturn rtn )
2918: {
2919: static const IONamedValue IOReturn_values[] = {
2920: {kIOReturnSuccess, "success" },
2921: {kIOReturnError, "general error" },
2922: {kIOReturnNoMemory, "memory allocation error" },
2923: {kIOReturnNoResources, "resource shortage" },
2924: {kIOReturnIPCError, "Mach IPC failure" },
2925: {kIOReturnNoDevice, "no such device" },
2926: {kIOReturnNotPrivileged, "privilege violation" },
2927: {kIOReturnBadArgument, "invalid argument" },
2928: {kIOReturnLockedRead, "device is read locked" },
2929: {kIOReturnLockedWrite, "device is write locked" },
2930: {kIOReturnExclusiveAccess, "device is exclusive access" },
2931: {kIOReturnBadMessageID, "bad IPC message ID" },
2932: {kIOReturnUnsupported, "unsupported function" },
2933: {kIOReturnVMError, "virtual memory error" },
2934: {kIOReturnInternalError, "internal driver error" },
2935: {kIOReturnIOError, "I/O error" },
2936: {kIOReturnCannotLock, "cannot acquire lock" },
2937: {kIOReturnNotOpen, "device is not open" },
2938: {kIOReturnNotReadable, "device is not readable" },
2939: {kIOReturnNotWritable, "device is not writeable" },
2940: {kIOReturnNotAligned, "alignment error" },
2941: {kIOReturnBadMedia, "media error" },
2942: {kIOReturnStillOpen, "device is still open" },
2943: {kIOReturnRLDError, "rld failure" },
2944: {kIOReturnDMAError, "DMA failure" },
2945: {kIOReturnBusy, "device is busy" },
2946: {kIOReturnTimeout, "I/O timeout" },
2947: {kIOReturnOffline, "device is offline" },
2948: {kIOReturnNotReady, "device is not ready" },
2949: {kIOReturnNotAttached, "device/channel is not attached" },
2950: {kIOReturnNoChannels, "no DMA channels available" },
2951: {kIOReturnNoSpace, "no space for data" },
2952: {kIOReturnPortExists, "device port already exists" },
2953: {kIOReturnCannotWire, "cannot wire physical memory" },
2954: {kIOReturnNoInterrupt, "no interrupt attached" },
2955: {kIOReturnNoFrames, "no DMA frames enqueued" },
2956: {kIOReturnMessageTooLarge, "message is too large" },
2957: {kIOReturnNotPermitted, "operation is not permitted" },
2958: {kIOReturnNoPower, "device is without power" },
2959: {kIOReturnNoMedia, "media is not present" },
2960: {kIOReturnUnformattedMedia, "media is not formatted" },
2961: {kIOReturnUnsupportedMode, "unsupported mode" },
2962: {kIOReturnUnderrun, "data underrun" },
2963: {kIOReturnOverrun, "data overrun" },
2964: {kIOReturnDeviceError, "device error" },
2965: {kIOReturnNoCompletion, "no completion routine" },
2966: {kIOReturnAborted, "operation was aborted" },
2967: {kIOReturnNoBandwidth, "bus bandwidth would be exceeded" },
2968: {kIOReturnNotResponding, "device is not responding" },
2969: {kIOReturnInvalid, "unanticipated driver error" },
2970: {0, NULL }
2971: };
2972:
2973: return IOFindNameForValue(rtn, IOReturn_values);
2974: }
2975:
2976: /*
2977: * Convert an IOReturn to an errno.
2978: */
2979: int IOService::errnoFromReturn( IOReturn rtn )
2980: {
2981: switch(rtn) {
2982: // (obvious match)
2983: case kIOReturnSuccess:
2984: return(0);
2985: case kIOReturnNoMemory:
2986: return(ENOMEM);
2987: case kIOReturnNoDevice:
2988: return(ENXIO);
2989: case kIOReturnVMError:
2990: return(EFAULT);
2991: case kIOReturnNotPermitted:
2992: return(EPERM);
2993: case kIOReturnNotPrivileged:
2994: return(EACCES);
2995: case kIOReturnIOError:
2996: return(EIO);
2997: case kIOReturnNotWritable:
2998: return(EROFS);
2999: case kIOReturnBadArgument:
3000: return(EINVAL);
3001: case kIOReturnUnsupported:
3002: return(EOPNOTSUPP);
3003: case kIOReturnBusy:
3004: return(EBUSY);
3005: case kIOReturnNoPower:
3006: return(EPWROFF);
3007: case kIOReturnDeviceError:
3008: return(EDEVERR);
3009: case kIOReturnTimeout:
3010: return(ETIMEDOUT);
3011: case kIOReturnMessageTooLarge:
3012: return(EMSGSIZE);
3013: case kIOReturnNoSpace:
3014: return(ENOSPC);
3015: case kIOReturnCannotLock:
3016: return(ENOLCK);
3017:
3018: // (best match)
3019: case kIOReturnBadMessageID:
3020: case kIOReturnNoCompletion:
3021: case kIOReturnNotAligned:
3022: return(EINVAL);
3023: case kIOReturnNotReady:
3024: return(EBUSY);
3025: case kIOReturnRLDError:
3026: return(EBADMACHO);
3027: case kIOReturnPortExists:
3028: case kIOReturnStillOpen:
3029: return(EEXIST);
3030: case kIOReturnExclusiveAccess:
3031: case kIOReturnLockedRead:
3032: case kIOReturnLockedWrite:
3033: case kIOReturnNotAttached:
3034: case kIOReturnNotOpen:
3035: case kIOReturnNotReadable:
3036: return(EACCES);
3037: case kIOReturnCannotWire:
3038: case kIOReturnNoResources:
3039: return(ENOMEM);
3040: case kIOReturnAborted:
3041: case kIOReturnOffline:
3042: case kIOReturnNotResponding:
3043: return(EBUSY);
3044: case kIOReturnBadMedia:
3045: case kIOReturnNoMedia:
3046: case kIOReturnUnformattedMedia:
3047: return(EIO); // (media error)
3048: case kIOReturnDMAError:
3049: case kIOReturnOverrun:
3050: case kIOReturnUnderrun:
3051: return(EIO); // (transfer error)
3052: case kIOReturnNoBandwidth:
3053: case kIOReturnNoChannels:
3054: case kIOReturnNoFrames:
3055: case kIOReturnNoInterrupt:
3056: return(EIO); // (hardware error)
3057: case kIOReturnError:
3058: case kIOReturnInternalError:
3059: case kIOReturnInvalid:
3060: return(EIO); // (generic error)
3061: case kIOReturnIPCError:
3062: return(EIO); // (ipc error)
3063: default:
3064: return(EIO); // (all other errors)
3065: }
3066: }
3067:
3068: IOReturn IOService::message( UInt32 type, IOService * provider,
3069: void * argument )
3070: {
3071: /*
3072: * Generic entry point for upstream object calls. A return value of
3073: * kIOReturnSuccess indicates the message was successful.
3074: */
3075:
3076: return kIOReturnUnsupported;
3077: }
3078:
3079: /*
3080: * Device memory
3081: */
3082:
3083: IOItemCount IOService::getDeviceMemoryCount( void )
3084: {
3085: OSArray * array;
3086: IOItemCount count;
3087:
3088: array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
3089: if( array)
3090: count = array->getCount();
3091: else
3092: count = 0;
3093:
3094: return( count);
3095: }
3096:
3097: IODeviceMemory * IOService::getDeviceMemoryWithIndex( unsigned int index )
3098: {
3099: OSArray * array;
3100: IODeviceMemory * range;
3101:
3102: array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
3103: if( array)
3104: range = (IODeviceMemory *) array->getObject( index );
3105: else
3106: range = 0;
3107:
3108: return( range);
3109: }
3110:
3111: IOMemoryMap * IOService::mapDeviceMemoryWithIndex( unsigned int index,
3112: IOOptionBits options = 0 )
3113: {
3114: IODeviceMemory * range;
3115: IOMemoryMap * map;
3116:
3117: range = getDeviceMemoryWithIndex( index );
3118: if( range)
3119: map = range->map( options );
3120: else
3121: map = 0;
3122:
3123: return( map );
3124: }
3125:
3126: OSArray * IOService::getDeviceMemory( void )
3127: {
3128: return( OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)));
3129: }
3130:
3131:
3132: void IOService::setDeviceMemory( OSArray * array )
3133: {
3134: setProperty( gIODeviceMemoryKey, array);
3135: }
3136:
3137: /*
3138: * Device interrupts
3139: */
3140:
3141: IOReturn IOService::resolveInterrupt(IOService *nub, int source)
3142: {
3143: IOInterruptController *interruptController;
3144: OSDictionary *propTable;
3145: OSArray *array;
3146: OSData *data;
3147: OSSymbol *interruptControllerName;
3148: long numSources;
3149: IOInterruptSource *interruptSources;
3150:
3151: // Get the property table from the nub.
3152: propTable = nub->getPropertyTable();
3153: if (propTable == 0) return kIOReturnNoResources;
3154:
3155: // Get the parents list from the property table.
3156: array = OSDynamicCast(OSArray,
3157: propTable->getObject(gIOInterruptControllersKey));
3158: if (array == 0) return kIOReturnNoResources;
3159:
3160: // Allocate space for the IOInterruptSources if needed... then return early.
3161: if (nub->_interruptSources == 0) {
3162: numSources = array->getCount();
3163: interruptSources = (IOInterruptSource *)IOMalloc(numSources * sizeof(IOInterruptSource));
3164: if (interruptSources == 0) return kIOReturnNoMemory;
3165:
3166: bzero(interruptSources, numSources * sizeof(IOInterruptSource));
3167:
3168: nub->_numInterruptSources = numSources;
3169: nub->_interruptSources = interruptSources;
3170: return kIOReturnSuccess;
3171: }
3172:
3173: interruptControllerName = OSDynamicCast(OSSymbol,array->getObject(source));
3174: if (interruptControllerName == 0) return kIOReturnNoResources;
3175:
3176: interruptController = getPlatform()->lookUpInterruptController(interruptControllerName);
3177: if (interruptController == 0) return kIOReturnNoResources;
3178:
3179: // Get the interrupt numbers from the property table.
3180: array = OSDynamicCast(OSArray,
3181: propTable->getObject(gIOInterruptSpecifiersKey));
3182: if (array == 0) return kIOReturnNoResources;
3183: data = OSDynamicCast(OSData, array->getObject(source));
3184: if (data == 0) return kIOReturnNoResources;
3185:
3186: // Set the interruptController and interruptSource in the nub's table.
3187: interruptSources = nub->_interruptSources;
3188: interruptSources[source].interruptController = interruptController;
3189: interruptSources[source].vectorData = data;
3190:
3191: return kIOReturnSuccess;
3192: }
3193:
3194: IOReturn IOService::lookupInterrupt(int source, bool resolve, IOInterruptController **interruptController)
3195: {
3196: IOReturn ret;
3197:
3198: /* Make sure the _interruptSources are set */
3199: if (_interruptSources == 0) {
3200: ret = resolveInterrupt(this, source);
3201: if (ret != kIOReturnSuccess) return ret;
3202: }
3203:
3204: /* Make sure the local source number is valid */
3205: if ((source < 0) || (source >= _numInterruptSources))
3206: return kIOReturnNoInterrupt;
3207:
3208: /* Look up the contoller for the local source */
3209: *interruptController = _interruptSources[source].interruptController;
3210:
3211: if (*interruptController == NULL) {
3212: if (!resolve) return kIOReturnNoInterrupt;
3213:
3214: /* Try to reslove the interrupt */
3215: ret = resolveInterrupt(this, source);
3216: if (ret != kIOReturnSuccess) return ret;
3217:
3218: *interruptController = _interruptSources[source].interruptController;
3219: }
3220:
3221: return kIOReturnSuccess;
3222: }
3223:
3224: IOReturn IOService::registerInterrupt(int source, OSObject *target,
3225: IOInterruptAction handler,
3226: void *refCon)
3227: {
3228: IOInterruptController *interruptController;
3229: IOReturn ret;
3230:
3231: ret = lookupInterrupt(source, true, &interruptController);
3232: if (ret != kIOReturnSuccess) return ret;
3233:
3234: /* Register the source */
3235: return interruptController->registerInterrupt(this, source, target,
3236: (IOInterruptHandler)handler,
3237: refCon);
3238: }
3239:
3240: IOReturn IOService::unregisterInterrupt(int source)
3241: {
3242: IOInterruptController *interruptController;
3243: IOReturn ret;
3244:
3245: ret = lookupInterrupt(source, false, &interruptController);
3246: if (ret != kIOReturnSuccess) return ret;
3247:
3248: /* Unregister the source */
3249: return interruptController->unregisterInterrupt(this, source);
3250: }
3251:
3252: IOReturn IOService::getInterruptType(int source, int *interruptType)
3253: {
3254: IOInterruptController *interruptController;
3255: IOReturn ret;
3256:
3257: ret = lookupInterrupt(source, true, &interruptController);
3258: if (ret != kIOReturnSuccess) return ret;
3259:
3260: /* Return the type */
3261: return interruptController->getInterruptType(this, source, interruptType);
3262: }
3263:
3264: IOReturn IOService::enableInterrupt(int source)
3265: {
3266: IOInterruptController *interruptController;
3267: IOReturn ret;
3268:
3269: ret = lookupInterrupt(source, false, &interruptController);
3270: if (ret != kIOReturnSuccess) return ret;
3271:
3272: /* Enable the source */
3273: return interruptController->enableInterrupt(this, source);
3274: }
3275:
3276: IOReturn IOService::disableInterrupt(int source)
3277: {
3278: IOInterruptController *interruptController;
3279: IOReturn ret;
3280:
3281: ret = lookupInterrupt(source, false, &interruptController);
3282: if (ret != kIOReturnSuccess) return ret;
3283:
3284: /* Disable the source */
3285: return interruptController->disableInterrupt(this, source);
3286: }
3287:
3288: IOReturn IOService::causeInterrupt(int source)
3289: {
3290: IOInterruptController *interruptController;
3291: IOReturn ret;
3292:
3293: ret = lookupInterrupt(source, false, &interruptController);
3294: if (ret != kIOReturnSuccess) return ret;
3295:
3296: /* Cause an interrupt for the source */
3297: return interruptController->causeInterrupt(this, source);
3298: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.