Annotation of XNU/iokit/Kernel/IOService.cpp, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.