X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/fa4905b191e0d16b0fffd53bd565eca71d01fae0..0c530ab8987f0ae6a1a3d9284f40182b88852816:/iokit/Kernel/IOService.cpp diff --git a/iokit/Kernel/IOService.cpp b/iokit/Kernel/IOService.cpp index 4bd1a2afa..f5f4f57e0 100644 --- a/iokit/Kernel/IOService.cpp +++ b/iokit/Kernel/IOService.cpp @@ -19,17 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - * Copyright (c) 1991-1999 Apple Computer, Inc. All rights reserved. - * - * HISTORY - * - * 29-Jan-91 Portions from IODevice.m, Doug Mitchell at NeXT, Created. - * 18-Jun-98 start IOKit objc - * 10-Nov-98 start iokit cpp - * 25-Feb-99 sdouglas, add threads and locks to ensure deadlock - * - */ #include @@ -37,13 +26,14 @@ #include #include #include +#include #include #include #include #include #include #include -#include +#include #include #include #include @@ -95,6 +85,7 @@ const OSSymbol * gIONameMatchKey; const OSSymbol * gIONameMatchedKey; const OSSymbol * gIOPropertyMatchKey; const OSSymbol * gIOLocationMatchKey; +const OSSymbol * gIOParentMatchKey; const OSSymbol * gIOPathMatchKey; const OSSymbol * gIOMatchCategoryKey; const OSSymbol * gIODefaultMatchCategoryKey; @@ -105,6 +96,12 @@ const OSSymbol * gIOKitDebugKey; const OSSymbol * gIOCommandPoolSizeKey; +const OSSymbol * gIOConsoleUsersKey; +const OSSymbol * gIOConsoleSessionUIDKey; +const OSSymbol * gIOConsoleUsersSeedKey; +const OSSymbol * gIOConsoleSessionOnConsoleKey; +const OSSymbol * gIOConsoleSessionSecureInputPIDKey; + static int gIOResourceGenerationCount; const OSSymbol * gIOServiceKey; @@ -140,6 +137,9 @@ static OSArray * gIOStopList; static OSArray * gIOStopProviderList; static OSArray * gIOFinalizeList; +static SInt32 gIOConsoleUsersSeed; +static OSData * gIOConsoleUsersSeedValue; + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define LOCKREADNOTIFY() \ @@ -149,6 +149,10 @@ static OSArray * gIOFinalizeList; #define LOCKWRITE2READNOTIFY() #define UNLOCKNOTIFY() \ IORecursiveLockUnlock( gNotificationLock ) +#define SLEEPNOTIFY(event) \ + IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT ) +#define WAKEUPNOTIFY(event) \ + IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false ) #define randomDelay() \ int del = read_processor_clock(); \ @@ -157,6 +161,19 @@ static OSArray * gIOFinalizeList; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#define queue_element(entry, element, type, field) do { \ + vm_address_t __ele = (vm_address_t) (entry); \ + __ele -= -4 + ((size_t)(&((type) 4)->field)); \ + (element) = (type) __ele; \ + } while(0) + +#define iterqueue(que, elt) \ + for (queue_entry_t elt = queue_first(que); \ + !queue_end(que, elt); \ + elt = queue_next(elt)) + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + struct ArbitrationLockQueueElement { queue_chain_t link; IOThread thread; @@ -171,6 +188,25 @@ static queue_head_t gArbitrationLockQueueWaiting; static queue_head_t gArbitrationLockQueueFree; static IOLock * gArbitrationLockQueueLock; +bool IOService::isInactive( void ) const + { return( 0 != (kIOServiceInactiveState & getState())); } + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#if __i386__ + +// Only used by the intel implementation of +// IOService::requireMaxBusStall(UInt32 __unused ns) +struct BusStallEntry +{ + const IOService *fService; + UInt32 fMaxDelay; +}; + +static OSData *sBusStall = OSData::withCapacity(8 * sizeof(BusStallEntry)); +static IOLock *sBusStallLock = IOLockAlloc(); +#endif /* __i386__ */ + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void IOService::initialize( void ) @@ -185,7 +221,8 @@ void IOService::initialize( void ) gIONameMatchedKey = OSSymbol::withCStringNoCopy( kIONameMatchedKey ); gIOPropertyMatchKey = OSSymbol::withCStringNoCopy( kIOPropertyMatchKey ); gIOPathMatchKey = OSSymbol::withCStringNoCopy( kIOPathMatchKey ); - gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey ); + gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey ); + gIOParentMatchKey = OSSymbol::withCStringNoCopy( kIOParentMatchKey ); gIOMatchCategoryKey = OSSymbol::withCStringNoCopy( kIOMatchCategoryKey ); gIODefaultMatchCategoryKey = OSSymbol::withCStringNoCopy( @@ -226,6 +263,13 @@ void IOService::initialize( void ) kIOTerminatedNotification ); gIOServiceKey = OSSymbol::withCStringNoCopy( kIOServiceClass); + gIOConsoleUsersKey = OSSymbol::withCStringNoCopy( kIOConsoleUsersKey); + gIOConsoleSessionUIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey); + gIOConsoleUsersSeedKey = OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey); + gIOConsoleSessionOnConsoleKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionOnConsoleKey); + gIOConsoleSessionSecureInputPIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionSecureInputPIDKey); + gIOConsoleUsersSeedValue = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed)); + gNotificationLock = IORecursiveLockAlloc(); assert( gIOServicePlane && gIODeviceMemoryKey @@ -234,7 +278,10 @@ void IOService::initialize( void ) && gIOProviderClassKey && gIONameMatchKey && gIONameMatchedKey && gIOMatchCategoryKey && gIODefaultMatchCategoryKey && gIOPublishNotification && gIOMatchedNotification - && gIOTerminatedNotification && gIOServiceKey ); + && gIOTerminatedNotification && gIOServiceKey + && gIOConsoleUsersKey && gIOConsoleSessionUIDKey + && gIOConsoleSessionOnConsoleKey && gIOConsoleSessionSecureInputPIDKey + && gIOConsoleUsersSeedKey && gIOConsoleUsersSeedValue); gJobsLock = IOLockAlloc(); gJobs = OSOrderedSet::withCapacity( 10 ); @@ -304,6 +351,7 @@ void IOService::stop( IOService * provider ) void IOService::free( void ) { + requireMaxBusStall(0); if( getPropertyTable()) unregisterAllInterest(); PMfree(); @@ -389,7 +437,7 @@ void IOService::detach( IOService * provider ) * Register instance - publish it for matching */ -void IOService::registerService( IOOptionBits options = 0 ) +void IOService::registerService( IOOptionBits options ) { char * pathBuf; const char * path; @@ -442,7 +490,7 @@ void IOService::registerService( IOOptionBits options = 0 ) startMatching( options ); } -void IOService::startMatching( IOOptionBits options = 0 ) +void IOService::startMatching( IOOptionBits options ) { IOService * provider; UInt32 prevBusy = 0; @@ -458,6 +506,8 @@ void IOService::startMatching( IOOptionBits options = 0 ) || ((provider = getProvider()) && (provider->__state[1] & kIOServiceSynchronousState)); + if ( options & kIOServiceAsynchronous ) + sync = false; needConfig = (0 == (__state[1] & (kIOServiceNeedConfigState | kIOServiceConfigState))) && (0 == (__state[0] & kIOServiceInactiveState)); @@ -500,7 +550,7 @@ void IOService::startMatching( IOOptionBits options = 0 ) lockForArbitration(); IOLockLock( gIOServiceBusyLock ); - waitAgain = (prevBusy != (__state[1] & kIOServiceBusyStateMask)); + waitAgain = (prevBusy < (__state[1] & kIOServiceBusyStateMask)); if( waitAgain) __state[1] |= kIOServiceSyncPubState | kIOServiceBusyWaiterState; else @@ -513,7 +563,7 @@ void IOService::startMatching( IOOptionBits options = 0 ) IOLockUnlock( gIOServiceBusyLock ); if( waitAgain) - thread_block((void (*)(void)) 0); + thread_block(THREAD_CONTINUE_NULL); } while( waitAgain ); } @@ -522,7 +572,8 @@ void IOService::startMatching( IOOptionBits options = 0 ) IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables ) { OSDictionary * table; - OSIterator * iter; + OSSet * set; + OSSet * allSet = 0; IOService * service; #if IOMATCHDEBUG SInt32 count = 0; @@ -533,18 +584,23 @@ IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables ) while( (table = (OSDictionary *) newTables->getFirstObject())) { LOCKWRITENOTIFY(); - iter = (OSIterator *) getExistingServices( table, - kIOServiceRegisteredState ); + set = (OSSet *) getExistingServices( table, + kIOServiceRegisteredState, + kIOServiceExistingSet); UNLOCKNOTIFY(); - if( iter) { - while( (service = (IOService *) iter->getNextObject())) { - service->startMatching(kIOServiceAsynchronous); + if( set) { + #if IOMATCHDEBUG - count++; + count += set->getCount(); #endif + if (allSet) { + allSet->merge((const OSSet *) set); + set->release(); } - iter->release(); + else + allSet = set; } + #if IOMATCHDEBUG if( getDebugFlags( table ) & kIOLogMatch) LOG("Matching service count = %ld\n", count); @@ -552,13 +608,21 @@ IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables ) newTables->removeObject(table); } + if (allSet) { + while( (service = (IOService *) allSet->getAnyObject())) { + service->startMatching(kIOServiceAsynchronous); + allSet->removeObject(service); + } + allSet->release(); + } + newTables->release(); return( kIOReturnSuccess ); } _IOServiceJob * _IOServiceJob::startJob( IOService * nub, int type, - IOOptionBits options = 0 ) + IOOptionBits options ) { _IOServiceJob * job; @@ -803,7 +867,7 @@ void IOService::setPMRootDomain( class IOPMrootDomain * rootDomain) * Stacking change */ -bool IOService::lockForArbitration( bool isSuccessRequired = true ) +bool IOService::lockForArbitration( bool isSuccessRequired ) { bool found; bool success; @@ -924,7 +988,9 @@ bool IOService::lockForArbitration( bool isSuccessRequired = true ) link ); // wake the victim - thread_wakeup_one(victim); + IOLockWakeup( gArbitrationLockQueueLock, + victim, + /* one thread */ true ); // allow this thread to proceed (ie. wait) success = true; // (put request on wait queue) @@ -962,15 +1028,17 @@ bool IOService::lockForArbitration( bool isSuccessRequired = true ) link ); // declare that this thread will wait for a given event -restart_sleep: assert_wait( element, - element->required ? THREAD_UNINT - : THREAD_INTERRUPTIBLE ); +restart_sleep: wait_result = assert_wait( element, + element->required ? THREAD_UNINT + : THREAD_INTERRUPTIBLE ); // unlock global access IOUnlock( gArbitrationLockQueueLock ); // put thread to sleep, waiting for our event to fire... - wait_result = thread_block((void (*)(void)) 0); + if (wait_result == THREAD_WAITING) + wait_result = thread_block(THREAD_CONTINUE_NULL); + // ...and we've been woken up; we might be in one of two states: // (a) we've been aborted and our queue element is not on @@ -1154,7 +1222,9 @@ void IOService::unlockForArbitration( void ) link ); // wake the waiting thread - thread_wakeup_one(element); + IOLockWakeup( gArbitrationLockQueueLock, + element, + /* one thread */ true ); } } @@ -1184,7 +1254,7 @@ void IOService::applyToClients( IOServiceApplierFunction applier, // send a message to a client or interested party of this service IOReturn IOService::messageClient( UInt32 type, OSObject * client, - void * argument = 0, vm_size_t argSize = 0 ) + void * argument, vm_size_t argSize ) { IOReturn ret; IOService * service; @@ -1219,7 +1289,7 @@ IOReturn IOService::messageClient( UInt32 type, OSObject * client, _IOServiceNotifierInvocation *, link ); if( kIOServiceNotifyWaiter & notify->state) { notify->state &= ~kIOServiceNotifyWaiter; - thread_wakeup( (event_t) notify); + WAKEUPNOTIFY( notify ); } UNLOCKNOTIFY(); @@ -1232,32 +1302,48 @@ IOReturn IOService::messageClient( UInt32 type, OSObject * client, return( ret ); } +static void +applyToInterestNotifiers(const IORegistryEntry *target, + const OSSymbol * typeOfInterest, + OSObjectApplierFunction applier, + void * context ) +{ + OSArray * copyArray = 0; + + LOCKREADNOTIFY(); + + IOCommand *notifyList = + OSDynamicCast( IOCommand, target->getProperty( typeOfInterest )); + + if( notifyList) { + copyArray = OSArray::withCapacity(1); + + // iterate over queue, entry is set to each element in the list + iterqueue(¬ifyList->fCommandChain, entry) { + _IOServiceInterestNotifier * notify; + + queue_element(entry, notify, _IOServiceInterestNotifier *, chain); + copyArray->setObject(notify); + } + } + UNLOCKNOTIFY(); + + if( copyArray) { + unsigned int index; + OSObject * next; + + for( index = 0; (next = copyArray->getObject( index )); index++) + (*applier)(next, context); + copyArray->release(); + } +} + void IOService::applyToInterested( const OSSymbol * typeOfInterest, OSObjectApplierFunction applier, void * context ) { - OSArray * array; - unsigned int index; - OSObject * next; - OSArray * copyArray; - applyToClients( (IOServiceApplierFunction) applier, context ); - - LOCKREADNOTIFY(); - array = OSDynamicCast( OSArray, getProperty( typeOfInterest )); - if( array) { - copyArray = OSArray::withArray( array ); - UNLOCKNOTIFY(); - if( copyArray) { - for( index = 0; - (next = array->getObject( index )); - index++) { - (*applier)(next, context); - } - copyArray->release(); - } - } else - UNLOCKNOTIFY(); + applyToInterestNotifiers(this, typeOfInterest, applier, context); } struct MessageClientsContext { @@ -1281,7 +1367,7 @@ static void messageClientsApplier( OSObject * object, void * ctx ) // send a message to all clients IOReturn IOService::messageClients( UInt32 type, - void * argument = 0, vm_size_t argSize = 0 ) + void * argument, vm_size_t argSize ) { MessageClientsContext context; @@ -1307,7 +1393,6 @@ IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, IOServiceInterestHandler handler, void * target, void * ref ) { _IOServiceInterestNotifier * notify = 0; - OSArray * set; if( (typeOfInterest != gIOGeneralInterest) && (typeOfInterest != gIOBusyInterest) @@ -1334,16 +1419,23 @@ IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, ////// queue LOCKWRITENOTIFY(); - if( 0 == (set = (OSArray *) getProperty( typeOfInterest ))) { - set = OSArray::withCapacity( 1 ); - if( set) { - setProperty( typeOfInterest, set ); - set->release(); - } - } - notify->whence = set; - if( set) - set->setObject( notify ); + + // Get the head of the notifier linked list + IOCommand *notifyList = (IOCommand *) getProperty( typeOfInterest ); + if (!notifyList || !OSDynamicCast(IOCommand, notifyList)) { + notifyList = OSTypeAlloc(IOCommand); + if (notifyList) { + notifyList->init(); + setProperty( typeOfInterest, notifyList); + notifyList->release(); + } + } + + if (notifyList) { + enqueue(¬ifyList->fCommandChain, ¬ify->chain); + notify->retain(); // ref'ed while in list + } + UNLOCKNOTIFY(); } } @@ -1352,30 +1444,30 @@ IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, return( notify ); } -static void cleanInterestArray( OSObject * object ) +static void cleanInterestList( OSObject * head ) { - OSArray * array; - unsigned int index; - _IOServiceInterestNotifier * next; - - if( (array = OSDynamicCast( OSArray, object))) { - LOCKWRITENOTIFY(); - for( index = 0; - (next = (_IOServiceInterestNotifier *) - array->getObject( index )); - index++) { - next->whence = 0; - } - UNLOCKNOTIFY(); + IOCommand *notifyHead = OSDynamicCast(IOCommand, head); + if (!notifyHead) + return; + + LOCKWRITENOTIFY(); + while ( queue_entry_t entry = dequeue(¬ifyHead->fCommandChain) ) { + queue_next(entry) = queue_prev(entry) = 0; + + _IOServiceInterestNotifier * notify; + + queue_element(entry, notify, _IOServiceInterestNotifier *, chain); + notify->release(); } + UNLOCKNOTIFY(); } void IOService::unregisterAllInterest( void ) { - cleanInterestArray( getProperty( gIOGeneralInterest )); - cleanInterestArray( getProperty( gIOBusyInterest )); - cleanInterestArray( getProperty( gIOAppPowerStateInterest )); - cleanInterestArray( getProperty( gIOPriorityPowerStateInterest )); + cleanInterestList( getProperty( gIOGeneralInterest )); + cleanInterestList( getProperty( gIOBusyInterest )); + cleanInterestList( getProperty( gIOAppPowerStateInterest )); + cleanInterestList( getProperty( gIOPriorityPowerStateInterest )); } /* @@ -1401,10 +1493,7 @@ void _IOServiceInterestNotifier::wait() } if( doWait) { state |= kIOServiceNotifyWaiter; - assert_wait( this, THREAD_UNINT); - UNLOCKNOTIFY(); - thread_block((void (*)(void)) 0); - LOCKWRITENOTIFY(); + SLEEPNOTIFY(this); } } while( doWait ); @@ -1420,10 +1509,10 @@ void _IOServiceInterestNotifier::remove() { LOCKWRITENOTIFY(); - if( whence) { - whence->removeObject(whence->getNextIndexOfObject( - (OSObject *) this, 0 )); - whence = 0; + if( queue_next( &chain )) { + remqueue( 0, &chain); + queue_next( &chain) = queue_prev( &chain) = 0; + release(); } state &= ~kIOServiceNotifyEnable; @@ -1503,7 +1592,7 @@ bool IOService::requestTerminate( IOService * provider, IOOptionBits options ) return( ok ); } -bool IOService::terminatePhase1( IOOptionBits options = 0 ) +bool IOService::terminatePhase1( IOOptionBits options ) { IOService * victim; IOService * client; @@ -1531,7 +1620,7 @@ bool IOService::terminatePhase1( IOOptionBits options = 0 ) while( victim ) { - didInactive = victim->lockForArbitration( true ); + didInactive = victim->lockForArbitration( true ); if( didInactive) { didInactive = (0 == (victim->__state[0] & kIOServiceInactiveState)); if( didInactive) { @@ -1540,7 +1629,7 @@ bool IOService::terminatePhase1( IOOptionBits options = 0 ) | kIOServiceFirstPublishState | kIOServiceFirstMatchState); victim->_adjustBusy( 1 ); } - victim->unlockForArbitration(); + victim->unlockForArbitration(); } if( victim == this) startPhase2 = didInactive; @@ -1548,7 +1637,6 @@ bool IOService::terminatePhase1( IOOptionBits options = 0 ) victim->deliverNotification( gIOTerminatedNotification, 0, 0xffffffff ); IOUserClient::destroyUserReferences( victim ); - victim->unregisterAllInterest(); iter = victim->getClientIterator(); if( iter) { @@ -1580,10 +1668,10 @@ bool IOService::terminatePhase1( IOOptionBits options = 0 ) return( true ); } -void IOService::scheduleTerminatePhase2( IOOptionBits options = 0 ) +void IOService::scheduleTerminatePhase2( IOOptionBits options ) { AbsoluteTime deadline; - int waitResult; + int waitResult = THREAD_AWAKENED; bool wait, haveDeadline = false; options |= kIOServiceRequired; @@ -1599,10 +1687,7 @@ void IOService::scheduleTerminatePhase2( IOOptionBits options = 0 ) wait = (gIOTerminateThread != 0); if( wait) { // wait to become the terminate thread - assert_wait( (event_t) &gIOTerminateThread, THREAD_UNINT ); - IOLockUnlock( gJobsLock ); - thread_block((void (*)(void)) 0); - IOLockLock( gJobsLock ); + IOLockSleep( gJobsLock, &gIOTerminateThread, THREAD_UNINT); } } while( wait ); @@ -1611,35 +1696,36 @@ void IOService::scheduleTerminatePhase2( IOOptionBits options = 0 ) gIOTerminateWork++; do { - terminateWorker( options ); + while( gIOTerminateWork ) + terminateWorker( options ); wait = (0 != (__state[1] & kIOServiceBusyStateMask)); if( wait) { // wait for the victim to go non-busy - assert_wait( (event_t) &gIOTerminateWork, THREAD_UNINT ); if( !haveDeadline) { clock_interval_to_deadline( 15, kSecondScale, &deadline ); haveDeadline = true; } - thread_set_timer_deadline( deadline ); - IOLockUnlock( gJobsLock ); - waitResult = thread_block((void (*)(void)) 0); + waitResult = IOLockSleepDeadline( gJobsLock, &gIOTerminateWork, + deadline, THREAD_UNINT ); if( waitResult == THREAD_TIMED_OUT) { TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName()); - } else - thread_cancel_timer(); - IOLockLock( gJobsLock ); + } } - } while( wait && (waitResult != THREAD_TIMED_OUT)); + } while(gIOTerminateWork || (wait && (waitResult != THREAD_TIMED_OUT))); - gIOTerminateThread = 0; - thread_wakeup( (event_t) &gIOTerminateThread ); + gIOTerminateThread = 0; + IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false); } else { // ! kIOServiceSynchronous gIOTerminatePhase2List->setObject( this ); - if( 0 == gIOTerminateWork++) - gIOTerminateThread = IOCreateThread( &terminateThread, (void *) options ); + if( 0 == gIOTerminateWork++) { + if( !gIOTerminateThread) + gIOTerminateThread = IOCreateThread( &terminateThread, (void *) options ); + else + IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); + } } IOLockUnlock( gJobsLock ); @@ -1651,10 +1737,11 @@ void IOService::terminateThread( void * arg ) { IOLockLock( gJobsLock ); - terminateWorker( (IOOptionBits) arg ); + while (gIOTerminateWork) + terminateWorker( (IOOptionBits) arg ); gIOTerminateThread = 0; - thread_wakeup( (event_t) &gIOTerminateThread ); + IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false); IOLockUnlock( gJobsLock ); } @@ -1671,7 +1758,7 @@ void IOService::scheduleStop( IOService * provider ) if( !gIOTerminateThread) gIOTerminateThread = IOCreateThread( &terminateThread, (void *) 0 ); else - thread_wakeup( (event_t) &gIOTerminateWork ); + IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); } IOLockUnlock( gJobsLock ); @@ -1688,7 +1775,7 @@ void IOService::scheduleFinalize( void ) if( !gIOTerminateThread) gIOTerminateThread = IOCreateThread( &terminateThread, (void *) 0 ); else - thread_wakeup( (event_t) &gIOTerminateWork ); + IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); } IOLockUnlock( gJobsLock ); @@ -1956,8 +2043,8 @@ bool IOService::finalize( IOOptionBits options ) return( true ); } -#undef tailQ(o) -#undef headQ(o) +#undef tailQ +#undef headQ /* * Terminate @@ -1981,7 +2068,7 @@ bool IOService::terminateClient( IOService * client, IOOptionBits options ) return( ok ); } -bool IOService::terminate( IOOptionBits options = 0 ) +bool IOService::terminate( IOOptionBits options ) { options |= kIOServiceTerminate; @@ -2011,8 +2098,8 @@ static void serviceOpenMessageApplier( OSObject * object, void * ctx ) } bool IOService::open( IOService * forClient, - IOOptionBits options = 0, - void * arg = 0 ) + IOOptionBits options, + void * arg ) { bool ok; ServiceOpenMessageContext context; @@ -2038,7 +2125,7 @@ bool IOService::open( IOService * forClient, } void IOService::close( IOService * forClient, - IOOptionBits options = 0 ) + IOOptionBits options ) { bool wasClosed; bool last = false; @@ -2070,7 +2157,7 @@ void IOService::close( IOService * forClient, } } -bool IOService::isOpen( const IOService * forClient = 0 ) const +bool IOService::isOpen( const IOService * forClient ) const { IOService * self = (IOService *) this; bool ok; @@ -2234,7 +2321,7 @@ bool IOService::invokeNotifer( _IOServiceNotifier * notify ) _IOServiceNotifierInvocation *, link ); if( kIOServiceNotifyWaiter & notify->state) { notify->state &= ~kIOServiceNotifyWaiter; - thread_wakeup( (event_t) notify); + WAKEUPNOTIFY( notify ); } UNLOCKNOTIFY(); } @@ -2533,14 +2620,37 @@ bool IOService::startCandidate( IOService * service ) ok = service->attach( this ); - if( ok) { - // stall for any nub resources - checkResources(); - // stall for any driver resources - service->checkResources(); + if( ok) + { + if (this != gIOResources) + { + // stall for any nub resources + checkResources(); + // stall for any driver resources + service->checkResources(); + } + + AbsoluteTime startTime; + AbsoluteTime endTime; + UInt64 nano; + if (kIOLogStart & gIOKitDebug) + clock_get_uptime(&startTime); - ok = service->start( this ); + ok = service->start(this); + + if (kIOLogStart & gIOKitDebug) + { + clock_get_uptime(&endTime); + + if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) + { + SUB_ABSOLUTETIME(&endTime, &startTime); + absolutetime_to_nanoseconds(endTime, &nano); + if (nano > 500000000ULL) + IOLog("%s::start took %ld ms\n", service->getName(), (UInt32)(nano / 1000000ULL)); + } + } if( !ok) service->detach( this ); } @@ -2552,7 +2662,7 @@ IOService * IOService::resources( void ) return( gIOResources ); } -void IOService::publishResource( const char * key, OSObject * value = 0 ) +void IOService::publishResource( const char * key, OSObject * value ) { const OSSymbol * sym; @@ -2562,35 +2672,38 @@ void IOService::publishResource( const char * key, OSObject * value = 0 ) } } -void IOService::publishResource( const OSSymbol * key, OSObject * value = 0 ) +void IOService::publishResource( const OSSymbol * key, OSObject * value ) { if( 0 == value) value = (OSObject *) gIOServiceKey; gIOResources->setProperty( key, value); + if( IORecursiveLockHaveLock( gNotificationLock)) + return; + gIOResourceGenerationCount++; gIOResources->registerService(); } bool IOService::addNeededResource( const char * key ) { - OSObject * resources; + OSObject * resourcesProp; OSSet * set; OSString * newKey; bool ret; - resources = getProperty( gIOResourceMatchKey ); + resourcesProp = getProperty( gIOResourceMatchKey ); newKey = OSString::withCString( key ); - if( (0 == resources) || (0 == newKey)) + if( (0 == resourcesProp) || (0 == newKey)) return( false); - set = OSDynamicCast( OSSet, resources ); + set = OSDynamicCast( OSSet, resourcesProp ); if( !set) { set = OSSet::withCapacity( 1 ); if( set) - set->setObject( resources ); + set->setObject( resourcesProp ); } else set->retain(); @@ -2637,32 +2750,32 @@ bool IOService::checkResource( OSObject * matching ) bool IOService::checkResources( void ) { - OSObject * resources; + OSObject * resourcesProp; OSSet * set; OSIterator * iter; bool ok; - resources = getProperty( gIOResourceMatchKey ); - if( 0 == resources) + resourcesProp = getProperty( gIOResourceMatchKey ); + if( 0 == resourcesProp) return( true ); - if( (set = OSDynamicCast( OSSet, resources ))) { + if( (set = OSDynamicCast( OSSet, resourcesProp ))) { iter = OSCollectionIterator::withCollection( set ); ok = (0 != iter); - while( ok && (resources = iter->getNextObject()) ) - ok = checkResource( resources ); + while( ok && (resourcesProp = iter->getNextObject()) ) + ok = checkResource( resourcesProp ); if( iter) iter->release(); } else - ok = checkResource( resources ); + ok = checkResource( resourcesProp ); return( ok ); } -_IOConfigThread * _IOConfigThread::configThread( void ) +void _IOConfigThread::configThread( void ) { _IOConfigThread * inst; @@ -2671,18 +2784,17 @@ _IOConfigThread * _IOConfigThread::configThread( void ) continue; if( !inst->init()) continue; - if( !(inst->thread = IOCreateThread - ( (IOThreadFunc) &_IOConfigThread::main, inst ))) + if( !(IOCreateThread((IOThreadFunc) &_IOConfigThread::main, inst ))) continue; - return( inst ); + return; } while( false); if( inst) inst->release(); - return( 0 ); + return; } void _IOConfigThread::free( void ) @@ -2801,21 +2913,15 @@ UInt32 IOService::_adjustBusy( SInt32 delta ) next->unlockForArbitration(); if( (wasQuiet || nowQuiet) ) { - OSArray * array; - unsigned int index; - OSObject * interested; - - array = OSDynamicCast( OSArray, next->getProperty( gIOBusyInterest )); - if( array) { - LOCKREADNOTIFY(); - for( index = 0; - (interested = array->getObject( index )); - index++) { - next->messageClient(kIOMessageServiceBusyStateChange, - interested, (void *) wasQuiet /* busy now */); - } - UNLOCKNOTIFY(); - } + MessageClientsContext context; + + context.service = next; + context.type = kIOMessageServiceBusyStateChange; + context.argument = (void *) wasQuiet; // busy now + context.argSize = 0; + + applyToInterestNotifiers( next, gIOBusyInterest, + &messageClientsApplier, &context ); if( nowQuiet && (next == gIOServiceRoot)) OSMetaClass::considerUnloads(); @@ -2841,7 +2947,7 @@ UInt32 IOService::getBusyState( void ) } IOReturn IOService::waitForState( UInt32 mask, UInt32 value, - mach_timespec_t * timeout = 0 ) + mach_timespec_t * timeout ) { bool wait; int waitResult = THREAD_AWAKENED; @@ -2855,7 +2961,6 @@ IOReturn IOService::waitForState( UInt32 mask, UInt32 value, if( wait) { __state[1] |= kIOServiceBusyWaiterState; unlockForArbitration(); - assert_wait( (event_t) this, THREAD_UNINT ); if( timeout ) { if( computeDeadline ) { AbsoluteTime nsinterval; @@ -2868,16 +2973,16 @@ IOReturn IOService::waitForState( UInt32 mask, UInt32 value, abstime, &abstime ); computeDeadline = false; } - thread_set_timer_deadline( abstime ); + + assert_wait_deadline((event_t)this, THREAD_UNINT, __OSAbsoluteTime(abstime)); } + else + assert_wait((event_t)this, THREAD_UNINT ); } else unlockForArbitration(); IOLockUnlock( gIOServiceBusyLock ); - if( wait) { - waitResult = thread_block((void (*)(void)) 0); - if( timeout && (waitResult != THREAD_TIMED_OUT)) - thread_cancel_timer(); - } + if( wait) + waitResult = thread_block(THREAD_CONTINUE_NULL); } while( wait && (waitResult != THREAD_TIMED_OUT)); @@ -2887,7 +2992,7 @@ IOReturn IOService::waitForState( UInt32 mask, UInt32 value, return( kIOReturnSuccess ); } -IOReturn IOService::waitQuiet( mach_timespec_t * timeout = 0 ) +IOReturn IOService::waitQuiet( mach_timespec_t * timeout ) { return( waitForState( kIOServiceBusyStateMask, 0, timeout )); } @@ -2956,7 +3061,7 @@ void _IOConfigThread::main( _IOConfigThread * self ) else { if( 0 == --gNumConfigThreads) { // IOLog("MATCH IDLE\n"); - thread_wakeup( (event_t) &gNumConfigThreads); + IOLockWakeup( gJobsLock, (event_t) &gNumConfigThreads, /* one-thread */ false ); } } IOUnlock( gJobsLock ); @@ -2977,11 +3082,10 @@ IOReturn IOService::waitMatchIdle( UInt32 msToWait ) bool computeDeadline = true; AbsoluteTime abstime; + IOLockLock( gJobsLock ); do { - IOLockLock( gJobsLock ); wait = (0 != gNumConfigThreads); if( wait) { - assert_wait( (event_t) &gNumConfigThreads, THREAD_UNINT ); if( msToWait) { if( computeDeadline ) { clock_interval_to_absolutetime_interval( @@ -2990,17 +3094,15 @@ IOReturn IOService::waitMatchIdle( UInt32 msToWait ) abstime, &abstime ); computeDeadline = false; } - thread_set_timer_deadline( abstime ); - } + waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads, + abstime, THREAD_UNINT ); + } else { + waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads, + THREAD_UNINT ); + } } - IOUnlock( gJobsLock ); - if( wait) { - waitResult = thread_block((void (*)(void)) 0); - if( msToWait && (waitResult != THREAD_TIMED_OUT)) - thread_cancel_timer(); - } - } while( wait && (waitResult != THREAD_TIMED_OUT)); + IOLockUnlock( gJobsLock ); if( waitResult == THREAD_TIMED_OUT) return( kIOReturnTimeout ); @@ -3043,44 +3145,64 @@ void _IOServiceJob::pingConfig( _IOServiceJob * job ) semaphore_signal( gJobsSemaphore ); } - // internal - call with gNotificationLock OSObject * IOService::getExistingServices( OSDictionary * matching, - IOOptionBits inState, IOOptionBits options = 0 ) + IOOptionBits inState, IOOptionBits options ) { OSObject * current = 0; OSIterator * iter; IOService * service; + OSObject * obj; if( !matching) return( 0 ); - iter = IORegistryIterator::iterateOver( gIOServicePlane, - kIORegistryIterateRecursively ); - if( iter) { - do { - iter->reset(); - while( (service = (IOService *) iter->getNextObject())) { - if( (inState == (service->__state[0] & inState)) - && (0 == (service->__state[0] & kIOServiceInactiveState)) - && service->passiveMatch( matching )) { - - if( options & kIONotifyOnce) { - current = service; - break; - } - if( current) - ((OSSet *)current)->setObject( service ); - else - current = OSSet::withObjects( - & (const OSObject *) service, 1, 1 ); - } - } - } while( !service && !iter->isValid()); - iter->release(); + if(true + && (obj = matching->getObject(gIOProviderClassKey)) + && gIOResourcesKey + && gIOResourcesKey->isEqualTo(obj) + && (service = gIOResources)) + { + if( (inState == (service->__state[0] & inState)) + && (0 == (service->__state[0] & kIOServiceInactiveState)) + && service->passiveMatch( matching )) + { + if( options & kIONotifyOnce) + current = service; + else + current = OSSet::withObjects( + (const OSObject **) &service, 1, 1 ); + } + } + else + { + iter = IORegistryIterator::iterateOver( gIOServicePlane, + kIORegistryIterateRecursively ); + if( iter) { + do { + iter->reset(); + while( (service = (IOService *) iter->getNextObject())) { + if( (inState == (service->__state[0] & inState)) + && (0 == (service->__state[0] & kIOServiceInactiveState)) + && service->passiveMatch( matching )) { + + if( options & kIONotifyOnce) { + current = service; + break; + } + if( current) + ((OSSet *)current)->setObject( service ); + else + current = OSSet::withObjects( + (const OSObject **) &service, 1, 1 ); + } + } + } while( !service && !iter->isValid()); + iter->release(); + } } - if( current && (0 == (options & kIONotifyOnce))) { + if( current && (0 == (options & (kIONotifyOnce | kIOServiceExistingSet)))) { iter = OSCollectionIterator::withCollection( (OSSet *)current ); current->release(); current = iter; @@ -3110,7 +3232,7 @@ OSIterator * IOService::getMatchingServices( OSDictionary * matching ) IONotifier * IOService::setNotification( const OSSymbol * type, OSDictionary * matching, IOServiceNotificationHandler handler, void * target, void * ref, - SInt32 priority = 0 ) + SInt32 priority ) { _IOServiceNotifier * notify = 0; OSOrderedSet * set; @@ -3214,8 +3336,8 @@ IONotifier * IOService::installNotification( IONotifier * IOService::addNotification( const OSSymbol * type, OSDictionary * matching, IOServiceNotificationHandler handler, - void * target, void * ref = 0, - SInt32 priority = 0 ) + void * target, void * ref, + SInt32 priority ) { OSIterator * existing; _IOServiceNotifier * notify; @@ -3261,7 +3383,7 @@ bool IOService::syncNotificationHandler( } IOService * IOService::waitForService( OSDictionary * matching, - mach_timespec_t * timeout = 0 ) + mach_timespec_t * timeout ) { IONotifier * notify = 0; // priority doesn't help us much since we need a thread wakeup @@ -3371,7 +3493,7 @@ IOOptionBits IOService::getState( void ) const */ OSDictionary * IOService::serviceMatching( const OSString * name, - OSDictionary * table = 0 ) + OSDictionary * table ) { if( !table) table = OSDictionary::withCapacity( 2 ); @@ -3382,7 +3504,7 @@ OSDictionary * IOService::serviceMatching( const OSString * name, } OSDictionary * IOService::serviceMatching( const char * name, - OSDictionary * table = 0 ) + OSDictionary * table ) { const OSString * str; @@ -3396,7 +3518,7 @@ OSDictionary * IOService::serviceMatching( const char * name, } OSDictionary * IOService::nameMatching( const OSString * name, - OSDictionary * table = 0 ) + OSDictionary * table ) { if( !table) table = OSDictionary::withCapacity( 2 ); @@ -3407,7 +3529,7 @@ OSDictionary * IOService::nameMatching( const OSString * name, } OSDictionary * IOService::nameMatching( const char * name, - OSDictionary * table = 0 ) + OSDictionary * table ) { const OSString * str; @@ -3421,7 +3543,7 @@ OSDictionary * IOService::nameMatching( const char * name, } OSDictionary * IOService::resourceMatching( const OSString * str, - OSDictionary * table = 0 ) + OSDictionary * table ) { table = serviceMatching( gIOResourcesKey, table ); if( table) @@ -3431,7 +3553,7 @@ OSDictionary * IOService::resourceMatching( const OSString * str, } OSDictionary * IOService::resourceMatching( const char * name, - OSDictionary * table = 0 ) + OSDictionary * table ) { const OSSymbol * str; @@ -3468,10 +3590,7 @@ void _IOServiceNotifier::wait() } if( doWait) { state |= kIOServiceNotifyWaiter; - assert_wait( this, THREAD_UNINT); - UNLOCKNOTIFY(); - thread_block((void (*)(void)) 0); - LOCKWRITENOTIFY(); + SLEEPNOTIFY(this); } } while( doWait ); @@ -3585,6 +3704,43 @@ bool IOResources::matchPropertyTable( OSDictionary * table ) return( ok ); } +IOReturn IOResources::setProperties( OSObject * properties ) +{ + IOReturn err; + const OSSymbol * key; + OSDictionary * dict; + OSCollectionIterator * iter; + + err = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator); + if ( kIOReturnSuccess != err) + return( err ); + + dict = OSDynamicCast(OSDictionary, properties); + if( 0 == dict) + return( kIOReturnBadArgument); + + iter = OSCollectionIterator::withCollection( dict); + if( 0 == iter) + return( kIOReturnBadArgument); + + while( (key = OSDynamicCast(OSSymbol, iter->getNextObject()))) { + + if (gIOConsoleUsersKey == key) + { + IORegistryEntry::getRegistryRoot()->setProperty(key, dict->getObject(key)); + OSIncrementAtomic( &gIOConsoleUsersSeed ); + publishResource( gIOConsoleUsersSeedKey, gIOConsoleUsersSeedValue ); + continue; + } + + publishResource( key, dict->getObject(key) ); + } + + iter->release(); + + return( kIOReturnSuccess ); +} + /* * Helpers for matching dictionaries. * Keys existing in matching are checked in properties. @@ -3690,6 +3846,7 @@ bool IOService::passiveMatch( OSDictionary * table, bool changesOK ) SInt32 score; OSNumber * newPri; bool match = true; + bool matchParent = false; UInt32 done; assert( table ); @@ -3697,140 +3854,174 @@ bool IOService::passiveMatch( OSDictionary * table, bool changesOK ) where = this; do { - done = 0; + do { + done = 0; - str = OSDynamicCast( OSString, table->getObject( gIOProviderClassKey)); - if( str) { - done++; - match = (0 != where->metaCast( str )); - if( !match) - break; - } + str = OSDynamicCast( OSString, table->getObject( gIOProviderClassKey)); + if( str) { + done++; + match = (0 != where->metaCast( str )); + if( !match) + break; + } - obj = table->getObject( gIONameMatchKey ); - if( obj) { - done++; - match = compareNames( obj, changesOK ? &matched : 0 ); - if( !match) - break; - if( changesOK && matched) { - // leave a hint as to which name matched - table->setObject( gIONameMatchedKey, matched ); - matched->release(); + obj = table->getObject( gIONameMatchKey ); + if( obj) { + done++; + match = where->compareNames( obj, changesOK ? &matched : 0 ); + if( !match) + break; + if( changesOK && matched) { + // leave a hint as to which name matched + table->setObject( gIONameMatchedKey, matched ); + matched->release(); + } } - } - obj = table->getObject( gIOPropertyMatchKey ); - if( obj) { - - OSDictionary * dict; - OSDictionary * nextDict; - OSIterator * iter; - - done++; - dict = where->dictionaryWithProperties(); - if( dict) { - nextDict = OSDynamicCast( OSDictionary, obj); - if( nextDict) - iter = 0; - else - iter = OSCollectionIterator::withCollection( - OSDynamicCast(OSCollection, obj)); - - while( nextDict - || (iter && (0 != (nextDict = OSDynamicCast(OSDictionary, - iter->getNextObject()))))) { - match = dict->isEqualTo( nextDict, nextDict); - if( match) - break; - nextDict = 0; + + str = OSDynamicCast( OSString, table->getObject( gIOLocationMatchKey )); + if( str) { + + const OSSymbol * sym; + + done++; + match = false; + sym = where->copyLocation(); + if( sym) { + match = sym->isEqualTo( str ); + sym->release(); } - dict->release(); - if( iter) - iter->release(); if( !match) break; } - } - str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey )); - if( str) { - done++; - entry = IORegistryEntry::fromPath( str->getCStringNoCopy() ); - match = (where == entry); - if( entry) - entry->release(); - if( !match) - break; - } + obj = table->getObject( gIOPropertyMatchKey ); + if( obj) { - num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey )); - if( num) { + OSDictionary * dict; + OSDictionary * nextDict; + OSIterator * iter; - OSIterator * iter; - IOService * service = 0; - UInt32 serviceCount = 0; + done++; + match = false; + dict = where->dictionaryWithProperties(); + if( dict) { + nextDict = OSDynamicCast( OSDictionary, obj); + if( nextDict) + iter = 0; + else + iter = OSCollectionIterator::withCollection( + OSDynamicCast(OSCollection, obj)); + + while( nextDict + || (iter && (0 != (nextDict = OSDynamicCast(OSDictionary, + iter->getNextObject()))))) { + match = dict->isEqualTo( nextDict, nextDict); + if( match) + break; + nextDict = 0; + } + dict->release(); + if( iter) + iter->release(); + } + if( !match) + break; + } - done++; - iter = getClientIterator(); - if( iter) { - while( (service = (IOService *) iter->getNextObject())) { - if( kIOServiceInactiveState & service->__state[0]) - continue; - if( 0 == service->getProperty( gIOMatchCategoryKey )) - continue; - ++serviceCount; + str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey )); + if( str) { + done++; + entry = IORegistryEntry::fromPath( str->getCStringNoCopy() ); + match = (where == entry); + if( entry) + entry->release(); + if( !match) + break; + } + + num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey )); + if( num) { + + OSIterator * iter; + IOService * service = 0; + UInt32 serviceCount = 0; + + done++; + iter = where->getClientIterator(); + if( iter) { + while( (service = (IOService *) iter->getNextObject())) { + if( kIOServiceInactiveState & service->__state[0]) + continue; + if( 0 == service->getProperty( gIOMatchCategoryKey )) + continue; + ++serviceCount; + } + iter->release(); } - iter->release(); + match = (serviceCount == num->unsigned32BitValue()); + if( !match) + break; } - match = (serviceCount == num->unsigned32BitValue()); - if( !match) - break; - } - if( done == table->getCount()) - // don't call family if we've done all the entries in the table - break; + if( done == table->getCount()) { + // don't call family if we've done all the entries in the table + matchParent = false; + break; + } - // pass in score from property table - score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey); + // pass in score from property table + score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey); - // do family specific matching - match = where->matchPropertyTable( table, &score ); + // do family specific matching + match = where->matchPropertyTable( table, &score ); - if( !match) { + if( !match) { #if IOMATCHDEBUG - if( kIOLogMatch & getDebugFlags( table )) - LOG("%s: family specific matching fails\n", where->getName()); + if( kIOLogMatch & getDebugFlags( table )) + LOG("%s: family specific matching fails\n", where->getName()); #endif - break; - } + break; + } + + if( changesOK) { + // save the score + newPri = OSNumber::withNumber( score, 32 ); + if( newPri) { + table->setObject( gIOProbeScoreKey, newPri ); + newPri->release(); + } + } + + if( !(match = where->compareProperty( table, kIOBSDNameKey ))) + break; + + matchParent = false; - if( changesOK) { - // save the score - newPri = OSNumber::withNumber( score, 32 ); - if( newPri) { - table->setObject( gIOProbeScoreKey, newPri ); - newPri->release(); + obj = OSDynamicCast( OSDictionary, + table->getObject( gIOParentMatchKey )); + if( obj) { + match = false; + matchParent = true; + table = (OSDictionary *) obj; + break; } - } - if( !(match = where->compareProperty( table, kIOBSDNameKey ))) - break; + table = OSDynamicCast( OSDictionary, + table->getObject( gIOLocationMatchKey )); + if( table) { + match = false; + where = where->getProvider(); + if( where) + where = where->matchLocation( where ); + } - table = OSDynamicCast( OSDictionary, - table->getObject( gIOLocationMatchKey )); - if( table) { - match = false; - where = where->getProvider(); - if( where) - where = where->matchLocation( where ); - } + } while( table && where ); - } while( table && where ); + } while( matchParent && (where = where->getProvider()) ); if( kIOLogMatch & gIOKitDebug) if( where != this) - LOG("match location @ %s = %d\n", + LOG("match parent @ %s = %d\n", where->getName(), match ); return( match ); @@ -3845,6 +4036,9 @@ IOReturn IOService::newUserClient( task_t owningTask, void * securityID, IOUserClient *client; OSObject *temp; + if (kIOReturnSuccess == newUserClient( owningTask, securityID, type, handler )) + return kIOReturnSuccess; + // First try my own properties for a user client class name temp = getProperty(gIOUserClientClassKey); if (temp) { @@ -3862,6 +4056,7 @@ IOReturn IOService::newUserClient( task_t owningTask, void * securityID, if (!userClientClass) return kIOReturnUnsupported; + // This reference is consumed by the IOServiceOpen call temp = OSMetaClass::allocClassWithName(userClientClass); if (!temp) return kIOReturnNoMemory; @@ -3896,7 +4091,7 @@ IOReturn IOService::newUserClient( task_t owningTask, void * securityID, IOReturn IOService::newUserClient( task_t owningTask, void * securityID, UInt32 type, IOUserClient ** handler ) { - return( newUserClient( owningTask, securityID, type, 0, handler )); + return( kIOReturnUnsupported ); } IOReturn IOService::requestProbe( IOOptionBits options ) @@ -3995,7 +4190,7 @@ int IOService::errnoFromReturn( IOReturn rtn ) case kIOReturnBadArgument: return(EINVAL); case kIOReturnUnsupported: - return(EOPNOTSUPP); + return(ENOTSUP); case kIOReturnBusy: return(EBUSY); case kIOReturnNoPower: @@ -4040,7 +4235,7 @@ int IOService::errnoFromReturn( IOReturn rtn ) case kIOReturnBadMedia: case kIOReturnNoMedia: case kIOReturnUnformattedMedia: - return(EIO); // (media error) + return(ENXIO); // (media error) case kIOReturnDMAError: case kIOReturnOverrun: case kIOReturnUnderrun: @@ -4106,7 +4301,7 @@ IODeviceMemory * IOService::getDeviceMemoryWithIndex( unsigned int index ) } IOMemoryMap * IOService::mapDeviceMemoryWithIndex( unsigned int index, - IOOptionBits options = 0 ) + IOOptionBits options ) { IODeviceMemory * range; IOMemoryMap * map; @@ -4131,6 +4326,92 @@ void IOService::setDeviceMemory( OSArray * array ) setProperty( gIODeviceMemoryKey, array); } +/* + * For machines where the transfers on an I/O bus can stall because + * the CPU is in an idle mode, These APIs allow a driver to specify + * the maximum bus stall that they can handle. 0 indicates no limit. + */ +void IOService:: +setCPUSnoopDelay(UInt32 __unused ns) +{ +#if __i386__ + ml_set_maxsnoop(ns); +#endif /* __i386__ */ +} + +UInt32 IOService:: +getCPUSnoopDelay() +{ +#if __i386__ + return ml_get_maxsnoop(); +#else + return 0; +#endif /* __i386__ */ +} + +void IOService:: +requireMaxBusStall(UInt32 __unused ns) +{ +#if __i386__ + static const UInt kNoReplace = -1U; // Must be an illegal index + UInt replace = kNoReplace; + + IOLockLock(sBusStallLock); + + UInt count = sBusStall->getLength() / sizeof(BusStallEntry); + BusStallEntry *entries = (BusStallEntry *) sBusStall->getBytesNoCopy(); + + if (ns) { + const BusStallEntry ne = {this, ns}; + + // Set Maximum bus delay. + for (UInt i = 0; i < count; i++) { + const IOService *thisService = entries[i].fService; + if (this == thisService) + replace = i; + else if (!thisService) { + if (kNoReplace == replace) + replace = i; + } + else { + const UInt32 thisMax = entries[i].fMaxDelay; + if (thisMax < ns) + ns = thisMax; + } + } + + // Must be safe to call from locked context + ml_set_maxbusdelay(ns); + + if (kNoReplace == replace) + sBusStall->appendBytes(&ne, sizeof(ne)); + else + entries[replace] = ne; + } + else { + ns = -1U; // Set to max unsigned, i.e. no restriction + + for (UInt i = 0; i < count; i++) { + // Clear a maximum bus delay. + const IOService *thisService = entries[i].fService; + UInt32 thisMax = entries[i].fMaxDelay; + if (this == thisService) + replace = i; + else if (thisService && thisMax < ns) + ns = thisMax; + } + + // Check if entry found + if (kNoReplace != replace) { + entries[replace].fService = 0; // Null the entry + ml_set_maxbusdelay(ns); + } + } + + IOLockUnlock(sBusStallLock); +#endif /* __i386__ */ +} + /* * Device interrupts */ @@ -4290,8 +4571,8 @@ IOReturn IOService::causeInterrupt(int source) OSMetaClassDefineReservedUsed(IOService, 0); OSMetaClassDefineReservedUsed(IOService, 1); OSMetaClassDefineReservedUsed(IOService, 2); +OSMetaClassDefineReservedUsed(IOService, 3); -OSMetaClassDefineReservedUnused(IOService, 3); OSMetaClassDefineReservedUnused(IOService, 4); OSMetaClassDefineReservedUnused(IOService, 5); OSMetaClassDefineReservedUnused(IOService, 6); @@ -4336,6 +4617,8 @@ OSMetaClassDefineReservedUnused(IOService, 44); OSMetaClassDefineReservedUnused(IOService, 45); OSMetaClassDefineReservedUnused(IOService, 46); OSMetaClassDefineReservedUnused(IOService, 47); + +#ifdef __ppc__ OSMetaClassDefineReservedUnused(IOService, 48); OSMetaClassDefineReservedUnused(IOService, 49); OSMetaClassDefineReservedUnused(IOService, 50); @@ -4352,3 +4635,4 @@ OSMetaClassDefineReservedUnused(IOService, 60); OSMetaClassDefineReservedUnused(IOService, 61); OSMetaClassDefineReservedUnused(IOService, 62); OSMetaClassDefineReservedUnused(IOService, 63); +#endif