darwin-xnu/iokit/Kernel/IOService.cpp
<<
>>
Prefs
   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#include <IOKit/system.h>
  24
  25#include <IOKit/IOService.h>
  26#include <libkern/c++/OSContainers.h>
  27#include <libkern/c++/OSUnserialize.h>
  28#include <IOKit/IOCatalogue.h>
  29#include <IOKit/IOCommand.h>
  30#include <IOKit/IODeviceMemory.h>
  31#include <IOKit/IOInterrupts.h>
  32#include <IOKit/IOInterruptController.h>
  33#include <IOKit/IOPlatformExpert.h>
  34#include <IOKit/IOMessage.h>
  35#include <IOKit/IOLib.h>
  36#include <IOKit/IOKitKeysPrivate.h>
  37#include <IOKit/IOBSD.h>
  38#include <IOKit/IOUserClient.h>
  39#include <IOKit/IOWorkLoop.h>
  40#include <mach/sync_policy.h>
  41#include <IOKit/assert.h>
  42#include <sys/errno.h>
  43
  44//#define LOG kprintf
  45#define LOG IOLog
  46
  47#include "IOServicePrivate.h"
  48
  49// take lockForArbitration before LOCKNOTIFY
  50
  51/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  52
  53#define super IORegistryEntry
  54
  55OSDefineMetaClassAndStructors(IOService, IORegistryEntry)
  56
  57OSDefineMetaClassAndStructors(_IOServiceNotifier, IONotifier)
  58
  59OSDefineMetaClassAndStructors(_IOServiceInterestNotifier, IONotifier)
  60
  61OSDefineMetaClassAndStructors(_IOConfigThread, OSObject)
  62
  63OSDefineMetaClassAndStructors(_IOServiceJob, OSObject)
  64
  65OSDefineMetaClassAndStructors(IOResources, IOService)
  66
  67OSDefineMetaClassAndStructors(_IOOpenServiceIterator, OSIterator)
  68
  69OSDefineMetaClassAndAbstractStructors(IONotifier, OSObject)
  70
  71/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  72
  73static IOPlatformExpert *       gIOPlatform;
  74static class IOPMrootDomain *   gIOPMRootDomain;
  75const IORegistryPlane *         gIOServicePlane;
  76const IORegistryPlane *         gIOPowerPlane;
  77const OSSymbol *                gIODeviceMemoryKey;
  78const OSSymbol *                gIOInterruptControllersKey;
  79const OSSymbol *                gIOInterruptSpecifiersKey;
  80
  81const OSSymbol *                gIOResourcesKey;
  82const OSSymbol *                gIOResourceMatchKey;
  83const OSSymbol *                gIOProviderClassKey;
  84const OSSymbol *                gIONameMatchKey;
  85const OSSymbol *                gIONameMatchedKey;
  86const OSSymbol *                gIOPropertyMatchKey;
  87const OSSymbol *                gIOLocationMatchKey;
  88const OSSymbol *                gIOParentMatchKey;
  89const OSSymbol *                gIOPathMatchKey;
  90const OSSymbol *                gIOMatchCategoryKey;
  91const OSSymbol *                gIODefaultMatchCategoryKey;
  92const OSSymbol *                gIOMatchedServiceCountKey;
  93
  94const OSSymbol *                gIOUserClientClassKey;
  95const OSSymbol *                gIOKitDebugKey;
  96
  97const OSSymbol *                gIOCommandPoolSizeKey;
  98
  99const OSSymbol *                gIOConsoleUsersKey;
 100const OSSymbol *                gIOConsoleSessionUIDKey;
 101const OSSymbol *                gIOConsoleUsersSeedKey;
 102
 103static int                      gIOResourceGenerationCount;
 104
 105const OSSymbol *                gIOServiceKey;
 106const OSSymbol *                gIOPublishNotification;
 107const OSSymbol *                gIOFirstPublishNotification;
 108const OSSymbol *                gIOMatchedNotification;
 109const OSSymbol *                gIOFirstMatchNotification;
 110const OSSymbol *                gIOTerminatedNotification;
 111
 112const OSSymbol *                gIOGeneralInterest;
 113const OSSymbol *                gIOBusyInterest;
 114const OSSymbol *                gIOAppPowerStateInterest;
 115const OSSymbol *                gIOPriorityPowerStateInterest;
 116
 117static OSDictionary *           gNotifications;
 118static IORecursiveLock *        gNotificationLock;
 119
 120static IOService *              gIOResources;
 121static IOService *              gIOServiceRoot;
 122
 123static OSOrderedSet *           gJobs;
 124static semaphore_port_t         gJobsSemaphore;
 125static IOLock *                 gJobsLock;
 126static int                      gOutstandingJobs;
 127static int                      gNumConfigThreads;
 128static int                      gNumWaitingThreads;
 129static IOLock *                 gIOServiceBusyLock;
 130
 131static thread_t                 gIOTerminateThread;
 132static UInt32                   gIOTerminateWork;
 133static OSArray *                gIOTerminatePhase2List;
 134static OSArray *                gIOStopList;
 135static OSArray *                gIOStopProviderList;
 136static OSArray *                gIOFinalizeList;
 137
 138static SInt32                   gIOConsoleUsersSeed;
 139static OSData *                 gIOConsoleUsersSeedValue;
 140
 141/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 142
 143#define LOCKREADNOTIFY()        \
 144    IORecursiveLockLock( gNotificationLock )
 145#define LOCKWRITENOTIFY()       \
 146    IORecursiveLockLock( gNotificationLock )
 147#define LOCKWRITE2READNOTIFY()
 148#define UNLOCKNOTIFY()          \
 149    IORecursiveLockUnlock( gNotificationLock )
 150#define SLEEPNOTIFY(event) \
 151    IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
 152#define WAKEUPNOTIFY(event) \
 153        IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
 154
 155#define randomDelay()   \
 156        int del = read_processor_clock();                               \
 157        del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff;      \
 158        IOSleep( del );
 159
 160/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 161
 162#define queue_element(entry, element, type, field) do { \
 163        vm_address_t __ele = (vm_address_t) (entry);    \
 164        __ele -= -4 + ((size_t)(&((type) 4)->field));   \
 165        (element) = (type) __ele;                       \
 166    } while(0)
 167
 168#define iterqueue(que, elt)                             \
 169        for (queue_entry_t elt = queue_first(que);      \
 170             !queue_end(que, elt);                      \
 171             elt = queue_next(elt))
 172
 173/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 174
 175struct ArbitrationLockQueueElement {
 176    queue_chain_t link;
 177    IOThread      thread;
 178    IOService *   service;
 179    unsigned      count;
 180    bool          required;
 181    bool          aborted;
 182};
 183
 184static queue_head_t gArbitrationLockQueueActive;
 185static queue_head_t gArbitrationLockQueueWaiting;
 186static queue_head_t gArbitrationLockQueueFree;
 187static IOLock *     gArbitrationLockQueueLock;
 188
 189bool IOService::isInactive( void ) const
 190    { return( 0 != (kIOServiceInactiveState & getState())); }
 191
 192/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 193
 194void IOService::initialize( void )
 195{
 196    kern_return_t       err;
 197
 198    gIOServicePlane     = IORegistryEntry::makePlane( kIOServicePlane );
 199    gIOPowerPlane       = IORegistryEntry::makePlane( kIOPowerPlane );
 200
 201    gIOProviderClassKey = OSSymbol::withCStringNoCopy( kIOProviderClassKey );
 202    gIONameMatchKey     = OSSymbol::withCStringNoCopy( kIONameMatchKey );
 203    gIONameMatchedKey   = OSSymbol::withCStringNoCopy( kIONameMatchedKey );
 204    gIOPropertyMatchKey = OSSymbol::withCStringNoCopy( kIOPropertyMatchKey );
 205    gIOPathMatchKey     = OSSymbol::withCStringNoCopy( kIOPathMatchKey );
 206    gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey );
 207    gIOParentMatchKey   = OSSymbol::withCStringNoCopy( kIOParentMatchKey );
 208
 209    gIOMatchCategoryKey = OSSymbol::withCStringNoCopy( kIOMatchCategoryKey );
 210    gIODefaultMatchCategoryKey  = OSSymbol::withCStringNoCopy( 
 211                                        kIODefaultMatchCategoryKey );
 212    gIOMatchedServiceCountKey   = OSSymbol::withCStringNoCopy( 
 213                                        kIOMatchedServiceCountKey );
 214
 215    gIOUserClientClassKey = OSSymbol::withCStringNoCopy( kIOUserClientClassKey );
 216
 217    gIOResourcesKey     = OSSymbol::withCStringNoCopy( kIOResourcesClass );
 218    gIOResourceMatchKey = OSSymbol::withCStringNoCopy( kIOResourceMatchKey );
 219
 220    gIODeviceMemoryKey  = OSSymbol::withCStringNoCopy( "IODeviceMemory" );
 221    gIOInterruptControllersKey
 222        = OSSymbol::withCStringNoCopy("IOInterruptControllers");
 223    gIOInterruptSpecifiersKey
 224        = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
 225
 226    gIOKitDebugKey      = OSSymbol::withCStringNoCopy( kIOKitDebugKey );
 227
 228    gIOCommandPoolSizeKey       = OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey );
 229
 230    gIOGeneralInterest          = OSSymbol::withCStringNoCopy( kIOGeneralInterest );
 231    gIOBusyInterest             = OSSymbol::withCStringNoCopy( kIOBusyInterest );
 232    gIOAppPowerStateInterest    = OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest );
 233    gIOPriorityPowerStateInterest       = OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest );
 234
 235    gNotifications              = OSDictionary::withCapacity( 1 );
 236    gIOPublishNotification      = OSSymbol::withCStringNoCopy(
 237                                                 kIOPublishNotification );
 238    gIOFirstPublishNotification = OSSymbol::withCStringNoCopy(
 239                                                 kIOFirstPublishNotification );
 240    gIOMatchedNotification      = OSSymbol::withCStringNoCopy(
 241                                                 kIOMatchedNotification );
 242    gIOFirstMatchNotification   = OSSymbol::withCStringNoCopy(
 243                                                 kIOFirstMatchNotification );
 244    gIOTerminatedNotification   = OSSymbol::withCStringNoCopy(
 245                                                 kIOTerminatedNotification );
 246    gIOServiceKey               = OSSymbol::withCStringNoCopy( kIOServiceClass);
 247
 248    gIOConsoleUsersKey          = OSSymbol::withCStringNoCopy( kIOConsoleUsersKey);
 249    gIOConsoleSessionUIDKey     = OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey);
 250    gIOConsoleUsersSeedKey      = OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey);
 251    gIOConsoleUsersSeedValue    = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed));
 252
 253    gNotificationLock           = IORecursiveLockAlloc();
 254
 255    assert( gIOServicePlane && gIODeviceMemoryKey
 256        && gIOInterruptControllersKey && gIOInterruptSpecifiersKey
 257        && gIOResourcesKey && gNotifications && gNotificationLock
 258        && gIOProviderClassKey && gIONameMatchKey && gIONameMatchedKey
 259        && gIOMatchCategoryKey && gIODefaultMatchCategoryKey
 260        && gIOPublishNotification && gIOMatchedNotification
 261        && gIOTerminatedNotification && gIOServiceKey
 262        && gIOConsoleUsersKey && gIOConsoleSessionUIDKey
 263        && gIOConsoleUsersSeedKey && gIOConsoleUsersSeedValue);
 264
 265    gJobsLock   = IOLockAlloc();
 266    gJobs       = OSOrderedSet::withCapacity( 10 );
 267
 268    gIOServiceBusyLock = IOLockAlloc();
 269
 270    err = semaphore_create(kernel_task, &gJobsSemaphore, SYNC_POLICY_FIFO, 0);
 271
 272    assert( gIOServiceBusyLock && gJobs && gJobsLock && (err == KERN_SUCCESS) );
 273
 274    gIOResources = IOResources::resources();
 275    assert( gIOResources );
 276
 277    gArbitrationLockQueueLock = IOLockAlloc();
 278    queue_init(&gArbitrationLockQueueActive);
 279    queue_init(&gArbitrationLockQueueWaiting);
 280    queue_init(&gArbitrationLockQueueFree);
 281
 282    assert( gArbitrationLockQueueLock );
 283
 284    gIOTerminatePhase2List = OSArray::withCapacity( 2 );
 285    gIOStopList            = OSArray::withCapacity( 16 );
 286    gIOStopProviderList    = OSArray::withCapacity( 16 );
 287    gIOFinalizeList        = OSArray::withCapacity( 16 );
 288    assert( gIOTerminatePhase2List && gIOStopList && gIOStopProviderList && gIOFinalizeList );
 289}
 290
 291/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 292
 293#if IOMATCHDEBUG
 294static UInt64 getDebugFlags( OSDictionary * props )
 295{
 296    OSNumber *  debugProp;
 297    UInt64      debugFlags;
 298
 299    debugProp = OSDynamicCast( OSNumber,
 300                props->getObject( gIOKitDebugKey ));
 301    if( debugProp)
 302        debugFlags = debugProp->unsigned64BitValue();
 303    else
 304        debugFlags = gIOKitDebug;
 305
 306    return( debugFlags );
 307}
 308#endif
 309
 310/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 311
 312// Probe a matched service and return an instance to be started.
 313// The default score is from the property table, & may be altered
 314// during probe to change the start order.
 315
 316IOService * IOService::probe(   IOService * provider,
 317                                SInt32    * score )
 318{
 319    return( this );
 320}
 321
 322bool IOService::start( IOService * provider )
 323{
 324    return( true );
 325}
 326
 327void IOService::stop( IOService * provider )
 328{
 329}
 330
 331void IOService::free( void )
 332{
 333    if( getPropertyTable())
 334        unregisterAllInterest();
 335    PMfree();
 336    super::free();
 337}
 338
 339/*
 340 * Attach in service plane
 341 */
 342bool IOService::attach( IOService * provider )
 343{
 344    bool        ok;
 345
 346    if( provider) {
 347
 348        if( gIOKitDebug & kIOLogAttach)
 349            LOG( "%s::attach(%s)\n", getName(),
 350                    provider->getName());
 351
 352        provider->lockForArbitration();
 353        if( provider->__state[0] & kIOServiceInactiveState)
 354            ok = false;
 355        else
 356            ok = attachToParent( provider, gIOServicePlane);
 357        provider->unlockForArbitration();
 358
 359    } else {
 360        gIOServiceRoot = this;
 361        ok = attachToParent( getRegistryRoot(), gIOServicePlane);
 362    }
 363
 364    return( ok );
 365}
 366
 367IOService * IOService::getServiceRoot( void )
 368{
 369    return( gIOServiceRoot );
 370}
 371
 372void IOService::detach( IOService * provider )
 373{
 374    IOService * newProvider = 0;
 375    SInt32      busy;
 376    bool        adjParent;
 377
 378    if( gIOKitDebug & kIOLogAttach)
 379        LOG("%s::detach(%s)\n", getName(), provider->getName());
 380
 381    lockForArbitration();
 382
 383    adjParent = ((busy = (__state[1] & kIOServiceBusyStateMask))
 384               && (provider == getProvider()));
 385
 386    detachFromParent( provider, gIOServicePlane );
 387
 388    if( busy) {
 389        newProvider = getProvider();
 390        if( busy && (__state[1] & kIOServiceTermPhase3State) && (0 == newProvider))
 391            _adjustBusy( -busy );
 392    }
 393
 394    unlockForArbitration();
 395
 396    if( newProvider) {
 397        newProvider->lockForArbitration();
 398        newProvider->_adjustBusy(1);
 399        newProvider->unlockForArbitration();
 400    }
 401
 402    // check for last client detach from a terminated service
 403    if( provider->lockForArbitration( true )) {
 404        if( adjParent)
 405            provider->_adjustBusy( -1 );
 406        if( (provider->__state[1] & kIOServiceTermPhase3State)
 407         && (0 == provider->getClient())) {
 408            provider->scheduleFinalize();
 409        }
 410        provider->unlockForArbitration();
 411    }
 412}
 413
 414/*
 415 * Register instance - publish it for matching
 416 */
 417
 418void IOService::registerService( IOOptionBits options )
 419{
 420    char *              pathBuf;
 421    const char *        path;
 422    char *              skip;
 423    int                 len;
 424    enum { kMaxPathLen  = 256 };
 425    enum { kMaxChars    = 63 };
 426
 427    IORegistryEntry * parent = this;
 428    IORegistryEntry * root = getRegistryRoot();
 429    while( parent && (parent != root))
 430        parent = parent->getParentEntry( gIOServicePlane);
 431
 432    if( parent != root) {
 433        IOLog("%s: not registry member at registerService()\n", getName());
 434        return;
 435    }
 436
 437    // Allow the Platform Expert to adjust this node.
 438    if( gIOPlatform && (!gIOPlatform->platformAdjustService(this)))
 439        return;
 440
 441    if( (this != gIOResources)
 442     && (kIOLogRegister & gIOKitDebug)) {
 443
 444        pathBuf = (char *) IOMalloc( kMaxPathLen );
 445
 446        IOLog( "Registering: " );
 447
 448        len = kMaxPathLen;
 449        if( pathBuf && getPath( pathBuf, &len, gIOServicePlane)) {
 450
 451            path = pathBuf;
 452            if( len > kMaxChars) {
 453                IOLog("..");
 454                len -= kMaxChars;
 455                path += len;
 456                if( (skip = strchr( path, '/')))
 457                    path = skip;
 458            }
 459        } else
 460            path = getName();
 461
 462        IOLog( "%s\n", path );
 463
 464        if( pathBuf)
 465            IOFree( pathBuf, kMaxPathLen );
 466    }
 467
 468    startMatching( options );
 469}
 470
 471void IOService::startMatching( IOOptionBits options )
 472{
 473    IOService * provider;
 474    UInt32      prevBusy = 0;
 475    bool        needConfig;
 476    bool        needWake = false;
 477    bool        ok;
 478    bool        sync;
 479    bool        waitAgain;
 480
 481    lockForArbitration();
 482
 483    sync = (options & kIOServiceSynchronous)
 484        || ((provider = getProvider())
 485                && (provider->__state[1] & kIOServiceSynchronousState));
 486
 487
 488    needConfig =  (0 == (__state[1] & (kIOServiceNeedConfigState | kIOServiceConfigState)))
 489               && (0 == (__state[0] & kIOServiceInactiveState));
 490
 491    __state[1] |= kIOServiceNeedConfigState;
 492
 493//    __state[0] &= ~kIOServiceInactiveState;
 494
 495//    if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
 496//                      OSKernelStackRemaining(), getName());
 497
 498    if( needConfig) {
 499        prevBusy = _adjustBusy( 1 );
 500        needWake = (0 != (kIOServiceSyncPubState & __state[1]));
 501    }
 502
 503    if( sync)
 504        __state[1] |= kIOServiceSynchronousState;
 505    else
 506        __state[1] &= ~kIOServiceSynchronousState;
 507
 508    unlockForArbitration();
 509
 510    if( needConfig) {
 511
 512        if( needWake) {
 513            IOLockLock( gIOServiceBusyLock );
 514            thread_wakeup( (event_t) this/*&__state[1]*/ );
 515            IOLockUnlock( gIOServiceBusyLock );
 516
 517        } else if( !sync || (kIOServiceAsynchronous & options)) {
 518
 519            ok = (0 != _IOServiceJob::startJob( this, kMatchNubJob, options ));
 520    
 521        } else do {
 522
 523            if( (__state[1] & kIOServiceNeedConfigState))
 524                doServiceMatch( options );
 525
 526            lockForArbitration();
 527            IOLockLock( gIOServiceBusyLock );
 528
 529            waitAgain = (prevBusy < (__state[1] & kIOServiceBusyStateMask));
 530            if( waitAgain)
 531                __state[1] |= kIOServiceSyncPubState | kIOServiceBusyWaiterState;
 532            else
 533                __state[1] &= ~kIOServiceSyncPubState;
 534
 535            unlockForArbitration();
 536
 537            if( waitAgain)
 538                assert_wait( (event_t) this/*&__state[1]*/, THREAD_UNINT);
 539
 540            IOLockUnlock( gIOServiceBusyLock );
 541            if( waitAgain)
 542                thread_block(THREAD_CONTINUE_NULL);
 543
 544        } while( waitAgain );
 545    }
 546}
 547
 548IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables )
 549{
 550    OSDictionary *      table;
 551    OSSet *             set;
 552    OSSet *             allSet = 0;
 553    IOService *         service;
 554#if IOMATCHDEBUG
 555    SInt32              count = 0;
 556#endif
 557
 558    newTables->retain();
 559    
 560    while( (table = (OSDictionary *) newTables->getFirstObject())) {
 561
 562        LOCKWRITENOTIFY();
 563        set = (OSSet *) getExistingServices( table, 
 564                                                kIOServiceRegisteredState,
 565                                                kIOServiceExistingSet);
 566        UNLOCKNOTIFY();
 567        if( set) {
 568
 569#if IOMATCHDEBUG
 570            count += set->getCount();
 571#endif
 572            if (allSet) {
 573                allSet->merge((const OSSet *) set);
 574                set->release();
 575            }
 576            else
 577                allSet = set;
 578        }
 579
 580#if IOMATCHDEBUG
 581        if( getDebugFlags( table ) & kIOLogMatch)
 582            LOG("Matching service count = %ld\n", count);
 583#endif
 584        newTables->removeObject(table);
 585    }
 586
 587    if (allSet) {
 588        while( (service = (IOService *) allSet->getAnyObject())) {
 589            service->startMatching(kIOServiceAsynchronous);
 590            allSet->removeObject(service);
 591        }
 592        allSet->release();
 593    }
 594
 595    newTables->release();
 596
 597    return( kIOReturnSuccess );
 598}
 599
 600 _IOServiceJob * _IOServiceJob::startJob( IOService * nub, int type,
 601                                                IOOptionBits options )
 602{
 603    _IOServiceJob *     job;
 604
 605    job = new _IOServiceJob;
 606    if( job && !job->init()) {
 607        job->release();
 608        job = 0;
 609    }
 610
 611    if( job) {
 612        job->type       = type;
 613        job->nub        = nub;
 614        job->options    = options;
 615        nub->retain();                  // thread will release()
 616        pingConfig( job );
 617    }
 618
 619    return( job );
 620}
 621
 622/*
 623 * Called on a registered service to see if it matches
 624 * a property table.
 625 */
 626
 627bool IOService::matchPropertyTable( OSDictionary * table, SInt32 * score )
 628{
 629    return( matchPropertyTable(table) );
 630}
 631
 632bool IOService::matchPropertyTable( OSDictionary * table )
 633{
 634    return( true );
 635}
 636
 637/*
 638 * Called on a matched service to allocate resources
 639 * before first driver is attached.
 640 */
 641
 642IOReturn IOService::getResources( void )
 643{
 644    return( kIOReturnSuccess);
 645}
 646
 647/*
 648 * Client/provider accessors
 649 */
 650
 651IOService * IOService::getProvider( void ) const
 652{
 653    IOService * self = (IOService *) this;
 654    IOService * parent;
 655    SInt32      generation;
 656
 657    parent = __provider;
 658    generation = getGenerationCount();
 659    if( __providerGeneration == generation)
 660        return( parent );
 661
 662    parent = (IOService *) getParentEntry( gIOServicePlane);
 663    if( parent == IORegistryEntry::getRegistryRoot())
 664        /* root is not an IOService */
 665        parent = 0;
 666
 667    self->__provider = parent;
 668    // save the count before getParentEntry()
 669    self->__providerGeneration = generation;
 670
 671    return( parent );
 672}
 673
 674IOWorkLoop * IOService::getWorkLoop() const
 675{ 
 676    IOService *provider = getProvider();
 677
 678    if (provider)
 679        return provider->getWorkLoop();
 680    else
 681        return 0;
 682}
 683
 684OSIterator * IOService::getProviderIterator( void ) const
 685{
 686    return( getParentIterator( gIOServicePlane));
 687}
 688
 689IOService * IOService::getClient( void ) const
 690{
 691    return( (IOService *) getChildEntry( gIOServicePlane));
 692}
 693
 694OSIterator * IOService::getClientIterator( void ) const
 695{
 696    return( getChildIterator( gIOServicePlane));
 697}
 698
 699OSIterator * _IOOpenServiceIterator::iterator( OSIterator * _iter,
 700                                                const IOService * client,
 701                                                const IOService * provider )
 702{
 703    _IOOpenServiceIterator * inst;
 704
 705    if( !_iter)
 706        return( 0 );
 707
 708    inst = new _IOOpenServiceIterator;
 709
 710    if( inst && !inst->init()) {
 711        inst->release();
 712        inst = 0;
 713    }
 714    if( inst) {
 715        inst->iter = _iter;
 716        inst->client = client;
 717        inst->provider = provider;
 718    }
 719
 720    return( inst );
 721}
 722
 723void _IOOpenServiceIterator::free()
 724{
 725    iter->release();
 726    if( last)
 727        last->unlockForArbitration();
 728    OSIterator::free();
 729}
 730
 731OSObject * _IOOpenServiceIterator::getNextObject()
 732{
 733    IOService * next;
 734
 735    if( last)
 736        last->unlockForArbitration();
 737
 738    while( (next = (IOService *) iter->getNextObject())) {
 739
 740        next->lockForArbitration();
 741        if( (client && (next->isOpen( client )))
 742         || (provider && (provider->isOpen( next ))) )
 743            break;
 744        next->unlockForArbitration();
 745    }
 746
 747    last = next;
 748
 749    return( next );
 750}
 751
 752bool _IOOpenServiceIterator::isValid()
 753{
 754    return( iter->isValid() );
 755}
 756
 757void _IOOpenServiceIterator::reset()
 758{
 759    if( last) {
 760        last->unlockForArbitration();
 761        last = 0;
 762    }
 763    iter->reset();
 764}
 765
 766OSIterator * IOService::getOpenProviderIterator( void ) const
 767{
 768    return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
 769}
 770
 771OSIterator * IOService::getOpenClientIterator( void ) const
 772{
 773    return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
 774}
 775
 776
 777IOReturn IOService::callPlatformFunction( const OSSymbol * functionName,
 778                                          bool waitForFunction,
 779                                          void *param1, void *param2,
 780                                          void *param3, void *param4 )
 781{
 782  IOReturn  result = kIOReturnUnsupported;
 783  IOService *provider = getProvider();
 784  
 785  if (provider != 0) {
 786    result = provider->callPlatformFunction(functionName, waitForFunction,
 787                                            param1, param2, param3, param4);
 788  }
 789  
 790  return result;
 791}
 792
 793IOReturn IOService::callPlatformFunction( const char * functionName,
 794                                          bool waitForFunction,
 795                                          void *param1, void *param2,
 796                                          void *param3, void *param4 )
 797{
 798  IOReturn result = kIOReturnNoMemory;
 799  const OSSymbol *functionSymbol = OSSymbol::withCString(functionName);
 800  
 801  if (functionSymbol != 0) {
 802    result = callPlatformFunction(functionSymbol, waitForFunction,
 803                                  param1, param2, param3, param4);
 804    functionSymbol->release();
 805  }
 806  
 807  return result;
 808}
 809
 810
 811/*
 812 * Accessors for global services
 813 */
 814
 815IOPlatformExpert * IOService::getPlatform( void )
 816{
 817    return( gIOPlatform);
 818}
 819
 820class IOPMrootDomain * IOService::getPMRootDomain( void )
 821{
 822    return( gIOPMRootDomain);
 823}
 824
 825IOService * IOService::getResourceService( void )
 826{
 827    return( gIOResources );
 828}
 829
 830void IOService::setPlatform( IOPlatformExpert * platform)
 831{
 832    gIOPlatform = platform;
 833    gIOResources->attachToParent( gIOServiceRoot, gIOServicePlane );
 834}
 835
 836void IOService::setPMRootDomain( class IOPMrootDomain * rootDomain)
 837{
 838    gIOPMRootDomain = rootDomain;
 839    publishResource("IOKit");
 840}
 841
 842/*
 843 * Stacking change
 844 */
 845
 846bool IOService::lockForArbitration( bool isSuccessRequired )
 847{
 848    bool                          found;
 849    bool                          success;
 850    ArbitrationLockQueueElement * element;
 851    ArbitrationLockQueueElement * active;
 852    ArbitrationLockQueueElement * waiting;
 853
 854    enum { kPutOnFreeQueue, kPutOnActiveQueue, kPutOnWaitingQueue } action;
 855
 856    // lock global access
 857    IOTakeLock( gArbitrationLockQueueLock );
 858
 859    // obtain an unused queue element
 860    if( !queue_empty( &gArbitrationLockQueueFree )) {
 861        queue_remove_first( &gArbitrationLockQueueFree,
 862                            element,
 863                            ArbitrationLockQueueElement *,
 864                            link );
 865    } else {
 866        element = IONew( ArbitrationLockQueueElement, 1 );
 867        assert( element );
 868    }
 869
 870    // prepare the queue element
 871    element->thread   = IOThreadSelf();
 872    element->service  = this;
 873    element->count    = 1;
 874    element->required = isSuccessRequired;
 875    element->aborted  = false;
 876
 877    // determine whether this object is already locked (ie. on active queue)
 878    found = false;
 879    queue_iterate( &gArbitrationLockQueueActive,
 880                    active,
 881                    ArbitrationLockQueueElement *,
 882                    link )
 883    {
 884        if( active->service == element->service ) {
 885            found = true;
 886            break;
 887        }
 888    }
 889
 890    if( found ) { // this object is already locked
 891
 892        // determine whether it is the same or a different thread trying to lock
 893        if( active->thread != element->thread ) { // it is a different thread
 894
 895            ArbitrationLockQueueElement * victim = 0;
 896
 897            // before placing this new thread on the waiting queue, we look for
 898            // a deadlock cycle...
 899
 900            while( 1 ) {
 901                // determine whether the active thread holding the object we
 902                // want is waiting for another object to be unlocked
 903                found = false;
 904                queue_iterate( &gArbitrationLockQueueWaiting,
 905                               waiting,
 906                               ArbitrationLockQueueElement *,
 907                               link )
 908                {
 909                    if( waiting->thread == active->thread ) {
 910                        assert( false == waiting->aborted );
 911                        found = true;
 912                        break;
 913                    }
 914                }
 915
 916                if( found ) { // yes, active thread waiting for another object
 917
 918                    // this may be a candidate for rejection if the required
 919                    // flag is not set, should we detect a deadlock later on
 920                    if( false == waiting->required )
 921                        victim = waiting;
 922
 923                    // find the thread that is holding this other object, that
 924                    // is blocking the active thread from proceeding (fun :-)
 925                    found = false;
 926                    queue_iterate( &gArbitrationLockQueueActive,
 927                                   active,      // (reuse active queue element)
 928                                   ArbitrationLockQueueElement *,
 929                                   link )
 930                    {
 931                        if( active->service == waiting->service ) {
 932                            found = true;
 933                            break;
 934                        }
 935                    }
 936
 937                    // someone must be holding it or it wouldn't be waiting
 938                    assert( found );
 939
 940                    if( active->thread == element->thread ) {
 941
 942                        // doh, it's waiting for the thread that originated
 943                        // this whole lock (ie. current thread) -> deadlock
 944                        if( false == element->required ) { // willing to fail?
 945
 946                            // the originating thread doesn't have the required
 947                            // flag, so it can fail
 948                            success = false; // (fail originating lock request)
 949                            break; // (out of while)
 950
 951                        } else { // originating thread is not willing to fail
 952
 953                            // see if we came across a waiting thread that did
 954                            // not have the 'required' flag set: we'll fail it
 955                            if( victim ) {
 956
 957                                // we do have a willing victim, fail it's lock
 958                                victim->aborted = true;
 959
 960                                // take the victim off the waiting queue
 961                                queue_remove( &gArbitrationLockQueueWaiting,
 962                                              victim,
 963                                              ArbitrationLockQueueElement *,
 964                                              link );
 965
 966                                // wake the victim
 967                                IOLockWakeup( gArbitrationLockQueueLock, 
 968                                              victim, 
 969                                              /* one thread */ true );
 970
 971                                // allow this thread to proceed (ie. wait)
 972                                success = true; // (put request on wait queue)
 973                                break; // (out of while)
 974                            } else {
 975
 976                                // all the waiting threads we came across in
 977                                // finding this loop had the 'required' flag
 978                                // set, so we've got a deadlock we can't avoid
 979                                panic("I/O Kit: Unrecoverable deadlock.");
 980                            }
 981                        }
 982                    } else {
 983                        // repeat while loop, redefining active thread to be the
 984                        // thread holding "this other object" (see above), and
 985                        // looking for threads waiting on it; note the active
 986                        // variable points to "this other object" already... so
 987                        // there nothing to do in this else clause.
 988                    }
 989                } else { // no, active thread is not waiting for another object
 990                      
 991                    success = true; // (put request on wait queue)
 992                    break; // (out of while)
 993                }
 994            } // while forever
 995
 996            if( success ) { // put the request on the waiting queue?
 997                kern_return_t wait_result;
 998
 999                // place this thread on the waiting queue and put it to sleep;
1000                // we place it at the tail of the queue...
1001                queue_enter( &gArbitrationLockQueueWaiting,
1002                             element,
1003                             ArbitrationLockQueueElement *,
1004                             link );
1005
1006                // declare that this thread will wait for a given event
1007restart_sleep:  wait_result = assert_wait( element,
1008                                           element->required ? THREAD_UNINT
1009                                           : THREAD_INTERRUPTIBLE );
1010
1011                // unlock global access
1012                IOUnlock( gArbitrationLockQueueLock );
1013
1014                // put thread to sleep, waiting for our event to fire...
1015                if (wait_result == THREAD_WAITING)
1016                    wait_result = thread_block(THREAD_CONTINUE_NULL);
1017
1018
1019                // ...and we've been woken up; we might be in one of two states:
1020                // (a) we've been aborted and our queue element is not on
1021                //     any of the three queues, but is floating around
1022                // (b) we're allowed to proceed with the lock and we have
1023                //     already been moved from the waiting queue to the
1024                //     active queue.
1025                // ...plus a 3rd state, should the thread have been interrupted:
1026                // (c) we're still on the waiting queue
1027
1028                // determine whether we were interrupted out of our sleep
1029                if( THREAD_INTERRUPTED == wait_result ) {
1030
1031                    // re-lock global access
1032                    IOTakeLock( gArbitrationLockQueueLock );
1033
1034                    // determine whether we're still on the waiting queue
1035                    found = false;
1036                    queue_iterate( &gArbitrationLockQueueWaiting,
1037                                   waiting,     // (reuse waiting queue element)
1038                                   ArbitrationLockQueueElement *,
1039                                   link )
1040                    {
1041                        if( waiting == element ) {
1042                            found = true;
1043                            break;
1044                        }
1045                    }
1046
1047                    if( found ) { // yes, we're still on the waiting queue
1048
1049                        // determine whether we're willing to fail
1050                        if( false == element->required ) {
1051
1052                            // mark us as aborted
1053                            element->aborted = true;
1054
1055                            // take us off the waiting queue
1056                            queue_remove( &gArbitrationLockQueueWaiting,
1057                                          element,
1058                                          ArbitrationLockQueueElement *,
1059                                          link );
1060                        } else { // we are not willing to fail
1061
1062                            // ignore interruption, go back to sleep
1063                            goto restart_sleep;
1064                        }
1065                    }
1066
1067                    // unlock global access
1068                    IOUnlock( gArbitrationLockQueueLock );
1069
1070                    // proceed as though this were a normal wake up
1071                    wait_result = THREAD_AWAKENED;
1072                }
1073
1074                assert( THREAD_AWAKENED == wait_result );
1075
1076                // determine whether we've been aborted while we were asleep
1077                if( element->aborted ) {
1078                    assert( false == element->required );
1079
1080                    // re-lock global access
1081                    IOTakeLock( gArbitrationLockQueueLock );
1082
1083                    action = kPutOnFreeQueue;
1084                    success = false;
1085                } else { // we weren't aborted, so we must be ready to go :-)
1086
1087                    // we've already been moved from waiting to active queue
1088                    return true;
1089                }
1090
1091            } else { // the lock request is to be failed
1092
1093                // return unused queue element to queue
1094                action = kPutOnFreeQueue;
1095            }
1096        } else { // it is the same thread, recursive access is allowed
1097
1098            // add one level of recursion
1099            active->count++;
1100
1101            // return unused queue element to queue
1102            action = kPutOnFreeQueue;
1103            success = true;
1104        }
1105    } else { // this object is not already locked, so let this thread through
1106        action = kPutOnActiveQueue;
1107        success = true;
1108    }
1109
1110    // put the new element on a queue
1111    if( kPutOnActiveQueue == action ) {
1112        queue_enter( &gArbitrationLockQueueActive,
1113                     element,
1114                     ArbitrationLockQueueElement *,
1115                     link );
1116    } else if( kPutOnFreeQueue == action ) {
1117        queue_enter( &gArbitrationLockQueueFree,
1118                     element,
1119                     ArbitrationLockQueueElement *,
1120                     link );
1121    } else {
1122        assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1123    }
1124
1125    // unlock global access
1126    IOUnlock( gArbitrationLockQueueLock );
1127
1128    return( success );
1129}
1130
1131void IOService::unlockForArbitration( void )
1132{
1133    bool                          found;
1134    ArbitrationLockQueueElement * element;
1135
1136    // lock global access
1137    IOTakeLock( gArbitrationLockQueueLock );
1138
1139    // find the lock element for this object (ie. on active queue)
1140    found = false;
1141    queue_iterate( &gArbitrationLockQueueActive,
1142                    element,
1143                    ArbitrationLockQueueElement *,
1144                    link )
1145    {
1146        if( element->service == this ) {
1147            found = true;
1148            break;
1149        }
1150    }
1151
1152    assert( found );
1153
1154    // determine whether the lock has been taken recursively
1155    if( element->count > 1 ) {
1156        // undo one level of recursion
1157        element->count--;
1158
1159    } else {
1160
1161        // remove it from the active queue
1162        queue_remove( &gArbitrationLockQueueActive,
1163                      element,
1164                      ArbitrationLockQueueElement *,
1165                      link );
1166
1167        // put it on the free queue
1168        queue_enter( &gArbitrationLockQueueFree,
1169                     element,
1170                     ArbitrationLockQueueElement *,
1171                     link );
1172
1173        // determine whether a thread is waiting for object (head to tail scan)
1174        found = false;
1175        queue_iterate( &gArbitrationLockQueueWaiting,
1176                       element,
1177                       ArbitrationLockQueueElement *,
1178                       link )
1179        {
1180            if( element->service == this ) {
1181                found = true;
1182                break;
1183            }
1184        }
1185
1186        if ( found ) { // we found an interested thread on waiting queue
1187
1188            // remove it from the waiting queue
1189            queue_remove( &gArbitrationLockQueueWaiting,
1190                          element,
1191                          ArbitrationLockQueueElement *,
1192                          link );
1193
1194            // put it on the active queue
1195            queue_enter( &gArbitrationLockQueueActive,
1196                         element,
1197                         ArbitrationLockQueueElement *,
1198                         link );
1199
1200            // wake the waiting thread
1201            IOLockWakeup( gArbitrationLockQueueLock,
1202                          element,
1203                          /* one thread */ true );
1204        }
1205    }
1206
1207    // unlock global access
1208    IOUnlock( gArbitrationLockQueueLock );
1209}
1210
1211void IOService::applyToProviders( IOServiceApplierFunction applier,
1212                                  void * context )
1213{
1214    applyToParents( (IORegistryEntryApplierFunction) applier,
1215                    context, gIOServicePlane );
1216}
1217
1218void IOService::applyToClients( IOServiceApplierFunction applier,
1219                                void * context )
1220{
1221    applyToChildren( (IORegistryEntryApplierFunction) applier,
1222                     context, gIOServicePlane );
1223}
1224
1225
1226/*
1227 * Client messages
1228 */
1229
1230
1231// send a message to a client or interested party of this service
1232IOReturn IOService::messageClient( UInt32 type, OSObject * client,
1233                                   void * argument, vm_size_t argSize )
1234{
1235    IOReturn                            ret;
1236    IOService *                         service;
1237    _IOServiceInterestNotifier *        notify;
1238
1239    if( (service = OSDynamicCast( IOService, client)))
1240        ret = service->message( type, this, argument );
1241    
1242    else if( (notify = OSDynamicCast( _IOServiceInterestNotifier, client))) {
1243
1244        _IOServiceNotifierInvocation invocation;
1245        bool                     willNotify;
1246    
1247        invocation.thread = current_thread();
1248    
1249        LOCKWRITENOTIFY();
1250        willNotify = (0 != (kIOServiceNotifyEnable & notify->state));
1251    
1252        if( willNotify) {
1253            queue_enter( &notify->handlerInvocations, &invocation,
1254                            _IOServiceNotifierInvocation *, link );
1255        }
1256        UNLOCKNOTIFY();
1257    
1258        if( willNotify) {
1259
1260            ret = (*notify->handler)( notify->target, notify->ref,
1261                                          type, this, argument, argSize );
1262    
1263            LOCKWRITENOTIFY();
1264            queue_remove( &notify->handlerInvocations, &invocation,
1265                            _IOServiceNotifierInvocation *, link );
1266            if( kIOServiceNotifyWaiter & notify->state) {
1267                notify->state &= ~kIOServiceNotifyWaiter;
1268                WAKEUPNOTIFY( notify );
1269            }
1270            UNLOCKNOTIFY();
1271
1272        } else
1273            ret = kIOReturnSuccess;
1274
1275    } else
1276        ret = kIOReturnBadArgument;
1277
1278    return( ret );
1279}
1280
1281void IOService::applyToInterested( const OSSymbol * typeOfInterest,
1282                                   OSObjectApplierFunction applier,
1283                                   void * context )
1284{
1285    OSArray *           copyArray = 0;
1286
1287    applyToClients( (IOServiceApplierFunction) applier, context );
1288
1289    LOCKREADNOTIFY();
1290
1291    IOCommand *notifyList =
1292        OSDynamicCast( IOCommand, getProperty( typeOfInterest ));
1293
1294    if( notifyList) {
1295        copyArray = OSArray::withCapacity(1);
1296
1297        // iterate over queue, entry is set to each element in the list
1298        iterqueue(&notifyList->fCommandChain, entry) {
1299            _IOServiceInterestNotifier * notify;
1300
1301            queue_element(entry, notify, _IOServiceInterestNotifier *, chain);
1302            copyArray->setObject(notify);
1303        }
1304    }
1305    UNLOCKNOTIFY();
1306
1307    if( copyArray) {
1308        unsigned int    index;
1309        OSObject *      next;
1310
1311        for( index = 0; (next = copyArray->getObject( index )); index++)
1312            (*applier)(next, context);
1313        copyArray->release();
1314    }
1315}
1316
1317struct MessageClientsContext {
1318    IOService * service;
1319    UInt32      type;
1320    void *      argument;
1321    vm_size_t   argSize;
1322    IOReturn    ret;
1323};
1324
1325static void messageClientsApplier( OSObject * object, void * ctx )
1326{
1327    IOReturn                ret;
1328    MessageClientsContext * context = (MessageClientsContext *) ctx;
1329
1330    ret = context->service->messageClient( context->type,
1331                                           object, context->argument, context->argSize );    
1332    if( kIOReturnSuccess != ret)
1333        context->ret = ret;
1334}
1335
1336// send a message to all clients
1337IOReturn IOService::messageClients( UInt32 type,
1338                                    void * argument, vm_size_t argSize )
1339{
1340    MessageClientsContext       context;
1341
1342    context.service     = this;
1343    context.type        = type;
1344    context.argument    = argument;
1345    context.argSize     = argSize;
1346    context.ret         = kIOReturnSuccess;
1347
1348    applyToInterested( gIOGeneralInterest,
1349                       &messageClientsApplier, &context );
1350
1351    return( context.ret );
1352}
1353
1354IOReturn IOService::acknowledgeNotification( IONotificationRef notification,
1355                                              IOOptionBits response )
1356{
1357    return( kIOReturnUnsupported );
1358}
1359
1360IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest,
1361                  IOServiceInterestHandler handler, void * target, void * ref )
1362{
1363    _IOServiceInterestNotifier * notify = 0;
1364
1365    if( (typeOfInterest != gIOGeneralInterest)
1366     && (typeOfInterest != gIOBusyInterest)
1367     && (typeOfInterest != gIOAppPowerStateInterest)
1368     && (typeOfInterest != gIOPriorityPowerStateInterest))
1369        return( 0 );
1370
1371    lockForArbitration();
1372    if( 0 == (__state[0] & kIOServiceInactiveState)) {
1373
1374        notify = new _IOServiceInterestNotifier;
1375        if( notify && !notify->init()) {
1376            notify->release();
1377            notify = 0;
1378        }
1379
1380        if( notify) {
1381            notify->handler = handler;
1382            notify->target = target;
1383            notify->ref = ref;
1384            notify->state = kIOServiceNotifyEnable;
1385            queue_init( &notify->handlerInvocations );
1386
1387            ////// queue
1388
1389            LOCKWRITENOTIFY();
1390
1391            // Get the head of the notifier linked list
1392            IOCommand *notifyList = (IOCommand *) getProperty( typeOfInterest );
1393            if (!notifyList || !OSDynamicCast(IOCommand, notifyList)) {
1394                notifyList = OSTypeAlloc(IOCommand);
1395                if (notifyList) {
1396                    notifyList->init();
1397                    setProperty( typeOfInterest, notifyList);
1398                    notifyList->release();
1399                }
1400            }
1401
1402            if (notifyList) {
1403                enqueue(&notifyList->fCommandChain, &notify->chain);
1404                notify->retain();       // ref'ed while in list
1405            }
1406
1407            UNLOCKNOTIFY();
1408        }
1409    }
1410    unlockForArbitration();
1411
1412    return( notify );
1413}
1414
1415static void cleanInterestList( OSObject * head )
1416{
1417    IOCommand *notifyHead = OSDynamicCast(IOCommand, head);
1418    if (!notifyHead)
1419        return;
1420
1421    LOCKWRITENOTIFY();
1422    while ( queue_entry_t entry = dequeue(&notifyHead->fCommandChain) ) {
1423        queue_next(entry) = queue_prev(entry) = 0;
1424
1425        _IOServiceInterestNotifier * notify;
1426
1427        queue_element(entry, notify, _IOServiceInterestNotifier *, chain);
1428        notify->release();
1429    }
1430    UNLOCKNOTIFY();
1431}
1432
1433void IOService::unregisterAllInterest( void )
1434{
1435    cleanInterestList( getProperty( gIOGeneralInterest ));
1436    cleanInterestList( getProperty( gIOBusyInterest ));
1437    cleanInterestList( getProperty( gIOAppPowerStateInterest ));
1438    cleanInterestList( getProperty( gIOPriorityPowerStateInterest ));
1439}
1440
1441/*
1442 * _IOServiceInterestNotifier
1443 */
1444
1445// wait for all threads, other than the current one,
1446//  to exit the handler
1447
1448void _IOServiceInterestNotifier::wait()
1449{
1450    _IOServiceNotifierInvocation * next;
1451    bool doWait;
1452
1453    do {
1454        doWait = false;
1455        queue_iterate( &handlerInvocations, next,
1456                        _IOServiceNotifierInvocation *, link) {
1457            if( next->thread != current_thread() ) {
1458                doWait = true;
1459                break;
1460            }
1461        }
1462        if( doWait) {
1463            state |= kIOServiceNotifyWaiter;
1464               SLEEPNOTIFY(this);
1465        }
1466
1467    } while( doWait );
1468}
1469
1470void _IOServiceInterestNotifier::free()
1471{
1472    assert( queue_empty( &handlerInvocations ));
1473    OSObject::free();
1474}
1475
1476void _IOServiceInterestNotifier::remove()
1477{
1478    LOCKWRITENOTIFY();
1479
1480    if( queue_next( &chain )) {
1481        remqueue( 0, &chain);
1482        queue_next( &chain) = queue_prev( &chain) = 0;
1483        release();
1484    }
1485
1486    state &= ~kIOServiceNotifyEnable;
1487
1488    wait();
1489
1490    UNLOCKNOTIFY();
1491    
1492    release();
1493}
1494
1495bool _IOServiceInterestNotifier::disable()
1496{
1497    bool        ret;
1498
1499    LOCKWRITENOTIFY();
1500
1501    ret = (0 != (kIOServiceNotifyEnable & state));
1502    state &= ~kIOServiceNotifyEnable;
1503    if( ret)
1504        wait();
1505
1506    UNLOCKNOTIFY();
1507
1508    return( ret );
1509}
1510
1511void _IOServiceInterestNotifier::enable( bool was )
1512{
1513    LOCKWRITENOTIFY();
1514    if( was)
1515        state |= kIOServiceNotifyEnable;
1516    else
1517        state &= ~kIOServiceNotifyEnable;
1518    UNLOCKNOTIFY();
1519}
1520
1521/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1522
1523/*
1524 * Termination
1525 */
1526
1527#define tailQ(o)                setObject(o)
1528#define headQ(o)                setObject(0, o)
1529#define TLOG(fmt, args...)      { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); }
1530
1531inline void _workLoopAction( IOWorkLoop::Action action,
1532                             IOService * service,
1533                             void * p0 = 0, void * p1 = 0,
1534                             void * p2 = 0, void * p3 = 0 )
1535{
1536    IOWorkLoop * wl;
1537
1538    if( (wl = service->getWorkLoop())) {
1539        wl->retain();
1540        wl->runAction( action, service, p0, p1, p2, p3 );
1541        wl->release();
1542    } else
1543        (*action)( service, p0, p1, p2, p3 );
1544}
1545
1546bool IOService::requestTerminate( IOService * provider, IOOptionBits options )
1547{
1548    bool ok;
1549
1550    // if its our only provider
1551    ok = isParent( provider, gIOServicePlane, true);
1552
1553    // -- compat
1554    if( ok) {
1555        provider->terminateClient( this, options | kIOServiceRecursing );
1556        ok = (0 != (__state[1] & kIOServiceRecursing));
1557    }
1558    // --
1559
1560    return( ok );
1561}
1562
1563bool IOService::terminatePhase1( IOOptionBits options )
1564{
1565    IOService *         victim;
1566    IOService *         client;
1567    OSIterator *        iter;
1568    OSArray *           makeInactive;
1569    bool                ok;
1570    bool                didInactive;
1571    bool                startPhase2 = false;
1572
1573    TLOG("%s::terminatePhase1(%08lx)\n", getName(), options);
1574
1575    // -- compat
1576    if( options & kIOServiceRecursing) {
1577        __state[1] |= kIOServiceRecursing;
1578        return( true );
1579    }
1580    // -- 
1581
1582    makeInactive = OSArray::withCapacity( 16 );
1583    if( !makeInactive)
1584        return( false );
1585
1586    victim = this;
1587    victim->retain();
1588
1589    while( victim ) {
1590
1591        didInactive = victim->lockForArbitration( true );
1592        if( didInactive) {
1593            didInactive = (0 == (victim->__state[0] & kIOServiceInactiveState));
1594            if( didInactive) {
1595                victim->__state[0] |= kIOServiceInactiveState;
1596                victim->__state[0] &= ~(kIOServiceRegisteredState | kIOServiceMatchedState
1597                                        | kIOServiceFirstPublishState | kIOServiceFirstMatchState);
1598                victim->_adjustBusy( 1 );
1599            }
1600            victim->unlockForArbitration();
1601        }
1602        if( victim == this)
1603            startPhase2 = didInactive;
1604        if( didInactive) {
1605
1606            victim->deliverNotification( gIOTerminatedNotification, 0, 0xffffffff );
1607            IOUserClient::destroyUserReferences( victim );
1608
1609            iter = victim->getClientIterator();
1610            if( iter) {
1611                while( (client = (IOService *) iter->getNextObject())) {
1612                    TLOG("%s::requestTerminate(%s, %08lx)\n",
1613                            client->getName(), victim->getName(), options);
1614                    ok = client->requestTerminate( victim, options );
1615                    TLOG("%s::requestTerminate(%s, ok = %d)\n",
1616                            client->getName(), victim->getName(), ok);
1617                    if( ok)
1618                        makeInactive->setObject( client );
1619                }
1620                iter->release();
1621            }
1622        }
1623        victim->release();
1624        victim = (IOService *) makeInactive->getObject(0);
1625        if( victim) {
1626            victim->retain();
1627            makeInactive->removeObject(0);
1628        }
1629    }
1630
1631    makeInactive->release();
1632
1633    if( startPhase2)
1634        scheduleTerminatePhase2( options );
1635
1636    return( true );
1637}
1638
1639void IOService::scheduleTerminatePhase2( IOOptionBits options )
1640{
1641    AbsoluteTime        deadline;
1642    int                 waitResult = THREAD_AWAKENED;
1643    bool                wait, haveDeadline = false;
1644
1645    options |= kIOServiceRequired;
1646
1647    retain();
1648
1649    IOLockLock( gJobsLock );
1650
1651    if( (options & kIOServiceSynchronous)
1652        && (current_thread() != gIOTerminateThread)) {
1653
1654        do {
1655            wait = (gIOTerminateThread != 0);
1656            if( wait) {
1657                // wait to become the terminate thread
1658                IOLockSleep( gJobsLock, &gIOTerminateThread, THREAD_UNINT);
1659            }
1660        } while( wait );
1661
1662        gIOTerminateThread = current_thread();
1663        gIOTerminatePhase2List->setObject( this );
1664        gIOTerminateWork++;
1665
1666        do {
1667            while( gIOTerminateWork )
1668                terminateWorker( options );
1669            wait = (0 != (__state[1] & kIOServiceBusyStateMask));
1670            if( wait) {
1671                // wait for the victim to go non-busy
1672                if( !haveDeadline) {
1673                    clock_interval_to_deadline( 15, kSecondScale, &deadline );
1674                    haveDeadline = true;
1675                }
1676                waitResult = IOLockSleepDeadline( gJobsLock, &gIOTerminateWork,
1677                                                  deadline, THREAD_UNINT );
1678                if( waitResult == THREAD_TIMED_OUT) {
1679                    TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName());
1680                                }
1681            }
1682        } while(gIOTerminateWork || (wait && (waitResult != THREAD_TIMED_OUT)));
1683
1684        gIOTerminateThread = 0;
1685        IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
1686
1687    } else {
1688        // ! kIOServiceSynchronous
1689
1690        gIOTerminatePhase2List->setObject( this );
1691        if( 0 == gIOTerminateWork++) {
1692            if( !gIOTerminateThread)
1693                gIOTerminateThread = IOCreateThread( &terminateThread, (void *) options );
1694            else
1695                IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false );
1696        }
1697    }
1698
1699    IOLockUnlock( gJobsLock );
1700
1701    release();
1702}
1703
1704void IOService::terminateThread( void * arg )
1705{
1706    IOLockLock( gJobsLock );
1707
1708    while (gIOTerminateWork)
1709        terminateWorker( (IOOptionBits) arg );
1710
1711    gIOTerminateThread = 0;
1712    IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
1713
1714    IOLockUnlock( gJobsLock );
1715}
1716
1717void IOService::scheduleStop( IOService * provider )
1718{
1719    TLOG("%s::scheduleStop(%s)\n", getName(), provider->getName());
1720
1721    IOLockLock( gJobsLock );
1722    gIOStopList->tailQ( this );
1723    gIOStopProviderList->tailQ( provider );
1724
1725    if( 0 == gIOTerminateWork++) {
1726        if( !gIOTerminateThread)
1727            gIOTerminateThread = IOCreateThread( &terminateThread, (void *) 0 );
1728        else
1729            IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false );
1730    }
1731
1732    IOLockUnlock( gJobsLock );
1733}
1734
1735void IOService::scheduleFinalize( void )
1736{
1737    TLOG("%s::scheduleFinalize\n", getName());
1738
1739    IOLockLock( gJobsLock );
1740    gIOFinalizeList->tailQ( this );
1741
1742    if( 0 == gIOTerminateWork++) {
1743        if( !gIOTerminateThread)
1744            gIOTerminateThread = IOCreateThread( &terminateThread, (void *) 0 );
1745        else
1746            IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false );
1747    }
1748
1749    IOLockUnlock( gJobsLock );
1750}
1751
1752bool IOService::willTerminate( IOService * provider, IOOptionBits options )
1753{
1754    return( true );
1755}
1756
1757bool IOService::didTerminate( IOService * provider, IOOptionBits options, bool * defer )
1758{
1759    if( false == *defer) {
1760
1761        if( lockForArbitration( true )) {
1762            if( false == provider->handleIsOpen( this ))
1763                scheduleStop( provider );
1764            // -- compat
1765            else {
1766                message( kIOMessageServiceIsRequestingClose, provider, (void *) options );
1767                if( false == provider->handleIsOpen( this ))
1768                    scheduleStop( provider );
1769            }
1770            // --
1771            unlockForArbitration();
1772        }
1773    }
1774
1775    return( true );
1776}
1777
1778void IOService::actionWillTerminate( IOService * victim, IOOptionBits options, 
1779                                    OSArray * doPhase2List )
1780{
1781    OSIterator * iter;
1782    IOService *  client;
1783    bool         ok;
1784
1785    iter = victim->getClientIterator();
1786    if( iter) {
1787        while( (client = (IOService *) iter->getNextObject())) {
1788            TLOG("%s::willTerminate(%s, %08lx)\n",
1789                    client->getName(), victim->getName(), options);
1790            ok = client->willTerminate( victim, options );
1791            doPhase2List->tailQ( client );
1792        }
1793        iter->release();
1794    }
1795}
1796
1797void IOService::actionDidTerminate( IOService * victim, IOOptionBits options )
1798{
1799    OSIterator * iter;
1800    IOService *  client;
1801    bool defer = false;
1802
1803    victim->messageClients( kIOMessageServiceIsTerminated, (void *) options );
1804
1805    iter = victim->getClientIterator();
1806    if( iter) {
1807        while( (client = (IOService *) iter->getNextObject())) {
1808            TLOG("%s::didTerminate(%s, %08lx)\n",
1809                    client->getName(), victim->getName(), options);
1810            client->didTerminate( victim, options, &defer );
1811            TLOG("%s::didTerminate(%s, defer %d)\n",
1812                    client->getName(), victim->getName(), defer);
1813        }
1814        iter->release();
1815    }
1816}
1817
1818void IOService::actionFinalize( IOService * victim, IOOptionBits options )
1819{
1820    TLOG("%s::finalize(%08lx)\n", victim->getName(), options);
1821    victim->finalize( options );
1822}
1823
1824void IOService::actionStop( IOService * provider, IOService * client )
1825{
1826    TLOG("%s::stop(%s)\n", client->getName(), provider->getName());
1827    client->stop( provider );
1828    if( provider->isOpen( client ))
1829        provider->close( client );
1830    TLOG("%s::detach(%s)\n", client->getName(), provider->getName());
1831    client->detach( provider );
1832}
1833
1834void IOService::terminateWorker( IOOptionBits options )
1835{
1836    OSArray *           doPhase2List;
1837    OSArray *           didPhase2List;
1838    OSSet *             freeList;
1839    UInt32              workDone;
1840    IOService *         victim;
1841    IOService *         client;
1842    IOService *         provider;
1843    unsigned int        idx;
1844    bool                moreToDo;
1845    bool                doPhase2;
1846    bool                doPhase3;
1847
1848    options |= kIOServiceRequired;
1849
1850    doPhase2List  = OSArray::withCapacity( 16 );
1851    didPhase2List = OSArray::withCapacity( 16 );
1852    freeList      = OSSet::withCapacity( 16 );
1853    if( (0 == doPhase2List) || (0 == didPhase2List) || (0 == freeList))
1854        return;
1855
1856    do {
1857        workDone = gIOTerminateWork;
1858
1859        while( (victim = (IOService *) gIOTerminatePhase2List->getObject(0) )) {
1860    
1861            victim->retain();
1862            gIOTerminatePhase2List->removeObject(0);
1863            IOLockUnlock( gJobsLock );
1864
1865            while( victim ) {
1866        
1867                doPhase2 = victim->lockForArbitration( true );
1868                if( doPhase2) {
1869                    doPhase2 = (0 != (kIOServiceInactiveState & victim->__state[0]));
1870                    if( doPhase2) {
1871                        doPhase2 = (0 == (victim->__state[1] & kIOServiceTermPhase2State))
1872                                && (0 == (victim->__state[1] & kIOServiceConfigState));
1873                        if( doPhase2)
1874                            victim->__state[1] |= kIOServiceTermPhase2State;
1875                    }
1876                    victim->unlockForArbitration();
1877                }
1878                if( doPhase2) {
1879                    if( 0 == victim->getClient()) {
1880                        // no clients - will go to finalize
1881                        IOLockLock( gJobsLock );
1882                        gIOFinalizeList->tailQ( victim );
1883                        IOLockUnlock( gJobsLock );
1884                    } else {
1885                        _workLoopAction( (IOWorkLoop::Action) &actionWillTerminate,
1886                                            victim, (void *) options, (void *) doPhase2List );
1887                    }
1888                    didPhase2List->headQ( victim );
1889                }
1890                victim->release();
1891                victim = (IOService *) doPhase2List->getObject(0);
1892                if( victim) {
1893                    victim->retain();
1894                    doPhase2List->removeObject(0);
1895                }
1896            }
1897        
1898            while( (victim = (IOService *) didPhase2List->getObject(0)) ) {
1899    
1900                if( victim->lockForArbitration( true )) {
1901                    victim->__state[1] |= kIOServiceTermPhase3State;
1902                    victim->unlockForArbitration();
1903                }
1904                _workLoopAction( (IOWorkLoop::Action) &actionDidTerminate,
1905                                    victim, (void *) options );
1906                didPhase2List->removeObject(0);
1907            }
1908            IOLockLock( gJobsLock );
1909        }
1910
1911        // phase 3
1912        do {
1913            doPhase3 = false;
1914            // finalize leaves
1915            while( (victim = (IOService *) gIOFinalizeList->getObject(0))) {
1916    
1917                IOLockUnlock( gJobsLock );
1918                _workLoopAction( (IOWorkLoop::Action) &actionFinalize,
1919                                    victim, (void *) options );
1920                IOLockLock( gJobsLock );
1921                // hold off free
1922                freeList->setObject( victim );
1923                // safe if finalize list is append only
1924                gIOFinalizeList->removeObject(0);
1925            }
1926        
1927            for( idx = 0;
1928                 (!doPhase3) && (client = (IOService *) gIOStopList->getObject(idx)); ) {
1929        
1930                provider = (IOService *) gIOStopProviderList->getObject(idx);
1931                assert( provider );
1932        
1933                if( !provider->isChild( client, gIOServicePlane )) {
1934                    // may be multiply queued - nop it
1935                    TLOG("%s::nop stop(%s)\n", client->getName(), provider->getName());
1936                } else {
1937                    // not ready for stop if it has clients, skip it
1938                    if( (client->__state[1] & kIOServiceTermPhase3State) && client->getClient()) {
1939                        TLOG("%s::defer stop(%s)\n", client->getName(), provider->getName());
1940                        idx++;
1941                        continue;
1942                    }
1943        
1944                    IOLockUnlock( gJobsLock );
1945                    _workLoopAction( (IOWorkLoop::Action) &actionStop,
1946                                     provider, (void *) client );
1947                    IOLockLock( gJobsLock );
1948                    // check the finalize list now
1949                    doPhase3 = true;
1950                }
1951                // hold off free
1952                freeList->setObject( client );
1953                freeList->setObject( provider );
1954
1955                // safe if stop list is append only
1956                gIOStopList->removeObject( idx );
1957                gIOStopProviderList->removeObject( idx );
1958                idx = 0;
1959            }
1960
1961        } while( doPhase3 );
1962
1963        gIOTerminateWork -= workDone;
1964        moreToDo = (gIOTerminateWork != 0);
1965
1966        if( !moreToDo) {
1967            TLOG("iokit terminate done, %d stops remain\n", gIOStopList->getCount());
1968        }
1969
1970    } while( moreToDo );
1971
1972    IOLockUnlock( gJobsLock );
1973
1974    freeList->release();
1975    doPhase2List->release();
1976    didPhase2List->release();
1977
1978    IOLockLock( gJobsLock );
1979}
1980
1981bool IOService::finalize( IOOptionBits options )
1982{
1983    OSIterator *        iter;
1984    IOService *         provider;
1985
1986    iter = getProviderIterator();
1987    assert( iter );
1988
1989    if( iter) {
1990        while( (provider = (IOService *) iter->getNextObject())) {
1991
1992            // -- compat
1993            if( 0 == (__state[1] & kIOServiceTermPhase3State)) {
1994                /* we come down here on programmatic terminate */
1995                stop( provider );
1996                if( provider->isOpen( this ))
1997                    provider->close( this );
1998                detach( provider );
1999            } else {
2000            //--
2001                if( provider->lockForArbitration( true )) {
2002                    if( 0 == (provider->__state[1] & kIOServiceTermPhase3State))
2003                        scheduleStop( provider );
2004                    provider->unlockForArbitration();
2005                }
2006            }
2007        }
2008        iter->release();
2009    }
2010
2011    return( true );
2012}
2013
2014#undef tailQ
2015#undef headQ
2016
2017/*
2018 * Terminate
2019 */
2020
2021void IOService::doServiceTerminate( IOOptionBits options )
2022{
2023}
2024
2025// a method in case someone needs to override it
2026bool IOService::terminateClient( IOService * client, IOOptionBits options )
2027{
2028    bool ok;
2029
2030    if( client->isParent( this, gIOServicePlane, true))
2031        // we are the clients only provider
2032        ok = client->terminate( options );
2033    else
2034        ok = true;
2035
2036    return( ok );
2037}
2038
2039bool IOService::terminate( IOOptionBits options )
2040{
2041    options |= kIOServiceTerminate;
2042
2043    return( terminatePhase1( options ));
2044}
2045
2046/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2047
2048/*
2049 * Open & close
2050 */
2051
2052struct ServiceOpenMessageContext
2053{
2054    IOService *  service;
2055    UInt32       type;
2056    IOService *  excludeClient;
2057    IOOptionBits options;
2058};
2059
2060static void serviceOpenMessageApplier( OSObject * object, void * ctx )
2061{
2062    ServiceOpenMessageContext * context = (ServiceOpenMessageContext *) ctx;
2063
2064    if( object != context->excludeClient)
2065        context->service->messageClient( context->type, object, (void *) context->options );    
2066}
2067
2068bool IOService::open(   IOService *     forClient,
2069                        IOOptionBits    options,
2070                        void *          arg )
2071{
2072    bool                        ok;
2073    ServiceOpenMessageContext   context;
2074
2075    context.service             = this;
2076    context.type                = kIOMessageServiceIsAttemptingOpen;
2077    context.excludeClient       = forClient;
2078    context.options             = options;
2079
2080    applyToInterested( gIOGeneralInterest,
2081                        &serviceOpenMessageApplier, &context );
2082
2083    if( false == lockForArbitration(false) )
2084        return false;
2085
2086    ok = (0 == (__state[0] & kIOServiceInactiveState));
2087    if( ok)
2088        ok = handleOpen( forClient, options, arg );
2089
2090    unlockForArbitration();
2091
2092    return( ok );
2093}
2094
2095void IOService::close(  IOService *     forClient,
2096                        IOOptionBits    options )
2097{
2098    bool                wasClosed;
2099    bool                last = false;
2100
2101    lockForArbitration();
2102
2103    wasClosed = handleIsOpen( forClient );
2104    if( wasClosed) {
2105        handleClose( forClient, options );
2106        last = (__state[1] & kIOServiceTermPhase3State);
2107    }
2108
2109    unlockForArbitration();
2110
2111    if( last)
2112        forClient->scheduleStop( this );
2113
2114    else if( wasClosed) {
2115
2116        ServiceOpenMessageContext context;
2117    
2118        context.service         = this;
2119        context.type            = kIOMessageServiceWasClosed;
2120        context.excludeClient   = forClient;
2121        context.options         = options;
2122
2123        applyToInterested( gIOGeneralInterest,
2124                            &serviceOpenMessageApplier, &context );
2125    }
2126}
2127
2128bool IOService::isOpen( const IOService * forClient ) const
2129{
2130    IOService * self = (IOService *) this;
2131    bool ok;
2132
2133    self->lockForArbitration();
2134
2135    ok = handleIsOpen( forClient );
2136
2137    self->unlockForArbitration();
2138
2139    return( ok );
2140}
2141
2142bool IOService::handleOpen(     IOService *     forClient,
2143                                IOOptionBits    options,
2144                                void *          arg )
2145{
2146    bool        ok;
2147
2148    ok = (0 == __owner);
2149    if( ok )
2150        __owner = forClient;
2151
2152    else if( options & kIOServiceSeize ) {
2153        ok = (kIOReturnSuccess == messageClient( kIOMessageServiceIsRequestingClose,
2154                                __owner, (void *) options ));
2155        if( ok && (0 == __owner ))
2156            __owner = forClient;
2157        else
2158            ok = false;
2159    }
2160    return( ok );
2161}
2162
2163void IOService::handleClose(    IOService *     forClient,
2164                                IOOptionBits    options )
2165{
2166    if( __owner == forClient)
2167        __owner = 0;
2168}
2169
2170bool IOService::handleIsOpen(   const IOService * forClient ) const
2171{
2172    if( forClient)
2173        return( __owner == forClient );
2174    else
2175        return( __owner != forClient );
2176}
2177
2178/*
2179 * Probing & starting
2180 */
2181static SInt32 IONotifyOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref )
2182{
2183    const _IOServiceNotifier * obj1 = (const _IOServiceNotifier *) inObj1;
2184    const _IOServiceNotifier * obj2 = (const _IOServiceNotifier *) inObj2;
2185    SInt32             val1;
2186    SInt32             val2;
2187
2188    val1 = 0;
2189    val2 = 0;
2190
2191    if ( obj1 )
2192        val1 = obj1->priority;
2193
2194    if ( obj2 )
2195        val2 = obj2->priority;
2196
2197    return ( val1 - val2 );
2198}
2199
2200static SInt32 IOServiceObjectOrder( const OSObject * entry, void * ref)
2201{
2202    OSDictionary *      dict;
2203    IOService *         service;
2204    _IOServiceNotifier * notify;
2205    OSSymbol *          key = (OSSymbol *) ref;
2206    OSNumber *          offset;
2207
2208    if( (notify = OSDynamicCast( _IOServiceNotifier, entry)))
2209        return( notify->priority );
2210
2211    else if( (service = OSDynamicCast( IOService, entry)))
2212        offset = OSDynamicCast(OSNumber, service->getProperty( key ));
2213    else if( (dict = OSDynamicCast( OSDictionary, entry)))
2214        offset = OSDynamicCast(OSNumber, dict->getObject( key ));
2215    else {
2216        assert( false );
2217        offset = 0;
2218    }
2219
2220    if( offset)
2221        return( (SInt32) offset->unsigned32BitValue());
2222    else
2223        return( kIODefaultProbeScore );
2224}
2225
2226SInt32 IOServiceOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref )
2227{
2228    const OSObject *    obj1 = (const OSObject *) inObj1;
2229    const OSObject *    obj2 = (const OSObject *) inObj2;
2230    SInt32               val1;
2231    SInt32               val2;
2232
2233    val1 = 0;
2234    val2 = 0;
2235
2236    if ( obj1 )
2237        val1 = IOServiceObjectOrder( obj1, ref );
2238
2239    if ( obj2 )
2240        val2 = IOServiceObjectOrder( obj2, ref );
2241
2242    return ( val1 - val2 );
2243}
2244
2245IOService * IOService::getClientWithCategory( const OSSymbol * category )
2246{
2247    IOService *         service = 0;
2248    OSIterator *        iter;
2249    const OSSymbol *    nextCat;
2250
2251    iter = getClientIterator();
2252    if( iter) {
2253        while( (service = (IOService *) iter->getNextObject())) {
2254            if( kIOServiceInactiveState & service->__state[0])
2255                continue;
2256            nextCat = (const OSSymbol *) OSDynamicCast( OSSymbol,
2257                        service->getProperty( gIOMatchCategoryKey ));
2258            if( category == nextCat)
2259                break;
2260        }
2261        iter->release();
2262    }
2263    return( service );
2264}
2265
2266bool IOService::invokeNotifer( _IOServiceNotifier * notify )
2267{
2268    _IOServiceNotifierInvocation invocation;
2269    bool                         willNotify;
2270    bool                         ret = true;
2271
2272    invocation.thread = current_thread();
2273
2274    LOCKWRITENOTIFY();
2275    willNotify = (0 != (kIOServiceNotifyEnable & notify->state));
2276
2277    if( willNotify) {
2278        queue_enter( &notify->handlerInvocations, &invocation,
2279                        _IOServiceNotifierInvocation *, link );
2280    }
2281    UNLOCKNOTIFY();
2282
2283    if( willNotify) {
2284
2285        ret = (*notify->handler)( notify->target, notify->ref, this );
2286
2287        LOCKWRITENOTIFY();
2288        queue_remove( &notify->handlerInvocations, &invocation,
2289                        _IOServiceNotifierInvocation *, link );
2290        if( kIOServiceNotifyWaiter & notify->state) {
2291            notify->state &= ~kIOServiceNotifyWaiter;
2292            WAKEUPNOTIFY( notify );
2293        }
2294        UNLOCKNOTIFY();
2295    }
2296
2297    return( ret );
2298}
2299
2300/*
2301 * Alloc and probe matching classes,
2302 * called on the provider instance
2303 */
2304
2305void IOService::probeCandidates( OSOrderedSet * matches )
2306{
2307    OSDictionary        *       match = 0;
2308    OSSymbol            *       symbol;
2309    IOService           *       inst;
2310    IOService           *       newInst;
2311    OSDictionary        *       props;
2312    SInt32                      score;
2313    OSNumber            *       newPri;
2314    OSOrderedSet        *       familyMatches = 0;
2315    OSOrderedSet        *       startList;
2316    OSDictionary        *       startDict = 0;
2317    const OSSymbol      *       category;
2318    OSIterator          *       iter;
2319    _IOServiceNotifier  *               notify;
2320    OSObject            *       nextMatch = 0;
2321    bool                        started;
2322    bool                        needReloc = false;
2323#if IOMATCHDEBUG
2324    SInt64                      debugFlags;
2325#endif
2326
2327    assert( matches );
2328    while( !needReloc && (nextMatch = matches->getFirstObject())) {
2329
2330        nextMatch->retain();
2331        matches->removeObject(nextMatch);
2332        
2333        if( (notify = OSDynamicCast( _IOServiceNotifier, nextMatch ))) {
2334
2335            lockForArbitration();
2336            if( 0 == (__state[0] & kIOServiceInactiveState))
2337                invokeNotifer( notify );
2338            unlockForArbitration();
2339            nextMatch->release();
2340            nextMatch = 0;
2341            continue;
2342
2343        } else if( !(match = OSDynamicCast( OSDictionary, nextMatch ))) {
2344            nextMatch->release();
2345            nextMatch = 0;
2346            continue;
2347        }
2348
2349        props = 0;
2350#if IOMATCHDEBUG
2351        debugFlags = getDebugFlags( match );
2352#endif
2353
2354        do {
2355            category = OSDynamicCast( OSSymbol,
2356                        match->getObject( gIOMatchCategoryKey ));
2357            if( 0 == category)
2358                category = gIODefaultMatchCategoryKey;
2359
2360            if( getClientWithCategory( category )) {
2361#if IOMATCHDEBUG
2362                if( debugFlags & kIOLogMatch)
2363                    LOG("%s: match category %s exists\n", getName(),
2364                                category->getCStringNoCopy());
2365#endif
2366                nextMatch->release();
2367                nextMatch = 0;
2368                continue;
2369            }
2370
2371            // create a copy now in case its modified during matching
2372            props = OSDictionary::withDictionary( match, match->getCount());
2373            if( 0 == props)
2374                continue;
2375            props->setCapacityIncrement(1);             
2376
2377            // check the nub matches
2378            if( false == passiveMatch( props, true ))
2379                continue;
2380
2381            // Check to see if driver reloc has been loaded.
2382            needReloc = (false == gIOCatalogue->isModuleLoaded( match ));
2383            if( needReloc) {
2384#if IOMATCHDEBUG
2385                if( debugFlags & kIOLogCatalogue)
2386                    LOG("%s: stalling for module\n", getName());
2387#endif
2388                // If reloc hasn't been loaded, exit;
2389                // reprobing will occur after reloc has been loaded.
2390                continue;
2391            }
2392
2393            // reorder on family matchPropertyTable score.
2394            if( 0 == familyMatches)
2395                familyMatches = OSOrderedSet::withCapacity( 1,
2396                        IOServiceOrdering, (void *) gIOProbeScoreKey );
2397            if( familyMatches)
2398                familyMatches->setObject( props );
2399
2400        } while( false );
2401
2402        if (nextMatch) {
2403            nextMatch->release();
2404            nextMatch = 0;
2405        }
2406        if( props)
2407            props->release();
2408    }
2409    matches->release();
2410    matches = 0;
2411
2412    if( familyMatches) {
2413
2414        while( !needReloc
2415             && (props = (OSDictionary *) familyMatches->getFirstObject())) {
2416
2417            props->retain();
2418            familyMatches->removeObject( props );
2419    
2420            inst = 0;
2421            newInst = 0;
2422#if IOMATCHDEBUG
2423            debugFlags = getDebugFlags( props );
2424#endif
2425            do {
2426                symbol = OSDynamicCast( OSSymbol,
2427                                props->getObject( gIOClassKey));
2428                if( !symbol)
2429                    continue;
2430    
2431                // alloc the driver instance
2432                inst = (IOService *) OSMetaClass::allocClassWithName( symbol);
2433    
2434                if( !inst) {
2435                    IOLog("Couldn't alloc class \"%s\"\n",
2436                        symbol->getCStringNoCopy());
2437                    continue;
2438                }
2439    
2440                // init driver instance
2441                if( !(inst->init( props ))) {
2442#if IOMATCHDEBUG
2443                    if( debugFlags & kIOLogStart)
2444                        IOLog("%s::init fails\n", symbol->getCStringNoCopy());
2445#endif
2446                    continue;
2447                }
2448                if( __state[1] & kIOServiceSynchronousState)
2449                    inst->__state[1] |= kIOServiceSynchronousState;
2450    
2451                // give the driver the default match category if not specified
2452                category = OSDynamicCast( OSSymbol,
2453                            props->getObject( gIOMatchCategoryKey ));
2454                if( 0 == category)
2455                    category = gIODefaultMatchCategoryKey;
2456                inst->setProperty( gIOMatchCategoryKey, (OSObject *) category );
2457    
2458                // attach driver instance
2459                if( !(inst->attach( this )))
2460                        continue;
2461    
2462                // pass in score from property table
2463                score = familyMatches->orderObject( props );
2464    
2465                // & probe the new driver instance
2466#if IOMATCHDEBUG
2467                if( debugFlags & kIOLogProbe)
2468                    LOG("%s::probe(%s)\n",
2469                        inst->getMetaClass()->getClassName(), getName());
2470#endif
2471    
2472                newInst = inst->probe( this, &score );
2473                inst->detach( this );
2474                if( 0 == newInst) {
2475#if IOMATCHDEBUG
2476                    if( debugFlags & kIOLogProbe)
2477                        IOLog("%s::probe fails\n", symbol->getCStringNoCopy());
2478#endif
2479                    continue;
2480                }
2481    
2482                // save the score
2483                newPri = OSNumber::withNumber( score, 32 );
2484                if( newPri) {
2485                    newInst->setProperty( gIOProbeScoreKey, newPri );
2486                    newPri->release();
2487                }
2488    
2489                // add to start list for the match category
2490                if( 0 == startDict)
2491                    startDict = OSDictionary::withCapacity( 1 );
2492                assert( startDict );
2493                startList = (OSOrderedSet *)
2494                                startDict->getObject( category );
2495                if( 0 == startList) {
2496                    startList = OSOrderedSet::withCapacity( 1,
2497                            IOServiceOrdering, (void *) gIOProbeScoreKey );
2498                    if( startDict && startList) {
2499                        startDict->setObject( category, startList );
2500                        startList->release();
2501                    }
2502                }
2503                assert( startList );
2504                if( startList)
2505                    startList->setObject( newInst );
2506    
2507            } while( false );
2508
2509            props->release();
2510            if( inst)
2511                inst->release();
2512        }
2513        familyMatches->release();
2514        familyMatches = 0;
2515    }
2516
2517    // start the best (until success) of each category
2518
2519    iter = OSCollectionIterator::withCollection( startDict );
2520    if( iter) {
2521        while( (category = (const OSSymbol *) iter->getNextObject())) {
2522
2523            startList = (OSOrderedSet *) startDict->getObject( category );
2524            assert( startList );
2525            if( !startList)
2526                continue;
2527
2528            started = false;
2529            while( true // (!started)
2530                   && (inst = (IOService *)startList->getFirstObject())) {
2531
2532                inst->retain();
2533                startList->removeObject(inst);
2534
2535#if IOMATCHDEBUG
2536                debugFlags = getDebugFlags( inst->getPropertyTable() );
2537
2538                if( debugFlags & kIOLogStart) {
2539                    if( started)
2540                        LOG( "match category exists, skipping " );
2541                    LOG( "%s::start(%s) <%d>\n", inst->getName(),
2542                         getName(), inst->getRetainCount());
2543                }
2544#endif
2545                if( false == started)
2546                    started = startCandidate( inst );
2547#if IOMATCHDEBUG
2548                if( (debugFlags & kIOLogStart) && (false == started))
2549                    LOG( "%s::start(%s) <%d> failed\n", inst->getName(), getName(),
2550                         inst->getRetainCount());
2551#endif
2552                inst->release();
2553            }
2554        }
2555        iter->release();
2556    }
2557
2558
2559    // adjust the busy count by -1 if matching is stalled for a module,
2560    // or +1 if a previously stalled matching is complete.
2561    lockForArbitration();
2562    SInt32 adjBusy = 0;
2563    if( needReloc) {
2564        adjBusy = (__state[1] & kIOServiceModuleStallState) ? 0 : 1;
2565        if( adjBusy)
2566            __state[1] |= kIOServiceModuleStallState;
2567
2568    } else if( __state[1] & kIOServiceModuleStallState) {
2569        __state[1] &= ~kIOServiceModuleStallState;
2570        adjBusy = -1;
2571    }
2572    if( adjBusy)
2573        _adjustBusy( adjBusy );
2574    unlockForArbitration();
2575
2576    if( startDict)
2577        startDict->release();
2578}
2579
2580/*
2581 * Start a previously attached & probed instance,
2582 * called on exporting object instance
2583 */
2584
2585bool IOService::startCandidate( IOService * service )
2586{
2587    bool                ok;
2588
2589    ok = service->attach( this );
2590
2591    if( ok)
2592    {
2593        if (this != gIOResources)
2594        {
2595            // stall for any nub resources
2596            checkResources();
2597            // stall for any driver resources
2598            service->checkResources();
2599        }
2600        
2601        AbsoluteTime startTime;
2602        AbsoluteTime endTime;
2603        UInt64       nano;
2604
2605        if (kIOLogStart & gIOKitDebug)
2606            clock_get_uptime(&startTime);
2607
2608        ok = service->start(this);
2609
2610        if (kIOLogStart & gIOKitDebug)
2611        {
2612            clock_get_uptime(&endTime);
2613    
2614            if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
2615            {
2616                SUB_ABSOLUTETIME(&endTime, &startTime);
2617                absolutetime_to_nanoseconds(endTime, &nano);
2618                if (nano > 500000000ULL)
2619                    IOLog("%s::start took %ld ms\n", service->getName(), (UInt32)(nano / 1000000ULL));
2620            }
2621        }
2622        if( !ok)
2623            service->detach( this );
2624    }
2625    return( ok );
2626}
2627
2628IOService * IOService::resources( void )
2629{
2630    return( gIOResources );
2631}
2632
2633void IOService::publishResource( const char * key, OSObject * value )
2634{
2635    const OSSymbol *    sym;
2636
2637    if( (sym = OSSymbol::withCString( key))) {
2638        publishResource( sym, value);
2639        sym->release();
2640    }
2641}
2642
2643void IOService::publishResource( const OSSymbol * key, OSObject * value )
2644{
2645    if( 0 == value)
2646        value = (OSObject *) gIOServiceKey;
2647
2648    gIOResources->setProperty( key, value);
2649
2650    if( IORecursiveLockHaveLock( gNotificationLock))
2651        return;
2652
2653    gIOResourceGenerationCount++;
2654    gIOResources->registerService();
2655}
2656
2657bool IOService::addNeededResource( const char * key )
2658{
2659    OSObject *  resourcesProp;
2660    OSSet *     set;
2661    OSString *  newKey;
2662    bool ret;
2663
2664    resourcesProp = getProperty( gIOResourceMatchKey );
2665
2666    newKey = OSString::withCString( key );
2667    if( (0 == resourcesProp) || (0 == newKey))
2668        return( false);
2669
2670    set = OSDynamicCast( OSSet, resourcesProp );
2671    if( !set) {
2672        set = OSSet::withCapacity( 1 );
2673        if( set)
2674            set->setObject( resourcesProp );
2675    }
2676    else
2677        set->retain();
2678
2679    set->setObject( newKey );
2680    newKey->release();
2681    ret = setProperty( gIOResourceMatchKey, set );
2682    set->release();
2683
2684    return( ret );
2685}
2686
2687bool IOService::checkResource( OSObject * matching )
2688{
2689    OSString *          str;
2690    OSDictionary *      table;
2691
2692    if( (str = OSDynamicCast( OSString, matching ))) {
2693        if( gIOResources->getProperty( str ))
2694            return( true );
2695    }
2696
2697    if( str)
2698        table = resourceMatching( str );
2699    else if( (table = OSDynamicCast( OSDictionary, matching )))
2700        table->retain();
2701    else {
2702        IOLog("%s: Can't match using: %s\n", getName(),
2703                matching->getMetaClass()->getClassName());
2704        /* false would stall forever */
2705        return( true );
2706    }
2707
2708    if( gIOKitDebug & kIOLogConfig)
2709        LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName());
2710
2711    waitForService( table );
2712
2713    if( gIOKitDebug & kIOLogConfig)
2714        LOG("config(%x): waking\n", (int) IOThreadSelf() );
2715
2716    return( true );
2717}
2718
2719bool IOService::checkResources( void )
2720{
2721    OSObject *          resourcesProp;
2722    OSSet *             set;
2723    OSIterator *        iter;
2724    bool                ok;
2725
2726    resourcesProp = getProperty( gIOResourceMatchKey );
2727    if( 0 == resourcesProp)
2728        return( true );
2729
2730    if( (set = OSDynamicCast( OSSet, resourcesProp ))) {
2731
2732        iter = OSCollectionIterator::withCollection( set );
2733        ok = (0 != iter);
2734        while( ok && (resourcesProp = iter->getNextObject()) )
2735            ok = checkResource( resourcesProp );
2736        if( iter)
2737            iter->release();
2738
2739    } else
2740        ok = checkResource( resourcesProp );
2741
2742    return( ok );
2743}
2744
2745
2746void _IOConfigThread::configThread( void )
2747{
2748    _IOConfigThread *   inst;
2749
2750    do {
2751        if( !(inst = new _IOConfigThread))
2752            continue;
2753        if( !inst->init())
2754            continue;
2755        if( !(IOCreateThread((IOThreadFunc) &_IOConfigThread::main, inst )))
2756            continue;
2757
2758        return;
2759
2760    } while( false);
2761
2762    if( inst)
2763        inst->release();
2764
2765    return;
2766}
2767
2768void _IOConfigThread::free( void )
2769{
2770    OSObject::free();
2771}
2772
2773void IOService::doServiceMatch( IOOptionBits options )
2774{
2775    _IOServiceNotifier * notify;
2776    OSIterator *        iter;
2777    OSOrderedSet *      matches;
2778    SInt32              catalogGeneration;
2779    bool                keepGuessing = true;
2780    bool                reRegistered = true;
2781
2782//    job->nub->deliverNotification( gIOPublishNotification,
2783//                              kIOServiceRegisteredState, 0xffffffff );
2784
2785    while( keepGuessing ) {
2786
2787        matches = gIOCatalogue->findDrivers( this, &catalogGeneration );
2788        // the matches list should always be created by findDrivers()
2789        if( matches) {
2790
2791            lockForArbitration();
2792            if( 0 == (__state[0] & kIOServiceFirstPublishState))
2793                deliverNotification( gIOFirstPublishNotification,
2794                                     kIOServiceFirstPublishState, 0xffffffff );
2795            LOCKREADNOTIFY();
2796            __state[1] &= ~kIOServiceNeedConfigState;
2797            __state[1] |= kIOServiceConfigState;
2798            __state[0] |= kIOServiceRegisteredState;
2799
2800            if( reRegistered && (0 == (__state[0] & kIOServiceInactiveState))) {
2801
2802                iter = OSCollectionIterator::withCollection( (OSOrderedSet *)
2803                        gNotifications->getObject( gIOPublishNotification ) );
2804                if( iter) {
2805                    while((notify = (_IOServiceNotifier *)
2806                           iter->getNextObject())) {
2807
2808                        if( passiveMatch( notify->matching )
2809                         && (kIOServiceNotifyEnable & notify->state))
2810                            matches->setObject( notify );
2811                    }
2812                    iter->release();
2813                }
2814            }
2815
2816            UNLOCKNOTIFY();
2817            unlockForArbitration();
2818
2819            if( matches->getCount() && (kIOReturnSuccess == getResources()))
2820                probeCandidates( matches );
2821            else
2822                matches->release();
2823        }
2824
2825        lockForArbitration();
2826        reRegistered = (0 != (__state[1] & kIOServiceNeedConfigState));
2827        keepGuessing =
2828                   (reRegistered || (catalogGeneration !=
2829                                        gIOCatalogue->getGenerationCount()))
2830                && (0 == (__state[0] & kIOServiceInactiveState));
2831
2832        if( keepGuessing)
2833            unlockForArbitration();
2834    }
2835
2836    if( (0 == (__state[0] & kIOServiceInactiveState))
2837     && (0 == (__state[1] & kIOServiceModuleStallState)) ) {
2838        deliverNotification( gIOMatchedNotification,
2839                kIOServiceMatchedState, 0xffffffff );
2840        if( 0 == (__state[0] & kIOServiceFirstMatchState))
2841            deliverNotification( gIOFirstMatchNotification,
2842                kIOServiceFirstMatchState, 0xffffffff );
2843    }
2844
2845    __state[1] &= ~kIOServiceConfigState;
2846    if( __state[0] & kIOServiceInactiveState)
2847        scheduleTerminatePhase2();
2848
2849    _adjustBusy( -1 );
2850    unlockForArbitration();
2851}
2852
2853UInt32 IOService::_adjustBusy( SInt32 delta )
2854{
2855    IOService * next;
2856    UInt32      count;
2857    UInt32      result;
2858    bool        wasQuiet, nowQuiet, needWake;
2859
2860    next = this;
2861    result = __state[1] & kIOServiceBusyStateMask;
2862
2863    if( delta) do {
2864        if( next != this)
2865            next->lockForArbitration();
2866        count = next->__state[1] & kIOServiceBusyStateMask;
2867        assert( count < kIOServiceBusyMax);
2868        wasQuiet = (0 == count);
2869        assert( (!wasQuiet) || (delta > 0));
2870        next->__state[1] += delta;
2871        nowQuiet = (0 == (next->__state[1] & kIOServiceBusyStateMask));
2872        needWake = (0 != (kIOServiceBusyWaiterState & next->__state[1]));
2873
2874        if( needWake) {
2875            next->__state[1] &= ~kIOServiceBusyWaiterState;
2876            IOLockLock( gIOServiceBusyLock );
2877            thread_wakeup( (event_t) next);
2878            IOLockUnlock( gIOServiceBusyLock );
2879        }
2880        if( next != this)
2881            next->unlockForArbitration();
2882
2883        if( (wasQuiet || nowQuiet) ) {
2884            OSArray *           array;
2885            unsigned int        index;
2886            OSObject *          interested;
2887
2888            array = OSDynamicCast( OSArray, next->getProperty( gIOBusyInterest ));
2889            if( array) {
2890                LOCKREADNOTIFY();
2891                for( index = 0;
2892                     (interested = array->getObject( index ));
2893                     index++) {
2894                    next->messageClient(kIOMessageServiceBusyStateChange,
2895                                     interested, (void *) wasQuiet /* busy now */);
2896                }
2897                UNLOCKNOTIFY();
2898            }
2899
2900            if( nowQuiet && (next == gIOServiceRoot))
2901                OSMetaClass::considerUnloads();
2902        }
2903
2904        delta = nowQuiet ? -1 : +1;
2905
2906    } while( (wasQuiet || nowQuiet) && (next = next->getProvider()));
2907
2908    return( result );
2909}
2910
2911void IOService::adjustBusy( SInt32 delta )
2912{
2913    lockForArbitration();
2914    _adjustBusy( delta );
2915    unlockForArbitration();
2916}
2917
2918UInt32 IOService::getBusyState( void )
2919{
2920    return( __state[1] & kIOServiceBusyStateMask );
2921}
2922
2923IOReturn IOService::waitForState( UInt32 mask, UInt32 value,
2924                                 mach_timespec_t * timeout )
2925{
2926    bool            wait;
2927    int             waitResult = THREAD_AWAKENED;
2928    bool            computeDeadline = true;
2929    AbsoluteTime    abstime;
2930
2931    do {
2932        lockForArbitration();
2933        IOLockLock( gIOServiceBusyLock );
2934        wait = (value != (__state[1] & mask));
2935        if( wait) {
2936            __state[1] |= kIOServiceBusyWaiterState;
2937            unlockForArbitration();
2938            if( timeout ) {
2939                if( computeDeadline ) {
2940                    AbsoluteTime  nsinterval;
2941                    clock_interval_to_absolutetime_interval(
2942                          timeout->tv_sec, kSecondScale, &abstime );
2943                    clock_interval_to_absolutetime_interval(
2944                          timeout->tv_nsec, kNanosecondScale, &nsinterval );
2945                    ADD_ABSOLUTETIME( &abstime, &nsinterval );
2946                    clock_absolutetime_interval_to_deadline(
2947                          abstime, &abstime );
2948                    computeDeadline = false;
2949                }
2950
2951                                assert_wait_deadline((event_t)this, THREAD_UNINT, __OSAbsoluteTime(abstime));
2952            }
2953                        else
2954                                assert_wait((event_t)this, THREAD_UNINT );
2955        } else
2956            unlockForArbitration();
2957        IOLockUnlock( gIOServiceBusyLock );
2958        if( wait)
2959            waitResult = thread_block(THREAD_CONTINUE_NULL);
2960
2961    } while( wait && (waitResult != THREAD_TIMED_OUT));
2962
2963    if( waitResult == THREAD_TIMED_OUT)
2964        return( kIOReturnTimeout );
2965    else
2966        return( kIOReturnSuccess );
2967}
2968
2969IOReturn IOService::waitQuiet( mach_timespec_t * timeout )
2970{
2971    return( waitForState( kIOServiceBusyStateMask, 0, timeout ));
2972}
2973
2974bool IOService::serializeProperties( OSSerialize * s ) const
2975{
2976#if 0
2977    ((IOService *)this)->setProperty( ((IOService *)this)->__state,
2978                sizeof( __state), "__state");
2979#endif
2980    return( super::serializeProperties(s) );
2981}
2982
2983
2984void _IOConfigThread::main( _IOConfigThread * self )
2985{
2986    _IOServiceJob *     job;
2987    IOService   *       nub;
2988    bool                alive = true;
2989
2990    do {
2991
2992//      randomDelay();
2993
2994        semaphore_wait( gJobsSemaphore );
2995
2996        IOTakeLock( gJobsLock );
2997        job = (_IOServiceJob *) gJobs->getFirstObject();
2998        job->retain();
2999        gJobs->removeObject(job);
3000        if( job) {
3001            gOutstandingJobs--;
3002//          gNumConfigThreads--;        // we're out of service
3003            gNumWaitingThreads--;       // we're out of service
3004        }
3005        IOUnlock( gJobsLock );
3006
3007        if( job) {
3008
3009          nub = job->nub;
3010
3011          if( gIOKitDebug & kIOLogConfig)
3012            LOG("config(%x): starting on %s, %d\n",
3013                        (int) IOThreadSelf(), job->nub->getName(), job->type);
3014
3015          switch( job->type) {
3016
3017            case kMatchNubJob:
3018                nub->doServiceMatch( job->options );
3019                break;
3020
3021            default:
3022                LOG("config(%x): strange type (%d)\n",
3023                        (int) IOThreadSelf(), job->type );
3024                break;
3025            }
3026
3027            nub->release();
3028            job->release();
3029
3030            IOTakeLock( gJobsLock );
3031            alive = (gOutstandingJobs > gNumWaitingThreads);
3032            if( alive)
3033                gNumWaitingThreads++;   // back in service
3034//              gNumConfigThreads++;
3035            else {
3036                if( 0 == --gNumConfigThreads) {
3037//                    IOLog("MATCH IDLE\n");
3038                    IOLockWakeup( gJobsLock, (event_t) &gNumConfigThreads, /* one-thread */ false );
3039                }
3040            }
3041            IOUnlock( gJobsLock );
3042        }
3043
3044    } while( alive );
3045
3046    if( gIOKitDebug & kIOLogConfig)
3047        LOG("config(%x): terminating\n", (int) IOThreadSelf() );
3048
3049    self->release();
3050}
3051
3052IOReturn IOService::waitMatchIdle( UInt32 msToWait )
3053{
3054    bool            wait;
3055    int             waitResult = THREAD_AWAKENED;
3056    bool            computeDeadline = true;
3057    AbsoluteTime    abstime;
3058
3059    IOLockLock( gJobsLock );
3060    do {
3061        wait = (0 != gNumConfigThreads);
3062        if( wait) {
3063            if( msToWait) {
3064                if( computeDeadline ) {
3065                    clock_interval_to_absolutetime_interval(
3066                          msToWait, kMillisecondScale, &abstime );
3067                    clock_absolutetime_interval_to_deadline(
3068                          abstime, &abstime );
3069                    computeDeadline = false;
3070                }
3071                          waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads,
3072                                                                abstime, THREAD_UNINT );
3073                   } else {
3074                          waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads,
3075                                                                THREAD_UNINT );
3076                }
3077        }
3078    } while( wait && (waitResult != THREAD_TIMED_OUT));
3079        IOLockUnlock( gJobsLock );
3080
3081    if( waitResult == THREAD_TIMED_OUT)
3082        return( kIOReturnTimeout );
3083    else
3084        return( kIOReturnSuccess );
3085}
3086
3087void _IOServiceJob::pingConfig( _IOServiceJob * job )
3088{
3089    int         count;
3090    bool        create;
3091
3092    assert( job );
3093
3094    IOTakeLock( gJobsLock );
3095
3096    gOutstandingJobs++;
3097    gJobs->setLastObject( job );
3098
3099    count = gNumWaitingThreads;
3100//    if( gNumConfigThreads) count++;// assume we're called from a config thread
3101
3102    create = (  (gOutstandingJobs > count)
3103                && (gNumConfigThreads < kMaxConfigThreads) );
3104    if( create) {
3105        gNumConfigThreads++;
3106        gNumWaitingThreads++;
3107    }
3108
3109    IOUnlock( gJobsLock );
3110
3111    job->release();
3112
3113    if( create) {
3114        if( gIOKitDebug & kIOLogConfig)
3115            LOG("config(%d): creating\n", gNumConfigThreads - 1);
3116        _IOConfigThread::configThread();
3117    }
3118
3119    semaphore_signal( gJobsSemaphore );
3120}
3121
3122// internal - call with gNotificationLock
3123OSObject * IOService::getExistingServices( OSDictionary * matching,
3124                 IOOptionBits inState, IOOptionBits options )
3125{
3126    OSObject *          current = 0;
3127    OSIterator *        iter;
3128    IOService *         service;
3129    OSObject *          obj;
3130
3131    if( !matching)
3132        return( 0 );
3133
3134    if(true 
3135      && (obj = matching->getObject(gIOProviderClassKey))
3136      && gIOResourcesKey
3137      && gIOResourcesKey->isEqualTo(obj)
3138      && (service = gIOResources))
3139    {
3140        if( (inState == (service->__state[0] & inState))
3141          && (0 == (service->__state[0] & kIOServiceInactiveState))
3142          &&  service->passiveMatch( matching ))
3143        {
3144            if( options & kIONotifyOnce)
3145                current = service;
3146            else
3147                current = OSSet::withObjects(
3148                                (const OSObject **) &service, 1, 1 );
3149        }
3150    }
3151    else
3152    {
3153        iter = IORegistryIterator::iterateOver( gIOServicePlane,
3154                                            kIORegistryIterateRecursively );
3155        if( iter) {
3156            do {
3157                iter->reset();
3158                while( (service = (IOService *) iter->getNextObject())) {
3159                    if( (inState == (service->__state[0] & inState))
3160                    && (0 == (service->__state[0] & kIOServiceInactiveState))
3161                    &&  service->passiveMatch( matching )) {
3162    
3163                        if( options & kIONotifyOnce) {
3164                            current = service;
3165                            break;
3166                        }
3167                        if( current)
3168                            ((OSSet *)current)->setObject( service );
3169                        else
3170                            current = OSSet::withObjects(
3171                                            (const OSObject **) &service, 1, 1 );
3172                    }
3173                }
3174            } while( !service && !iter->isValid());
3175            iter->release();
3176        }
3177    }
3178
3179    if( current && (0 == (options & (kIONotifyOnce | kIOServiceExistingSet)))) {
3180        iter = OSCollectionIterator::withCollection( (OSSet *)current );
3181        current->release();
3182        current = iter;
3183    }
3184
3185    return( current );
3186}
3187
3188// public version
3189OSIterator * IOService::getMatchingServices( OSDictionary * matching )
3190{
3191    OSIterator *        iter;
3192
3193    // is a lock even needed?
3194    LOCKWRITENOTIFY();
3195
3196    iter = (OSIterator *) getExistingServices( matching,
3197                                                kIOServiceMatchedState );
3198    
3199    UNLOCKNOTIFY();
3200
3201    return( iter );
3202}
3203
3204
3205// internal - call with gNotificationLock
3206IONotifier * IOService::setNotification(
3207            const OSSymbol * type, OSDictionary * matching,
3208            IOServiceNotificationHandler handler, void * target, void * ref,
3209            SInt32 priority )
3210{
3211    _IOServiceNotifier * notify = 0;
3212    OSOrderedSet *      set;
3213
3214    if( !matching)
3215        return( 0 );
3216
3217    notify = new _IOServiceNotifier;
3218    if( notify && !notify->init()) {
3219        notify->release();
3220        notify = 0;
3221    }
3222
3223    if( notify) {
3224        notify->matching = matching;
3225        notify->handler = handler;
3226        notify->target = target;
3227        notify->ref = ref;
3228        notify->priority = priority;
3229        notify->state = kIOServiceNotifyEnable;
3230        queue_init( &notify->handlerInvocations );
3231
3232        ////// queue
3233
3234        if( 0 == (set = (OSOrderedSet *) gNotifications->getObject( type ))) {
3235            set = OSOrderedSet::withCapacity( 1,
3236                        IONotifyOrdering, 0 );
3237            if( set) {
3238                gNotifications->setObject( type, set );
3239                set->release();
3240            }
3241        }
3242        notify->whence = set;
3243        if( set)
3244            set->setObject( notify );
3245    }
3246
3247    return( notify );
3248}
3249
3250// internal - call with gNotificationLock
3251IONotifier * IOService::doInstallNotification(
3252                        const OSSymbol * type, OSDictionary * matching,
3253                        IOServiceNotificationHandler handler,
3254                        void * target, void * ref,
3255                        SInt32 priority, OSIterator ** existing )
3256{
3257    OSIterator *        exist;
3258    IONotifier *        notify;
3259    IOOptionBits        inState;
3260
3261    if( !matching)
3262        return( 0 );
3263
3264    if( type == gIOPublishNotification)
3265        inState = kIOServiceRegisteredState;
3266
3267    else if( type == gIOFirstPublishNotification)
3268        inState = kIOServiceFirstPublishState;
3269
3270    else if( (type == gIOMatchedNotification)
3271          || (type == gIOFirstMatchNotification))
3272        inState = kIOServiceMatchedState;
3273    else if( type == gIOTerminatedNotification)
3274        inState = 0;
3275    else
3276        return( 0 );
3277
3278    notify = setNotification( type, matching, handler, target, ref, priority );
3279    
3280    if( inState)
3281        // get the current set
3282        exist = (OSIterator *) getExistingServices( matching, inState );
3283    else
3284        exist = 0;
3285
3286    *existing = exist;    
3287
3288    return( notify );
3289}
3290
3291
3292IONotifier * IOService::installNotification(
3293                        const OSSymbol * type, OSDictionary * matching,
3294                        IOServiceNotificationHandler handler,
3295                        void * target, void * ref,
3296                        SInt32 priority, OSIterator ** existing )
3297{
3298    IONotifier *        notify;
3299
3300    LOCKWRITENOTIFY();
3301
3302    notify = doInstallNotification( type, matching, handler, target, ref,
3303                priority, existing );
3304
3305    UNLOCKNOTIFY();
3306
3307    return( notify );
3308}
3309
3310IONotifier * IOService::addNotification(
3311                        const OSSymbol * type, OSDictionary * matching,
3312                        IOServiceNotificationHandler handler,
3313                        void * target, void * ref,
3314                        SInt32 priority )
3315{
3316    OSIterator *                existing;
3317    _IOServiceNotifier *        notify;
3318    IOService *                 next;
3319
3320    notify = (_IOServiceNotifier *) installNotification( type, matching,
3321                handler, target, ref, priority, &existing );
3322
3323    // send notifications for existing set
3324    if( existing) {
3325
3326        notify->retain();               // in case handler remove()s
3327        while( (next = (IOService *) existing->getNextObject())) {
3328
3329            next->lockForArbitration();
3330            if( 0 == (next->__state[0] & kIOServiceInactiveState))
3331                next->invokeNotifer( notify );
3332            next->unlockForArbitration();
3333        }
3334        notify->release();
3335        existing->release();
3336    }
3337
3338    return( notify );
3339}
3340
3341struct SyncNotifyVars {
3342    semaphore_port_t    waitHere;
3343    IOService *         result;
3344};
3345
3346bool IOService::syncNotificationHandler(
3347                        void * /* target */, void * ref,
3348                        IOService * newService )
3349{
3350
3351    // result may get written more than once before the
3352    // notification is removed!
3353    ((SyncNotifyVars *) ref)->result = newService;
3354    semaphore_signal( ((SyncNotifyVars *) ref)->waitHere );
3355
3356    return( false );
3357}
3358
3359IOService * IOService::waitForService( OSDictionary * matching,
3360                                mach_timespec_t * timeout )
3361{
3362    IONotifier *        notify = 0;
3363    // priority doesn't help us much since we need a thread wakeup
3364    SInt32              priority = 0;
3365    SyncNotifyVars      state;
3366    kern_return_t       err = kIOReturnBadArgument;
3367
3368    if( !matching)
3369        return( 0 );
3370
3371    state.waitHere = 0;
3372    state.result = 0;
3373
3374    LOCKWRITENOTIFY();
3375
3376    do {
3377
3378        state.result = (IOService *) getExistingServices( matching,
3379                            kIOServiceMatchedState, kIONotifyOnce );
3380        if( state.result)
3381            continue;
3382
3383        err = semaphore_create( kernel_task, &state.waitHere,
3384                                    SYNC_POLICY_FIFO, 0 );
3385        if( KERN_SUCCESS != err)
3386            continue;
3387
3388        notify = IOService::setNotification( gIOMatchedNotification, matching,
3389                    &IOService::syncNotificationHandler, (void *) 0,
3390                    (void *) &state, priority );
3391
3392    } while( false );
3393
3394    UNLOCKNOTIFY();
3395
3396     if( notify) {
3397        if( timeout)
3398            err = semaphore_timedwait( state.waitHere, *timeout );
3399        else
3400            err = semaphore_wait( state.waitHere );
3401    }
3402
3403    if( notify)
3404        notify->remove();       // dequeues
3405    else
3406        matching->release();
3407    if( state.waitHere)
3408        semaphore_destroy( kernel_task, state.waitHere );
3409
3410    return( state.result );
3411}
3412
3413void IOService::deliverNotification( const OSSymbol * type,
3414                            IOOptionBits orNewState, IOOptionBits andNewState )
3415{
3416    _IOServiceNotifier * notify;
3417    OSIterator *         iter;
3418    OSArray *            willSend = 0;
3419
3420    lockForArbitration();
3421
3422    if( (0 == (__state[0] & kIOServiceInactiveState))
3423     || (type == gIOTerminatedNotification)) {
3424
3425        LOCKREADNOTIFY();
3426
3427        iter = OSCollectionIterator::withCollection( (OSOrderedSet *)
3428                    gNotifications->getObject( type ) );
3429
3430        if( iter) {
3431            while( (notify = (_IOServiceNotifier *) iter->getNextObject())) {
3432
3433                if( passiveMatch( notify->matching)
3434                  && (kIOServiceNotifyEnable & notify->state)) {
3435                    if( 0 == willSend)
3436                        willSend = OSArray::withCapacity(8);
3437                    if( willSend)
3438                        willSend->setObject( notify );
3439                }
3440            }
3441            iter->release();
3442        }
3443
3444        __state[0] = (__state[0] | orNewState) & andNewState;
3445
3446        UNLOCKNOTIFY();
3447    }
3448
3449    if( willSend) {
3450        for( unsigned int idx = 0;
3451             (notify = (_IOServiceNotifier *) willSend->getObject(idx));
3452             idx++) {
3453            invokeNotifer( notify );
3454        }
3455        willSend->release();
3456    }
3457    unlockForArbitration();
3458}
3459
3460IOOptionBits IOService::getState( void ) const
3461{
3462    return( __state[0] );
3463}
3464
3465/*
3466 * Helpers to make matching objects for simple cases
3467 */
3468
3469OSDictionary * IOService::serviceMatching( const OSString * name,
3470                        OSDictionary * table )
3471{
3472    if( !table)
3473        table = OSDictionary::withCapacity( 2 );
3474    if( table)
3475        table->setObject(gIOProviderClassKey, (OSObject *)name );
3476
3477    return( table );
3478}
3479
3480OSDictionary * IOService::serviceMatching( const char * name,
3481                        OSDictionary * table )
3482{
3483    const OSString *    str;
3484
3485    str = OSSymbol::withCString( name );
3486    if( !str)
3487        return( 0 );
3488
3489    table = serviceMatching( str, table );
3490    str->release();
3491    return( table );
3492}
3493
3494OSDictionary * IOService::nameMatching( const OSString * name,
3495                        OSDictionary * table )
3496{
3497    if( !table)
3498        table = OSDictionary::withCapacity( 2 );
3499    if( table)
3500        table->setObject( gIONameMatchKey, (OSObject *)name );
3501
3502    return( table );
3503}
3504
3505OSDictionary * IOService::nameMatching( const char * name,
3506                        OSDictionary * table )
3507{
3508    const OSString *    str;
3509
3510    str = OSSymbol::withCString( name );
3511    if( !str)
3512        return( 0 );
3513
3514    table = nameMatching( str, table );
3515    str->release();
3516    return( table );
3517}
3518
3519OSDictionary * IOService::resourceMatching( const OSString * str,
3520                        OSDictionary * table )
3521{
3522    table = serviceMatching( gIOResourcesKey, table );
3523    if( table)
3524        table->setObject( gIOResourceMatchKey, (OSObject *) str );
3525
3526    return( table );
3527}
3528
3529OSDictionary * IOService::resourceMatching( const char * name,
3530                        OSDictionary * table )
3531{
3532    const OSSymbol *    str;
3533
3534    str = OSSymbol::withCString( name );
3535    if( !str)
3536        return( 0 );
3537
3538    table = resourceMatching( str, table );
3539    str->release();
3540
3541    return( table );
3542}
3543
3544/*
3545 * _IOServiceNotifier
3546 */
3547
3548// wait for all threads, other than the current one,
3549//  to exit the handler
3550
3551void _IOServiceNotifier::wait()
3552{
3553    _IOServiceNotifierInvocation * next;
3554    bool doWait;
3555
3556    do {
3557        doWait = false;
3558        queue_iterate( &handlerInvocations, next,
3559                        _IOServiceNotifierInvocation *, link) {
3560            if( next->thread != current_thread() ) {
3561                doWait = true;
3562                break;
3563            }
3564        }
3565        if( doWait) {
3566            state |= kIOServiceNotifyWaiter;
3567            SLEEPNOTIFY(this);
3568        }
3569
3570    } while( doWait );
3571}
3572
3573void _IOServiceNotifier::free()
3574{
3575    assert( queue_empty( &handlerInvocations ));
3576    OSObject::free();
3577}
3578
3579void _IOServiceNotifier::remove()
3580{
3581    LOCKWRITENOTIFY();
3582
3583    if( whence) {
3584        whence->removeObject( (OSObject *) this );
3585        whence = 0;
3586    }
3587    if( matching) {
3588        matching->release();
3589        matching = 0;
3590    }
3591
3592    state &= ~kIOServiceNotifyEnable;
3593
3594    wait();
3595
3596    UNLOCKNOTIFY();
3597    
3598    release();
3599}
3600
3601bool _IOServiceNotifier::disable()
3602{
3603    bool        ret;
3604
3605    LOCKWRITENOTIFY();
3606
3607    ret = (0 != (kIOServiceNotifyEnable & state));
3608    state &= ~kIOServiceNotifyEnable;
3609    if( ret)
3610        wait();
3611
3612    UNLOCKNOTIFY();
3613
3614    return( ret );
3615}
3616
3617void _IOServiceNotifier::enable( bool was )
3618{
3619    LOCKWRITENOTIFY();
3620    if( was)
3621        state |= kIOServiceNotifyEnable;
3622    else
3623        state &= ~kIOServiceNotifyEnable;
3624    UNLOCKNOTIFY();
3625}
3626
3627/*
3628 * IOResources
3629 */
3630
3631IOService * IOResources::resources( void )
3632{
3633    IOResources *       inst;
3634
3635    inst = new IOResources;
3636    if( inst && !inst->init()) {
3637        inst->release();
3638        inst = 0;
3639    }
3640
3641    return( inst );
3642}
3643
3644IOWorkLoop * IOResources::getWorkLoop() const
3645{
3646    // If we are the resource root then bringe over to the
3647    // platform to get its workloop
3648    if (this == (IOResources *) gIOResources)
3649        return getPlatform()->getWorkLoop();
3650    else
3651        return IOService::getWorkLoop();
3652}
3653
3654bool IOResources::matchPropertyTable( OSDictionary * table )
3655{
3656    OSObject *          prop;
3657    OSString *          str;
3658    OSSet *             set;
3659    OSIterator *        iter;
3660    bool                ok = false;
3661
3662    prop = table->getObject( gIOResourceMatchKey );
3663    str = OSDynamicCast( OSString, prop );
3664    if( str)
3665        ok = (0 != getProperty( str ));
3666
3667    else if( (set = OSDynamicCast( OSSet, prop))) {
3668
3669        iter = OSCollectionIterator::withCollection( set );
3670        ok = (iter != 0);
3671        while( ok && (str = OSDynamicCast( OSString, iter->getNextObject()) ))
3672            ok = (0 != getProperty( str ));
3673
3674        if( iter)
3675            iter->release();
3676    }
3677
3678    return( ok );
3679}
3680
3681IOReturn IOResources::setProperties( OSObject * properties )
3682{
3683    IOReturn                    err;
3684    const OSSymbol *            key;
3685    OSDictionary *              dict;
3686    OSCollectionIterator *      iter;
3687
3688    err = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
3689    if ( kIOReturnSuccess != err)
3690        return( err );
3691
3692    dict = OSDynamicCast(OSDictionary, properties);
3693    if( 0 == dict)
3694        return( kIOReturnBadArgument);
3695
3696    iter = OSCollectionIterator::withCollection( dict);
3697    if( 0 == iter)
3698        return( kIOReturnBadArgument);
3699
3700    while( (key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
3701
3702        if (gIOConsoleUsersKey == key)
3703        {
3704            IORegistryEntry::getRegistryRoot()->setProperty(key, dict->getObject(key));
3705            OSIncrementAtomic( &gIOConsoleUsersSeed );
3706            publishResource( gIOConsoleUsersSeedKey, gIOConsoleUsersSeedValue );
3707            continue;
3708        }
3709
3710        publishResource( key, dict->getObject(key) );
3711    }
3712
3713    iter->release();
3714
3715    return( kIOReturnSuccess );
3716}
3717
3718/*
3719 * Helpers for matching dictionaries.
3720 * Keys existing in matching are checked in properties.
3721 * Keys may be a string or OSCollection of IOStrings
3722 */
3723
3724bool IOService::compareProperty( OSDictionary * matching,
3725                                 const char *   key )
3726{
3727    OSObject *  value;
3728    bool        ok;
3729
3730    value = matching->getObject( key );
3731    if( value)
3732        ok = value->isEqualTo( getProperty( key ));
3733    else
3734        ok = true;
3735
3736    return( ok );
3737}
3738
3739
3740bool IOService::compareProperty( OSDictionary *   matching,
3741                                 const OSString * key )
3742{
3743    OSObject *  value;
3744    bool        ok;
3745
3746    value = matching->getObject( key );
3747    if( value)
3748        ok = value->isEqualTo( getProperty( key ));
3749    else
3750        ok = true;
3751
3752    return( ok );
3753}
3754
3755bool IOService::compareProperties( OSDictionary * matching,
3756                                   OSCollection * keys )
3757{
3758    OSCollectionIterator *      iter;
3759    const OSString *            key;
3760    bool                        ok = true;
3761
3762    if( !matching || !keys)
3763        return( false );
3764
3765    iter = OSCollectionIterator::withCollection( keys );
3766
3767    if( iter) {
3768        while( ok && (key = OSDynamicCast( OSString, iter->getNextObject())))
3769            ok = compareProperty( matching, key );
3770
3771        iter->release();
3772    }
3773    keys->release();    // !! consume a ref !!
3774
3775    return( ok );
3776}
3777
3778/* Helper to add a location matching dict to the table */
3779
3780OSDictionary * IOService::addLocation( OSDictionary * table )
3781{
3782    OSDictionary *      dict;
3783
3784    if( !table)
3785        return( 0 );
3786
3787    dict = OSDictionary::withCapacity( 1 );
3788    if( dict) {
3789        table->setObject( gIOLocationMatchKey, dict );
3790        dict->release(); 
3791    }
3792
3793    return( dict );
3794}
3795
3796/*
3797 * Go looking for a provider to match a location dict.
3798 */
3799
3800IOService * IOService::matchLocation( IOService * /* client */ )
3801{
3802    IOService * parent;
3803
3804    parent = getProvider();
3805
3806    if( parent)
3807        parent = parent->matchLocation( this );
3808
3809    return( parent );
3810}
3811
3812bool IOService::passiveMatch( OSDictionary * table, bool changesOK )
3813{
3814    IOService *         where;
3815    OSString *          matched;
3816    OSObject *          obj;
3817    OSString *          str;
3818    IORegistryEntry *   entry;
3819    OSNumber *          num;
3820    SInt32              score;
3821    OSNumber *          newPri;
3822    bool                match = true;
3823    bool                matchParent = false;
3824    UInt32              done;
3825
3826    assert( table );
3827
3828    where = this;
3829
3830    do {
3831        do {
3832            done = 0;
3833
3834            str = OSDynamicCast( OSString, table->getObject( gIOProviderClassKey));
3835            if( str) {
3836                done++;
3837                match = (0 != where->metaCast( str ));
3838                if( !match)
3839                    break;
3840            }
3841
3842            obj = table->getObject( gIONameMatchKey );
3843            if( obj) {
3844                done++;
3845                match = where->compareNames( obj, changesOK ? &matched : 0 );
3846                if( !match)
3847                    break;
3848                if( changesOK && matched) {
3849                    // leave a hint as to which name matched
3850                    table->setObject( gIONameMatchedKey, matched );
3851                    matched->release();
3852                }
3853            }
3854
3855            str = OSDynamicCast( OSString, table->getObject( gIOLocationMatchKey ));
3856            if( str) {
3857
3858                const OSSymbol * sym;
3859
3860                done++;
3861                match = false;
3862                sym = where->copyLocation();
3863                if( sym) {
3864                    match = sym->isEqualTo( str );
3865                    sym->release();
3866                }
3867                if( !match)
3868                    break;
3869            }
3870
3871            obj = table->getObject( gIOPropertyMatchKey );
3872            if( obj) {
3873
3874                OSDictionary * dict;
3875                OSDictionary * nextDict;
3876                OSIterator *   iter;
3877
3878                done++;
3879                match = false;
3880                dict = where->dictionaryWithProperties();
3881                if( dict) {
3882                    nextDict = OSDynamicCast( OSDictionary, obj);
3883                    if( nextDict)
3884                        iter = 0;
3885                    else
3886                        iter = OSCollectionIterator::withCollection(
3887                                    OSDynamicCast(OSCollection, obj));
3888
3889                    while( nextDict
3890                        || (iter && (0 != (nextDict = OSDynamicCast(OSDictionary,
3891                                                iter->getNextObject()))))) {
3892                        match = dict->isEqualTo( nextDict, nextDict);
3893                        if( match)
3894                            break;
3895                        nextDict = 0;
3896                    }
3897                    dict->release();
3898                    if( iter)
3899                        iter->release();
3900                }
3901                if( !match)
3902                    break;
3903            }
3904
3905            str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey ));
3906            if( str) {
3907                done++;
3908                entry = IORegistryEntry::fromPath( str->getCStringNoCopy() );
3909                match = (where == entry);
3910                if( entry)
3911                    entry->release();
3912                if( !match)
3913                    break;
3914            }
3915
3916            num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey ));
3917            if( num) {
3918
3919                OSIterator *    iter;
3920                IOService *             service = 0;
3921                UInt32          serviceCount = 0;
3922
3923                done++;
3924                iter = where->getClientIterator();
3925                if( iter) {
3926                    while( (service = (IOService *) iter->getNextObject())) {
3927                        if( kIOServiceInactiveState & service->__state[0])
3928                            continue;
3929                        if( 0 == service->getProperty( gIOMatchCategoryKey ))
3930                            continue;
3931                        ++serviceCount;
3932                    }
3933                    iter->release();
3934                }
3935                match = (serviceCount == num->unsigned32BitValue());
3936                if( !match)
3937                    break;
3938            }
3939
3940            if( done == table->getCount()) {
3941                // don't call family if we've done all the entries in the table
3942                matchParent = false;
3943                break;
3944            }
3945
3946            // pass in score from property table
3947            score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey);
3948
3949            // do family specific matching
3950            match = where->matchPropertyTable( table, &score );
3951
3952            if( !match) {
3953#if IOMATCHDEBUG
3954                if( kIOLogMatch & getDebugFlags( table ))
3955                    LOG("%s: family specific matching fails\n", where->getName());
3956#endif
3957                break;
3958            }
3959
3960            if( changesOK) {
3961                // save the score
3962                newPri = OSNumber::withNumber( score, 32 );
3963                if( newPri) {
3964                    table->setObject( gIOProbeScoreKey, newPri );
3965                    newPri->release();
3966                }
3967            }
3968
3969            if( !(match = where->compareProperty( table, kIOBSDNameKey )))
3970                break;
3971
3972            matchParent = false;
3973
3974            obj = OSDynamicCast( OSDictionary,
3975                  table->getObject( gIOParentMatchKey ));
3976            if( obj) {
3977                match = false;
3978                matchParent = true;
3979                table = (OSDictionary *) obj;
3980                break;
3981            }
3982
3983            table = OSDynamicCast( OSDictionary,
3984                    table->getObject( gIOLocationMatchKey ));
3985            if( table) {
3986                match = false;
3987                where = where->getProvider();
3988                if( where)
3989                    where = where->matchLocation( where );
3990            }
3991
3992        } while( table && where );
3993
3994    } while( matchParent && (where = where->getProvider()) );
3995
3996    if( kIOLogMatch & gIOKitDebug)
3997        if( where != this)
3998            LOG("match parent @ %s = %d\n",
3999                        where->getName(), match );
4000
4001    return( match );
4002}
4003
4004
4005IOReturn IOService::newUserClient( task_t owningTask, void * securityID,
4006                                    UInt32 type,  OSDictionary * properties,
4007                                    IOUserClient ** handler )
4008{
4009    const OSSymbol *userClientClass = 0;
4010    IOUserClient *client;
4011    OSObject *temp;
4012
4013    // First try my own properties for a user client class name
4014    temp = getProperty(gIOUserClientClassKey);
4015    if (temp) {
4016        if (OSDynamicCast(OSSymbol, temp))
4017            userClientClass = (const OSSymbol *) temp;
4018        else if (OSDynamicCast(OSString, temp)) {
4019            userClientClass = OSSymbol::withString((OSString *) temp);
4020            if (userClientClass)
4021                setProperty(kIOUserClientClassKey,
4022                            (OSObject *) userClientClass);
4023        }
4024    }
4025
4026    // Didn't find one so lets just bomb out now without further ado.
4027    if (!userClientClass)
4028        return kIOReturnUnsupported;
4029
4030    temp = OSMetaClass::allocClassWithName(userClientClass);
4031    if (!temp)
4032        return kIOReturnNoMemory;
4033
4034    if (OSDynamicCast(IOUserClient, temp))
4035        client = (IOUserClient *) temp;
4036    else {
4037        temp->release();
4038        return kIOReturnUnsupported;
4039    }
4040
4041    if ( !client->initWithTask(owningTask, securityID, type, properties) ) {
4042        client->release();
4043        return kIOReturnBadArgument;
4044    }
4045
4046    if ( !client->attach(this) ) {
4047        client->release();
4048        return kIOReturnUnsupported;
4049    }
4050
4051    if ( !client->start(this) ) {
4052        client->detach(this);
4053        client->release();
4054        return kIOReturnUnsupported;
4055    }
4056
4057    *handler = client;
4058    return kIOReturnSuccess;
4059}
4060
4061IOReturn IOService::newUserClient( task_t owningTask, void * securityID,
4062                                    UInt32 type, IOUserClient ** handler )
4063{
4064    return( newUserClient( owningTask, securityID, type, 0, handler ));
4065}
4066
4067IOReturn IOService::requestProbe( IOOptionBits options )
4068{
4069    return( kIOReturnUnsupported);
4070}
4071
4072/*
4073 * Convert an IOReturn to text. Subclasses which add additional
4074 * IOReturn's should override this method and call 
4075 * super::stringFromReturn if the desired value is not found.
4076 */
4077
4078const char * IOService::stringFromReturn( IOReturn rtn )
4079{
4080    static const IONamedValue IOReturn_values[] = { 
4081        {kIOReturnSuccess,          "success"                           },
4082        {kIOReturnError,            "general error"                     },
4083        {kIOReturnNoMemory,         "memory allocation error"           },
4084        {kIOReturnNoResources,      "resource shortage"                 },
4085        {kIOReturnIPCError,         "Mach IPC failure"                  },
4086        {kIOReturnNoDevice,         "no such device"                    },
4087        {kIOReturnNotPrivileged,    "privilege violation"               },
4088        {kIOReturnBadArgument,      "invalid argument"                  },
4089        {kIOReturnLockedRead,       "device is read locked"             },
4090        {kIOReturnLockedWrite,      "device is write locked"            },
4091        {kIOReturnExclusiveAccess,  "device is exclusive access"        },
4092        {kIOReturnBadMessageID,     "bad IPC message ID"                },
4093        {kIOReturnUnsupported,      "unsupported function"              },
4094        {kIOReturnVMError,          "virtual memory error"              },
4095        {kIOReturnInternalError,    "internal driver error"             },
4096        {kIOReturnIOError,          "I/O error"                         },
4097        {kIOReturnCannotLock,       "cannot acquire lock"               },
4098        {kIOReturnNotOpen,          "device is not open"                },
4099        {kIOReturnNotReadable,      "device is not readable"            },
4100        {kIOReturnNotWritable,      "device is not writeable"           },
4101        {kIOReturnNotAligned,       "alignment error"                   },
4102        {kIOReturnBadMedia,         "media error"                       },
4103        {kIOReturnStillOpen,        "device is still open"              },
4104        {kIOReturnRLDError,         "rld failure"                       },
4105        {kIOReturnDMAError,         "DMA failure"                       },
4106        {kIOReturnBusy,             "device is busy"                    },
4107        {kIOReturnTimeout,          "I/O timeout"                       },
4108        {kIOReturnOffline,          "device is offline"                 },
4109        {kIOReturnNotReady,         "device is not ready"               },
4110        {kIOReturnNotAttached,      "device/channel is not attached"    },
4111        {kIOReturnNoChannels,       "no DMA channels available"         },
4112        {kIOReturnNoSpace,          "no space for data"                 },
4113        {kIOReturnPortExists,       "device port already exists"        },
4114        {kIOReturnCannotWire,       "cannot wire physical memory"       },
4115        {kIOReturnNoInterrupt,      "no interrupt attached"             },
4116        {kIOReturnNoFrames,         "no DMA frames enqueued"            },
4117        {kIOReturnMessageTooLarge,  "message is too large"              },
4118        {kIOReturnNotPermitted,     "operation is not permitted"        },
4119        {kIOReturnNoPower,          "device is without power"           },
4120        {kIOReturnNoMedia,          "media is not present"              },
4121        {kIOReturnUnformattedMedia, "media is not formatted"            },
4122        {kIOReturnUnsupportedMode,  "unsupported mode"                  },
4123        {kIOReturnUnderrun,         "data underrun"                     },
4124        {kIOReturnOverrun,          "data overrun"                      },
4125        {kIOReturnDeviceError,      "device error"                      },
4126        {kIOReturnNoCompletion,     "no completion routine"             },
4127        {kIOReturnAborted,          "operation was aborted"             },
4128        {kIOReturnNoBandwidth,      "bus bandwidth would be exceeded"   },
4129        {kIOReturnNotResponding,    "device is not responding"          },
4130        {kIOReturnInvalid,          "unanticipated driver error"        },
4131        {0,                         NULL                                }
4132    };
4133
4134    return IOFindNameForValue(rtn, IOReturn_values);
4135}
4136
4137/*
4138 * Convert an IOReturn to an errno.
4139 */
4140int IOService::errnoFromReturn( IOReturn rtn )
4141{
4142    switch(rtn) {
4143        // (obvious match)
4144        case kIOReturnSuccess:
4145            return(0);
4146        case kIOReturnNoMemory:
4147            return(ENOMEM);
4148        case kIOReturnNoDevice:
4149            return(ENXIO);
4150        case kIOReturnVMError:
4151            return(EFAULT);
4152        case kIOReturnNotPermitted:
4153            return(EPERM);
4154        case kIOReturnNotPrivileged:
4155            return(EACCES);
4156        case kIOReturnIOError:
4157            return(EIO);
4158        case kIOReturnNotWritable:
4159            return(EROFS);
4160        case kIOReturnBadArgument:
4161            return(EINVAL);
4162        case kIOReturnUnsupported:
4163            return(ENOTSUP);
4164        case kIOReturnBusy:
4165            return(EBUSY);
4166        case kIOReturnNoPower:
4167            return(EPWROFF);
4168        case kIOReturnDeviceError:
4169            return(EDEVERR);
4170        case kIOReturnTimeout: 
4171            return(ETIMEDOUT);
4172        case kIOReturnMessageTooLarge:
4173            return(EMSGSIZE);
4174        case kIOReturnNoSpace:
4175            return(ENOSPC);
4176        case kIOReturnCannotLock:
4177            return(ENOLCK);
4178
4179        // (best match)
4180        case kIOReturnBadMessageID:
4181        case kIOReturnNoCompletion:
4182        case kIOReturnNotAligned:
4183            return(EINVAL);
4184        case kIOReturnNotReady:
4185            return(EBUSY);
4186        case kIOReturnRLDError:
4187            return(EBADMACHO);
4188        case kIOReturnPortExists:
4189        case kIOReturnStillOpen:
4190            return(EEXIST);
4191        case kIOReturnExclusiveAccess:
4192        case kIOReturnLockedRead:
4193        case kIOReturnLockedWrite:
4194        case kIOReturnNotAttached:
4195        case kIOReturnNotOpen:
4196        case kIOReturnNotReadable:
4197            return(EACCES);
4198        case kIOReturnCannotWire:
4199        case kIOReturnNoResources:
4200            return(ENOMEM);
4201        case kIOReturnAborted:
4202        case kIOReturnOffline:
4203        case kIOReturnNotResponding:
4204            return(EBUSY);
4205        case kIOReturnBadMedia:
4206        case kIOReturnNoMedia:
4207        case kIOReturnUnformattedMedia:
4208            return(ENXIO); // (media error)
4209        case kIOReturnDMAError:
4210        case kIOReturnOverrun:
4211        case kIOReturnUnderrun:
4212            return(EIO); // (transfer error)
4213        case kIOReturnNoBandwidth:
4214        case kIOReturnNoChannels:
4215        case kIOReturnNoFrames:
4216        case kIOReturnNoInterrupt:
4217            return(EIO); // (hardware error)
4218        case kIOReturnError:
4219        case kIOReturnInternalError:
4220        case kIOReturnInvalid:
4221            return(EIO); // (generic error)
4222        case kIOReturnIPCError:
4223            return(EIO); // (ipc error)
4224        default:
4225            return(EIO); // (all other errors)
4226    }
4227}
4228
4229IOReturn IOService::message( UInt32 type, IOService * provider,
4230                                void * argument )
4231{
4232    /*
4233     * Generic entry point for calls from the provider.  A return value of
4234     * kIOReturnSuccess indicates that the message was received, and where
4235     * applicable, that it was successful.
4236     */
4237
4238    return kIOReturnUnsupported;
4239}
4240
4241/*
4242 * Device memory
4243 */
4244
4245IOItemCount IOService::getDeviceMemoryCount( void )
4246{
4247    OSArray *           array;
4248    IOItemCount         count;
4249
4250    array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
4251    if( array)
4252        count = array->getCount();
4253    else
4254        count = 0;
4255
4256    return( count);
4257}
4258
4259IODeviceMemory * IOService::getDeviceMemoryWithIndex( unsigned int index )
4260{
4261    OSArray *           array;
4262    IODeviceMemory *    range;
4263
4264    array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
4265    if( array)
4266        range = (IODeviceMemory *) array->getObject( index );
4267    else
4268        range = 0;
4269
4270    return( range);
4271}
4272
4273IOMemoryMap * IOService::mapDeviceMemoryWithIndex( unsigned int index,
4274                                                IOOptionBits options )
4275{
4276    IODeviceMemory *    range;
4277    IOMemoryMap *       map;
4278
4279    range = getDeviceMemoryWithIndex( index );
4280    if( range)
4281        map = range->map( options );
4282    else
4283        map = 0;
4284
4285    return( map );
4286}
4287
4288OSArray * IOService::getDeviceMemory( void )
4289{
4290    return( OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)));
4291}
4292
4293
4294void IOService::setDeviceMemory( OSArray * array )
4295{
4296    setProperty( gIODeviceMemoryKey, array);
4297}
4298
4299/*
4300 * Device interrupts
4301 */
4302
4303IOReturn IOService::resolveInterrupt(IOService *nub, int source)
4304{
4305  IOInterruptController *interruptController;
4306  OSArray               *array;
4307  OSData                *data;
4308  OSSymbol              *interruptControllerName;
4309  long                  numSources;
4310  IOInterruptSource     *interruptSources;
4311  
4312  // Get the parents list from the nub.
4313  array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptControllersKey));
4314  if (array == 0) return kIOReturnNoResources;
4315  
4316  // Allocate space for the IOInterruptSources if needed... then return early.
4317  if (nub->_interruptSources == 0) {
4318    numSources = array->getCount();
4319    interruptSources = (IOInterruptSource *)IOMalloc(numSources * sizeof(IOInterruptSource));
4320    if (interruptSources == 0) return kIOReturnNoMemory;
4321    
4322    bzero(interruptSources, numSources * sizeof(IOInterruptSource));
4323    
4324    nub->_numInterruptSources = numSources;
4325    nub->_interruptSources = interruptSources;
4326    return kIOReturnSuccess;
4327  }
4328  
4329  interruptControllerName = OSDynamicCast(OSSymbol,array->getObject(source));
4330  if (interruptControllerName == 0) return kIOReturnNoResources;
4331  
4332  interruptController = getPlatform()->lookUpInterruptController(interruptControllerName);
4333  if (interruptController == 0) return kIOReturnNoResources;
4334  
4335  // Get the interrupt numbers from the nub.
4336  array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptSpecifiersKey));
4337  if (array == 0) return kIOReturnNoResources;
4338  data = OSDynamicCast(OSData, array->getObject(source));
4339  if (data == 0) return kIOReturnNoResources;
4340  
4341  // Set the interruptController and interruptSource in the nub's table.
4342  interruptSources = nub->_interruptSources;
4343  interruptSources[source].interruptController = interruptController;
4344  interruptSources[source].vectorData = data;
4345  
4346  return kIOReturnSuccess;
4347}
4348
4349IOReturn IOService::lookupInterrupt(int source, bool resolve, IOInterruptController **interruptController)
4350{
4351  IOReturn ret;
4352  
4353  /* Make sure the _interruptSources are set */
4354  if (_interruptSources == 0) {
4355    ret = resolveInterrupt(this, source);
4356    if (ret != kIOReturnSuccess) return ret;
4357  }
4358  
4359  /* Make sure the local source number is valid */
4360  if ((source < 0) || (source >= _numInterruptSources))
4361    return kIOReturnNoInterrupt;
4362  
4363  /* Look up the contoller for the local source */
4364  *interruptController = _interruptSources[source].interruptController;
4365  
4366  if (*interruptController == NULL) {
4367    if (!resolve) return kIOReturnNoInterrupt;
4368    
4369    /* Try to reslove the interrupt */
4370    ret = resolveInterrupt(this, source);
4371    if (ret != kIOReturnSuccess) return ret;    
4372    
4373    *interruptController = _interruptSources[source].interruptController;
4374  }
4375  
4376  return kIOReturnSuccess;
4377}
4378
4379IOReturn IOService::registerInterrupt(int source, OSObject *target,
4380                                      IOInterruptAction handler,
4381                                      void *refCon)
4382{
4383  IOInterruptController *interruptController;
4384  IOReturn              ret;
4385  
4386  ret = lookupInterrupt(source, true, &interruptController);
4387  if (ret != kIOReturnSuccess) return ret;
4388  
4389  /* Register the source */
4390  return interruptController->registerInterrupt(this, source, target,
4391                                                (IOInterruptHandler)handler,
4392                                                refCon);
4393}
4394
4395IOReturn IOService::unregisterInterrupt(int source)
4396{
4397  IOInterruptController *interruptController;
4398  IOReturn              ret;
4399  
4400  ret = lookupInterrupt(source, false, &interruptController);
4401  if (ret != kIOReturnSuccess) return ret;
4402  
4403  /* Unregister the source */
4404  return interruptController->unregisterInterrupt(this, source);
4405}
4406
4407IOReturn IOService::getInterruptType(int source, int *interruptType)
4408{
4409  IOInterruptController *interruptController;
4410  IOReturn              ret;
4411  
4412  ret = lookupInterrupt(source, true, &interruptController);
4413  if (ret != kIOReturnSuccess) return ret;
4414    
4415  /* Return the type */
4416  return interruptController->getInterruptType(this, source, interruptType);
4417}
4418
4419IOReturn IOService::enableInterrupt(int source)
4420{
4421  IOInterruptController *interruptController;
4422  IOReturn              ret;
4423  
4424  ret = lookupInterrupt(source, false, &interruptController);
4425  if (ret != kIOReturnSuccess) return ret;
4426  
4427  /* Enable the source */
4428  return interruptController->enableInterrupt(this, source);
4429}
4430
4431IOReturn IOService::disableInterrupt(int source)
4432{
4433  IOInterruptController *interruptController;
4434  IOReturn              ret;
4435  
4436  ret = lookupInterrupt(source, false, &interruptController);
4437  if (ret != kIOReturnSuccess) return ret;
4438  
4439  /* Disable the source */
4440  return interruptController->disableInterrupt(this, source);
4441}
4442
4443IOReturn IOService::causeInterrupt(int source)
4444{
4445  IOInterruptController *interruptController;
4446  IOReturn              ret;
4447  
4448  ret = lookupInterrupt(source, false, &interruptController);
4449  if (ret != kIOReturnSuccess) return ret;
4450  
4451  /* Cause an interrupt for the source */
4452  return interruptController->causeInterrupt(this, source);
4453}
4454
4455OSMetaClassDefineReservedUsed(IOService, 0);
4456OSMetaClassDefineReservedUsed(IOService, 1);
4457OSMetaClassDefineReservedUsed(IOService, 2);
4458OSMetaClassDefineReservedUsed(IOService, 3);
4459
4460OSMetaClassDefineReservedUnused(IOService, 4);
4461OSMetaClassDefineReservedUnused(IOService, 5);
4462OSMetaClassDefineReservedUnused(IOService, 6);
4463OSMetaClassDefineReservedUnused(IOService, 7);
4464OSMetaClassDefineReservedUnused(IOService, 8);
4465OSMetaClassDefineReservedUnused(IOService, 9);
4466OSMetaClassDefineReservedUnused(IOService, 10);
4467OSMetaClassDefineReservedUnused(IOService, 11);
4468OSMetaClassDefineReservedUnused(IOService, 12);
4469OSMetaClassDefineReservedUnused(IOService, 13);
4470OSMetaClassDefineReservedUnused(IOService, 14);
4471OSMetaClassDefineReservedUnused(IOService, 15);
4472OSMetaClassDefineReservedUnused(IOService, 16);
4473OSMetaClassDefineReservedUnused(IOService, 17);
4474OSMetaClassDefineReservedUnused(IOService, 18);
4475OSMetaClassDefineReservedUnused(IOService, 19);
4476OSMetaClassDefineReservedUnused(IOService, 20);
4477OSMetaClassDefineReservedUnused(IOService, 21);
4478OSMetaClassDefineReservedUnused(IOService, 22);
4479OSMetaClassDefineReservedUnused(IOService, 23);
4480OSMetaClassDefineReservedUnused(IOService, 24);
4481OSMetaClassDefineReservedUnused(IOService, 25);
4482OSMetaClassDefineReservedUnused(IOService, 26);
4483OSMetaClassDefineReservedUnused(IOService, 27);
4484OSMetaClassDefineReservedUnused(IOService, 28);
4485OSMetaClassDefineReservedUnused(IOService, 29);
4486OSMetaClassDefineReservedUnused(IOService, 30);
4487OSMetaClassDefineReservedUnused(IOService, 31);
4488OSMetaClassDefineReservedUnused(IOService, 32);
4489OSMetaClassDefineReservedUnused(IOService, 33);
4490OSMetaClassDefineReservedUnused(IOService, 34);
4491OSMetaClassDefineReservedUnused(IOService, 35);
4492OSMetaClassDefineReservedUnused(IOService, 36);
4493OSMetaClassDefineReservedUnused(IOService, 37);
4494OSMetaClassDefineReservedUnused(IOService, 38);
4495OSMetaClassDefineReservedUnused(IOService, 39);
4496OSMetaClassDefineReservedUnused(IOService, 40);
4497OSMetaClassDefineReservedUnused(IOService, 41);
4498OSMetaClassDefineReservedUnused(IOService, 42);
4499OSMetaClassDefineReservedUnused(IOService, 43);
4500OSMetaClassDefineReservedUnused(IOService, 44);
4501OSMetaClassDefineReservedUnused(IOService, 45);
4502OSMetaClassDefineReservedUnused(IOService, 46);
4503OSMetaClassDefineReservedUnused(IOService, 47);
4504OSMetaClassDefineReservedUnused(IOService, 48);
4505OSMetaClassDefineReservedUnused(IOService, 49);
4506OSMetaClassDefineReservedUnused(IOService, 50);
4507OSMetaClassDefineReservedUnused(IOService, 51);
4508OSMetaClassDefineReservedUnused(IOService, 52);
4509OSMetaClassDefineReservedUnused(IOService, 53);
4510OSMetaClassDefineReservedUnused(IOService, 54);
4511OSMetaClassDefineReservedUnused(IOService, 55);
4512OSMetaClassDefineReservedUnused(IOService, 56);
4513OSMetaClassDefineReservedUnused(IOService, 57);
4514OSMetaClassDefineReservedUnused(IOService, 58);
4515OSMetaClassDefineReservedUnused(IOService, 59);
4516OSMetaClassDefineReservedUnused(IOService, 60);
4517OSMetaClassDefineReservedUnused(IOService, 61);
4518OSMetaClassDefineReservedUnused(IOService, 62);
4519OSMetaClassDefineReservedUnused(IOService, 63);
4520
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.