Annotation of XNU/iokit/Kernel/IOService.cpp, revision 1.1.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.