1/* 2 * Copyright (c) 1998-2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <IOKit/system.h> 30 31#include <IOKit/IOService.h> 32#include <libkern/OSDebug.h> 33#include <libkern/c++/OSContainers.h> 34#include <libkern/c++/OSKext.h> 35#include <libkern/c++/OSUnserialize.h> 36#include <IOKit/IOCatalogue.h> 37#include <IOKit/IOCommand.h> 38#include <IOKit/IODeviceTreeSupport.h> 39#include <IOKit/IODeviceMemory.h> 40#include <IOKit/IOInterrupts.h> 41#include <IOKit/IOInterruptController.h> 42#include <IOKit/IOPlatformExpert.h> 43#include <IOKit/IOMessage.h> 44#include <IOKit/IOLib.h> 45#include <IOKit/IOKitKeysPrivate.h> 46#include <IOKit/IOBSD.h> 47#include <IOKit/IOUserClient.h> 48#include <IOKit/IOWorkLoop.h> 49#include <IOKit/IOTimeStamp.h> 50#include <IOKit/IOHibernatePrivate.h> 51#include <mach/sync_policy.h> 52#include <IOKit/assert.h> 53#include <sys/errno.h> 54 55#include <machine/pal_routines.h> 56 57#define LOG kprintf 58//#define LOG IOLog 59#define MATCH_DEBUG 0 60#define OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x))) 61 62#include "IOServicePrivate.h" 63#include "IOKitKernelInternal.h" 64 65// take lockForArbitration before LOCKNOTIFY 66 67/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 68 69#define super IORegistryEntry 70 71OSDefineMetaClassAndStructors(IOService, IORegistryEntry) 72 73OSDefineMetaClassAndStructors(_IOServiceNotifier, IONotifier) 74 75OSDefineMetaClassAndStructors(_IOServiceInterestNotifier, IONotifier) 76 77OSDefineMetaClassAndStructors(_IOConfigThread, OSObject) 78 79OSDefineMetaClassAndStructors(_IOServiceJob, OSObject) 80 81OSDefineMetaClassAndStructors(IOResources, IOService) 82 83OSDefineMetaClassAndStructors(_IOOpenServiceIterator, OSIterator) 84 85OSDefineMetaClassAndAbstractStructors(IONotifier, OSObject) 86 87/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 88 89static IOPlatformExpert * gIOPlatform; 90static class IOPMrootDomain * gIOPMRootDomain; 91const IORegistryPlane * gIOServicePlane; 92const IORegistryPlane * gIOPowerPlane; 93const OSSymbol * gIODeviceMemoryKey; 94const OSSymbol * gIOInterruptControllersKey; 95const OSSymbol * gIOInterruptSpecifiersKey; 96 97const OSSymbol * gIOResourcesKey; 98const OSSymbol * gIOResourceMatchKey; 99const OSSymbol * gIOProviderClassKey; 100const OSSymbol * gIONameMatchKey; 101const OSSymbol * gIONameMatchedKey; 102const OSSymbol * gIOPropertyMatchKey; 103const OSSymbol * gIOLocationMatchKey; 104const OSSymbol * gIOParentMatchKey; 105const OSSymbol * gIOPathMatchKey; 106const OSSymbol * gIOMatchCategoryKey; 107const OSSymbol * gIODefaultMatchCategoryKey; 108const OSSymbol * gIOMatchedServiceCountKey; 109 110const OSSymbol * gIOMapperIDKey; 111const OSSymbol * gIOUserClientClassKey; 112const OSSymbol * gIOKitDebugKey; 113 114const OSSymbol * gIOCommandPoolSizeKey; 115 116const OSSymbol * gIOConsoleLockedKey; 117const OSSymbol * gIOConsoleUsersKey; 118const OSSymbol * gIOConsoleSessionUIDKey; 119const OSSymbol * gIOConsoleSessionAuditIDKey; 120const OSSymbol * gIOConsoleUsersSeedKey; 121const OSSymbol * gIOConsoleSessionOnConsoleKey; 122const OSSymbol * gIOConsoleSessionLoginDoneKey; 123const OSSymbol * gIOConsoleSessionSecureInputPIDKey; 124const OSSymbol * gIOConsoleSessionScreenLockedTimeKey; 125 126clock_sec_t gIOConsoleLockTime; 127static bool gIOConsoleLoggedIn; 128#if HIBERNATION 129static uint32_t gIOScreenLockState; 130#endif 131static IORegistryEntry * gIOChosenEntry; 132 133static int gIOResourceGenerationCount; 134 135const OSSymbol * gIOServiceKey; 136const OSSymbol * gIOPublishNotification; 137const OSSymbol * gIOFirstPublishNotification; 138const OSSymbol * gIOMatchedNotification; 139const OSSymbol * gIOFirstMatchNotification; 140const OSSymbol * gIOTerminatedNotification; 141 142const OSSymbol * gIOGeneralInterest; 143const OSSymbol * gIOBusyInterest; 144const OSSymbol * gIOAppPowerStateInterest; 145const OSSymbol * gIOPriorityPowerStateInterest; 146const OSSymbol * gIOConsoleSecurityInterest; 147 148static OSDictionary * gNotifications; 149static IORecursiveLock * gNotificationLock; 150 151static IOService * gIOResources; 152static IOService * gIOServiceRoot; 153 154static OSOrderedSet * gJobs; 155static semaphore_port_t gJobsSemaphore; 156static IOLock * gJobsLock; 157static int gOutstandingJobs; 158static int gNumConfigThreads; 159static int gNumWaitingThreads; 160static IOLock * gIOServiceBusyLock; 161 162static thread_t gIOTerminateThread; 163static UInt32 gIOTerminateWork; 164static OSArray * gIOTerminatePhase2List; 165static OSArray * gIOStopList; 166static OSArray * gIOStopProviderList; 167static OSArray * gIOFinalizeList; 168 169static SInt32 gIOConsoleUsersSeed; 170static OSData * gIOConsoleUsersSeedValue; 171 172extern const OSSymbol * gIODTPHandleKey; 173 174const OSSymbol * gIOPlatformSleepActionKey; 175const OSSymbol * gIOPlatformWakeActionKey; 176const OSSymbol * gIOPlatformQuiesceActionKey; 177const OSSymbol * gIOPlatformActiveActionKey; 178 179const OSSymbol * gIOPlatformFunctionHandlerSet; 180 181static IOLock * gIOConsoleUsersLock; 182static thread_call_t gIOConsoleLockCallout; 183 184/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 185 186#define LOCKREADNOTIFY() \ 187 IORecursiveLockLock( gNotificationLock ) 188#define LOCKWRITENOTIFY() \ 189 IORecursiveLockLock( gNotificationLock ) 190#define LOCKWRITE2READNOTIFY() 191#define UNLOCKNOTIFY() \ 192 IORecursiveLockUnlock( gNotificationLock ) 193#define SLEEPNOTIFY(event) \ 194 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT ) 195#define SLEEPNOTIFYTO(event, deadline) \ 196 IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT ) 197#define WAKEUPNOTIFY(event) \ 198 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false ) 199 200#define randomDelay() \ 201 int del = read_processor_clock(); \ 202 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \ 203 IOSleep( del ); 204 205/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 206 207#define queue_element(entry, element, type, field) do { \ 208 vm_address_t __ele = (vm_address_t) (entry); \ 209 __ele -= -4 + ((size_t)(&((type) 4)->field)); \ 210 (element) = (type) __ele; \ 211 } while(0) 212 213#define iterqueue(que, elt) \ 214 for (queue_entry_t elt = queue_first(que); \ 215 !queue_end(que, elt); \ 216 elt = queue_next(elt)) 217 218/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 219 220struct ArbitrationLockQueueElement { 221 queue_chain_t link; 222 IOThread thread; 223 IOService * service; 224 unsigned count; 225 bool required; 226 bool aborted; 227}; 228 229static queue_head_t gArbitrationLockQueueActive; 230static queue_head_t gArbitrationLockQueueWaiting; 231static queue_head_t gArbitrationLockQueueFree; 232static IOLock * gArbitrationLockQueueLock; 233 234bool IOService::isInactive( void ) const 235 { return( 0 != (kIOServiceInactiveState & getState())); } 236 237/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 238 239#if defined(__i386__) || defined(__x86_64__) 240 241// Only used by the intel implementation of 242// IOService::requireMaxBusStall(UInt32 ns) 243// IOService::requireMaxInterruptDelay(uint32_t ns) 244struct CpuDelayEntry 245{ 246 IOService * fService; 247 UInt32 fMaxDelay; 248 UInt32 fDelayType; 249}; 250 251enum { 252 kCpuDelayBusStall, kCpuDelayInterrupt, 253 kCpuNumDelayTypes 254}; 255 256static OSData *sCpuDelayData = OSData::withCapacity(8 * sizeof(CpuDelayEntry)); 257static IORecursiveLock *sCpuDelayLock = IORecursiveLockAlloc(); 258static OSArray *sCpuLatencyHandlers[kCpuNumDelayTypes]; 259const OSSymbol *sCPULatencyFunctionName[kCpuNumDelayTypes]; 260 261static void 262requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType); 263static IOReturn 264setLatencyHandler(UInt32 delayType, IOService * target, bool enable); 265 266#endif /* defined(__i386__) || defined(__x86_64__) */ 267 268/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 269 270void IOService::initialize( void ) 271{ 272 kern_return_t err; 273 274 gIOServicePlane = IORegistryEntry::makePlane( kIOServicePlane ); 275 gIOPowerPlane = IORegistryEntry::makePlane( kIOPowerPlane ); 276 277 gIOProviderClassKey = OSSymbol::withCStringNoCopy( kIOProviderClassKey ); 278 gIONameMatchKey = OSSymbol::withCStringNoCopy( kIONameMatchKey ); 279 gIONameMatchedKey = OSSymbol::withCStringNoCopy( kIONameMatchedKey ); 280 gIOPropertyMatchKey = OSSymbol::withCStringNoCopy( kIOPropertyMatchKey ); 281 gIOPathMatchKey = OSSymbol::withCStringNoCopy( kIOPathMatchKey ); 282 gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey ); 283 gIOParentMatchKey = OSSymbol::withCStringNoCopy( kIOParentMatchKey ); 284 285 gIOMatchCategoryKey = OSSymbol::withCStringNoCopy( kIOMatchCategoryKey ); 286 gIODefaultMatchCategoryKey = OSSymbol::withCStringNoCopy( 287 kIODefaultMatchCategoryKey ); 288 gIOMatchedServiceCountKey = OSSymbol::withCStringNoCopy( 289 kIOMatchedServiceCountKey ); 290 291 gIOUserClientClassKey = OSSymbol::withCStringNoCopy( kIOUserClientClassKey ); 292 293 gIOResourcesKey = OSSymbol::withCStringNoCopy( kIOResourcesClass ); 294 gIOResourceMatchKey = OSSymbol::withCStringNoCopy( kIOResourceMatchKey ); 295 296 gIODeviceMemoryKey = OSSymbol::withCStringNoCopy( "IODeviceMemory" ); 297 gIOInterruptControllersKey 298 = OSSymbol::withCStringNoCopy("IOInterruptControllers"); 299 gIOInterruptSpecifiersKey 300 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers"); 301 302 gIOMapperIDKey = OSSymbol::withCStringNoCopy(kIOMapperIDKey); 303 304 gIOKitDebugKey = OSSymbol::withCStringNoCopy( kIOKitDebugKey ); 305 306 gIOCommandPoolSizeKey = OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey ); 307 308 gIOGeneralInterest = OSSymbol::withCStringNoCopy( kIOGeneralInterest ); 309 gIOBusyInterest = OSSymbol::withCStringNoCopy( kIOBusyInterest ); 310 gIOAppPowerStateInterest = OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest ); 311 gIOPriorityPowerStateInterest = OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest ); 312 gIOConsoleSecurityInterest = OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest ); 313 314 gNotifications = OSDictionary::withCapacity( 1 ); 315 gIOPublishNotification = OSSymbol::withCStringNoCopy( 316 kIOPublishNotification ); 317 gIOFirstPublishNotification = OSSymbol::withCStringNoCopy( 318 kIOFirstPublishNotification ); 319 gIOMatchedNotification = OSSymbol::withCStringNoCopy( 320 kIOMatchedNotification ); 321 gIOFirstMatchNotification = OSSymbol::withCStringNoCopy( 322 kIOFirstMatchNotification ); 323 gIOTerminatedNotification = OSSymbol::withCStringNoCopy( 324 kIOTerminatedNotification ); 325 gIOServiceKey = OSSymbol::withCStringNoCopy( kIOServiceClass); 326 327 gIOConsoleLockedKey = OSSymbol::withCStringNoCopy( kIOConsoleLockedKey); 328 gIOConsoleUsersKey = OSSymbol::withCStringNoCopy( kIOConsoleUsersKey); 329 gIOConsoleSessionUIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey); 330 gIOConsoleSessionAuditIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey); 331 332 gIOConsoleUsersSeedKey = OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey); 333 gIOConsoleSessionOnConsoleKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey); 334 gIOConsoleSessionLoginDoneKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey); 335 gIOConsoleSessionSecureInputPIDKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey); 336 gIOConsoleSessionScreenLockedTimeKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey); 337 338 gIOConsoleUsersSeedValue = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed)); 339 340 gIOPlatformSleepActionKey = OSSymbol::withCStringNoCopy(kIOPlatformSleepActionKey); 341 gIOPlatformWakeActionKey = OSSymbol::withCStringNoCopy(kIOPlatformWakeActionKey); 342 gIOPlatformQuiesceActionKey = OSSymbol::withCStringNoCopy(kIOPlatformQuiesceActionKey); 343 gIOPlatformActiveActionKey = OSSymbol::withCStringNoCopy(kIOPlatformActiveActionKey); 344 345 gIOPlatformFunctionHandlerSet = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet); 346#if defined(__i386__) || defined(__x86_64__) 347 sCPULatencyFunctionName[kCpuDelayBusStall] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay); 348 sCPULatencyFunctionName[kCpuDelayInterrupt] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay); 349#endif 350 gNotificationLock = IORecursiveLockAlloc(); 351 352 assert( gIOServicePlane && gIODeviceMemoryKey 353 && gIOInterruptControllersKey && gIOInterruptSpecifiersKey 354 && gIOResourcesKey && gNotifications && gNotificationLock 355 && gIOProviderClassKey && gIONameMatchKey && gIONameMatchedKey 356 && gIOMatchCategoryKey && gIODefaultMatchCategoryKey 357 && gIOPublishNotification && gIOMatchedNotification 358 && gIOTerminatedNotification && gIOServiceKey 359 && gIOConsoleUsersKey && gIOConsoleSessionUIDKey 360 && gIOConsoleSessionOnConsoleKey && gIOConsoleSessionSecureInputPIDKey 361 && gIOConsoleUsersSeedKey && gIOConsoleUsersSeedValue); 362 363 gJobsLock = IOLockAlloc(); 364 gJobs = OSOrderedSet::withCapacity( 10 ); 365 366 gIOServiceBusyLock = IOLockAlloc(); 367 368 gIOConsoleUsersLock = IOLockAlloc(); 369 370 err = semaphore_create(kernel_task, &gJobsSemaphore, SYNC_POLICY_FIFO, 0); 371 372 gIOConsoleLockCallout = thread_call_allocate(&IOService::consoleLockTimer, NULL); 373 374 IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey, kOSBooleanTrue); 375 376 assert( gIOServiceBusyLock && gJobs && gJobsLock && gIOConsoleUsersLock 377 && gIOConsoleLockCallout && (err == KERN_SUCCESS) ); 378 379 gIOResources = IOResources::resources(); 380 assert( gIOResources ); 381 382 gArbitrationLockQueueLock = IOLockAlloc(); 383 queue_init(&gArbitrationLockQueueActive); 384 queue_init(&gArbitrationLockQueueWaiting); 385 queue_init(&gArbitrationLockQueueFree); 386 387 assert( gArbitrationLockQueueLock ); 388 389 gIOTerminatePhase2List = OSArray::withCapacity( 2 ); 390 gIOStopList = OSArray::withCapacity( 16 ); 391 gIOStopProviderList = OSArray::withCapacity( 16 ); 392 gIOFinalizeList = OSArray::withCapacity( 16 ); 393 assert( gIOTerminatePhase2List && gIOStopList && gIOStopProviderList && gIOFinalizeList ); 394} 395 396/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 397 398#if IOMATCHDEBUG 399static UInt64 getDebugFlags( OSDictionary * props ) 400{ 401 OSNumber * debugProp; 402 UInt64 debugFlags; 403 404 debugProp = OSDynamicCast( OSNumber, 405 props->getObject( gIOKitDebugKey )); 406 if( debugProp) 407 debugFlags = debugProp->unsigned64BitValue(); 408 else 409 debugFlags = gIOKitDebug; 410 411 return( debugFlags ); 412} 413#endif 414 415/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 416 417// Probe a matched service and return an instance to be started. 418// The default score is from the property table, & may be altered 419// during probe to change the start order. 420 421IOService * IOService::probe( IOService * provider, 422 SInt32 * score ) 423{ 424 return( this ); 425} 426 427bool IOService::start( IOService * provider ) 428{ 429 return( true ); 430} 431 432void IOService::stop( IOService * provider ) 433{ 434} 435 436void IOService::free( void ) 437{ 438 requireMaxBusStall(0); 439 requireMaxInterruptDelay(0); 440 if( getPropertyTable()) 441 unregisterAllInterest(); 442 PMfree(); 443 super::free(); 444} 445 446/* 447 * Attach in service plane 448 */ 449bool IOService::attach( IOService * provider ) 450{ 451 bool ok; 452 453 if( provider) { 454 455 if( gIOKitDebug & kIOLogAttach) 456 LOG( "%s::attach(%s)\n", getName(), 457 provider->getName()); 458 459 provider->lockForArbitration(); 460 if( provider->__state[0] & kIOServiceInactiveState) 461 ok = false; 462 else 463 ok = attachToParent( provider, gIOServicePlane); 464 provider->unlockForArbitration(); 465 466 } else { 467 gIOServiceRoot = this; 468 ok = attachToParent( getRegistryRoot(), gIOServicePlane); 469 } 470 471 if (ok && !__provider) (void) getProvider(); 472 473 return( ok ); 474} 475 476IOService * IOService::getServiceRoot( void ) 477{ 478 return( gIOServiceRoot ); 479} 480 481void IOService::detach( IOService * provider ) 482{ 483 IOService * newProvider = 0; 484 SInt32 busy; 485 bool adjParent; 486 487 if( gIOKitDebug & kIOLogAttach) 488 LOG("%s::detach(%s)\n", getName(), provider->getName()); 489 490 lockForArbitration(); 491 492 adjParent = ((busy = (__state[1] & kIOServiceBusyStateMask)) 493 && (provider == getProvider())); 494 495 detachFromParent( provider, gIOServicePlane ); 496 497 if( busy) { 498 newProvider = getProvider(); 499 if( busy && (__state[1] & kIOServiceTermPhase3State) && (0 == newProvider)) 500 _adjustBusy( -busy ); 501 } 502 503 if (kIOServiceInactiveState & __state[0]) { 504 getMetaClass()->removeInstance(this); 505 } 506 507 unlockForArbitration(); 508 509 if( newProvider) { 510 newProvider->lockForArbitration(); 511 newProvider->_adjustBusy(1); 512 newProvider->unlockForArbitration(); 513 } 514 515 // check for last client detach from a terminated service 516 if( provider->lockForArbitration( true )) { 517 if( adjParent) 518 provider->_adjustBusy( -1 ); 519 if( (provider->__state[1] & kIOServiceTermPhase3State) 520 && (0 == provider->getClient())) { 521 provider->scheduleFinalize(); 522 } 523 provider->unlockForArbitration(); 524 } 525} 526 527/* 528 * Register instance - publish it for matching 529 */ 530 531void IOService::registerService( IOOptionBits options ) 532{ 533 char * pathBuf; 534 const char * path; 535 char * skip; 536 int len; 537 enum { kMaxPathLen = 256 }; 538 enum { kMaxChars = 63 }; 539 540 IORegistryEntry * parent = this; 541 IORegistryEntry * root = getRegistryRoot(); 542 while( parent && (parent != root)) 543 parent = parent->getParentEntry( gIOServicePlane); 544 545 if( parent != root) { 546 IOLog("%s: not registry member at registerService()\n", getName()); 547 return; 548 } 549 550 // Allow the Platform Expert to adjust this node. 551 if( gIOPlatform && (!gIOPlatform->platformAdjustService(this))) 552 return; 553 554 if( (this != gIOResources) 555 && (kIOLogRegister & gIOKitDebug)) { 556 557 pathBuf = (char *) IOMalloc( kMaxPathLen ); 558 559 IOLog( "Registering: " ); 560 561 len = kMaxPathLen; 562 if( pathBuf && getPath( pathBuf, &len, gIOServicePlane)) { 563 564 path = pathBuf; 565 if( len > kMaxChars) { 566 IOLog(".."); 567 len -= kMaxChars; 568 path += len; 569 if( (skip = strchr( path, '/'))) 570 path = skip; 571 } 572 } else 573 path = getName(); 574 575 IOLog( "%s\n", path ); 576 577 if( pathBuf) 578 IOFree( pathBuf, kMaxPathLen ); 579 } 580 581 startMatching( options ); 582} 583 584void IOService::startMatching( IOOptionBits options ) 585{ 586 IOService * provider; 587 UInt32 prevBusy = 0; 588 bool needConfig; 589 bool needWake = false; 590 bool ok; 591 bool sync; 592 bool waitAgain; 593 594 lockForArbitration(); 595 596 sync = (options & kIOServiceSynchronous) 597 || ((provider = getProvider()) 598 && (provider->__state[1] & kIOServiceSynchronousState)); 599 600 if ( options & kIOServiceAsynchronous ) 601 sync = false; 602 603 needConfig = (0 == (__state[1] & (kIOServiceNeedConfigState | kIOServiceConfigState))) 604 && (0 == (__state[0] & kIOServiceInactiveState)); 605 606 __state[1] |= kIOServiceNeedConfigState; 607 608// __state[0] &= ~kIOServiceInactiveState; 609 610// if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n", 611// OSKernelStackRemaining(), getName()); 612 613 if( needConfig) { 614 needWake = (0 != (kIOServiceSyncPubState & __state[1])); 615 } 616 617 if( sync) 618 __state[1] |= kIOServiceSynchronousState; 619 else 620 __state[1] &= ~kIOServiceSynchronousState; 621 622 if( needConfig) prevBusy = _adjustBusy( 1 ); 623 624 unlockForArbitration(); 625 626 if( needConfig) { 627 628 if( needWake) { 629 IOLockLock( gIOServiceBusyLock ); 630 thread_wakeup( (event_t) this/*&__state[1]*/ ); 631 IOLockUnlock( gIOServiceBusyLock ); 632 633 } else if( !sync || (kIOServiceAsynchronous & options)) { 634 635 ok = (0 != _IOServiceJob::startJob( this, kMatchNubJob, options )); 636 637 } else do { 638 639 if( (__state[1] & kIOServiceNeedConfigState)) 640 doServiceMatch( options ); 641 642 lockForArbitration(); 643 IOLockLock( gIOServiceBusyLock ); 644 645 waitAgain = ((prevBusy < (__state[1] & kIOServiceBusyStateMask)) 646 && (0 == (__state[0] & kIOServiceInactiveState))); 647 648 if( waitAgain) 649 __state[1] |= kIOServiceSyncPubState | kIOServiceBusyWaiterState; 650 else 651 __state[1] &= ~kIOServiceSyncPubState; 652 653 unlockForArbitration(); 654 655 if( waitAgain) 656 assert_wait( (event_t) this/*&__state[1]*/, THREAD_UNINT); 657 658 IOLockUnlock( gIOServiceBusyLock ); 659 if( waitAgain) 660 thread_block(THREAD_CONTINUE_NULL); 661 662 } while( waitAgain ); 663 } 664} 665 666IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables ) 667{ 668 OSDictionary * table; 669 OSSet * set; 670 OSSet * allSet = 0; 671 IOService * service; 672#if IOMATCHDEBUG 673 SInt32 count = 0; 674#endif 675 676 newTables->retain(); 677 678 while( (table = (OSDictionary *) newTables->getFirstObject())) { 679 680 LOCKWRITENOTIFY(); 681 set = (OSSet *) copyExistingServices( table, 682 kIOServiceRegisteredState, 683 kIOServiceExistingSet); 684 UNLOCKNOTIFY(); 685 if( set) { 686 687#if IOMATCHDEBUG 688 count += set->getCount(); 689#endif 690 if (allSet) { 691 allSet->merge((const OSSet *) set); 692 set->release(); 693 } 694 else 695 allSet = set; 696 } 697 698#if IOMATCHDEBUG 699 if( getDebugFlags( table ) & kIOLogMatch) 700 LOG("Matching service count = %ld\n", (long)count); 701#endif 702 newTables->removeObject(table); 703 } 704 705 if (allSet) { 706 while( (service = (IOService *) allSet->getAnyObject())) { 707 service->startMatching(kIOServiceAsynchronous); 708 allSet->removeObject(service); 709 } 710 allSet->release(); 711 } 712 713 newTables->release(); 714 715 return( kIOReturnSuccess ); 716} 717 718 _IOServiceJob * _IOServiceJob::startJob( IOService * nub, int type, 719 IOOptionBits options ) 720{ 721 _IOServiceJob * job; 722 723 job = new _IOServiceJob; 724 if( job && !job->init()) { 725 job->release(); 726 job = 0; 727 } 728 729 if( job) { 730 job->type = type; 731 job->nub = nub; 732 job->options = options; 733 nub->retain(); // thread will release() 734 pingConfig( job ); 735 } 736 737 return( job ); 738} 739 740/* 741 * Called on a registered service to see if it matches 742 * a property table. 743 */ 744 745bool IOService::matchPropertyTable( OSDictionary * table, SInt32 * score ) 746{ 747 return( matchPropertyTable(table) ); 748} 749 750bool IOService::matchPropertyTable( OSDictionary * table ) 751{ 752 return( true ); 753} 754 755/* 756 * Called on a matched service to allocate resources 757 * before first driver is attached. 758 */ 759 760IOReturn IOService::getResources( void ) 761{ 762 return( kIOReturnSuccess); 763} 764 765/* 766 * Client/provider accessors 767 */ 768 769IOService * IOService::getProvider( void ) const 770{ 771 IOService * self = (IOService *) this; 772 IOService * parent; 773 SInt32 generation; 774 775 generation = getGenerationCount(); 776 if( __providerGeneration == generation) 777 return( __provider ); 778 779 parent = (IOService *) getParentEntry( gIOServicePlane); 780 if( parent == IORegistryEntry::getRegistryRoot()) 781 /* root is not an IOService */ 782 parent = 0; 783 784 self->__provider = parent; 785 OSMemoryBarrier(); 786 // save the count from before call to getParentEntry() 787 self->__providerGeneration = generation; 788 789 return( parent ); 790} 791 792IOWorkLoop * IOService::getWorkLoop() const 793{ 794 IOService *provider = getProvider(); 795 796 if (provider) 797 return provider->getWorkLoop(); 798 else 799 return 0; 800} 801 802OSIterator * IOService::getProviderIterator( void ) const 803{ 804 return( getParentIterator( gIOServicePlane)); 805} 806 807IOService * IOService::getClient( void ) const 808{ 809 return( (IOService *) getChildEntry( gIOServicePlane)); 810} 811 812OSIterator * IOService::getClientIterator( void ) const 813{ 814 return( getChildIterator( gIOServicePlane)); 815} 816 817OSIterator * _IOOpenServiceIterator::iterator( OSIterator * _iter, 818 const IOService * client, 819 const IOService * provider ) 820{ 821 _IOOpenServiceIterator * inst; 822 823 if( !_iter) 824 return( 0 ); 825 826 inst = new _IOOpenServiceIterator; 827 828 if( inst && !inst->init()) { 829 inst->release(); 830 inst = 0; 831 } 832 if( inst) { 833 inst->iter = _iter; 834 inst->client = client; 835 inst->provider = provider; 836 } 837 838 return( inst ); 839} 840 841void _IOOpenServiceIterator::free() 842{ 843 iter->release(); 844 if( last) 845 last->unlockForArbitration(); 846 OSIterator::free(); 847} 848 849OSObject * _IOOpenServiceIterator::getNextObject() 850{ 851 IOService * next; 852 853 if( last) 854 last->unlockForArbitration(); 855 856 while( (next = (IOService *) iter->getNextObject())) { 857 858 next->lockForArbitration(); 859 if( (client && (next->isOpen( client ))) 860 || (provider && (provider->isOpen( next ))) ) 861 break; 862 next->unlockForArbitration(); 863 } 864 865 last = next; 866 867 return( next ); 868} 869 870bool _IOOpenServiceIterator::isValid() 871{ 872 return( iter->isValid() ); 873} 874 875void _IOOpenServiceIterator::reset() 876{ 877 if( last) { 878 last->unlockForArbitration(); 879 last = 0; 880 } 881 iter->reset(); 882} 883 884OSIterator * IOService::getOpenProviderIterator( void ) const 885{ 886 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 )); 887} 888 889OSIterator * IOService::getOpenClientIterator( void ) const 890{ 891 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this )); 892} 893 894 895IOReturn IOService::callPlatformFunction( const OSSymbol * functionName, 896 bool waitForFunction, 897 void *param1, void *param2, 898 void *param3, void *param4 ) 899{ 900 IOReturn result = kIOReturnUnsupported; 901 IOService *provider; 902 903 if (gIOPlatformFunctionHandlerSet == functionName) 904 { 905#if defined(__i386__) || defined(__x86_64__) 906 const OSSymbol * functionHandlerName = (const OSSymbol *) param1; 907 IOService * target = (IOService *) param2; 908 bool enable = (param3 != 0); 909 910 if (sCPULatencyFunctionName[kCpuDelayBusStall] == functionHandlerName) 911 result = setLatencyHandler(kCpuDelayBusStall, target, enable); 912 else if (sCPULatencyFunctionName[kCpuDelayInterrupt] == param1) 913 result = setLatencyHandler(kCpuDelayInterrupt, target, enable); 914#endif /* defined(__i386__) || defined(__x86_64__) */ 915 } 916 917 if ((kIOReturnUnsupported == result) && (provider = getProvider())) { 918 result = provider->callPlatformFunction(functionName, waitForFunction, 919 param1, param2, param3, param4); 920 } 921 922 return result; 923} 924 925IOReturn IOService::callPlatformFunction( const char * functionName, 926 bool waitForFunction, 927 void *param1, void *param2, 928 void *param3, void *param4 ) 929{ 930 IOReturn result = kIOReturnNoMemory; 931 const OSSymbol *functionSymbol = OSSymbol::withCString(functionName); 932 933 if (functionSymbol != 0) { 934 result = callPlatformFunction(functionSymbol, waitForFunction, 935 param1, param2, param3, param4); 936 functionSymbol->release(); 937 } 938 939 return result; 940} 941 942 943/* 944 * Accessors for global services 945 */ 946 947IOPlatformExpert * IOService::getPlatform( void ) 948{ 949 return( gIOPlatform); 950} 951 952class IOPMrootDomain * IOService::getPMRootDomain( void ) 953{ 954 return( gIOPMRootDomain); 955} 956 957IOService * IOService::getResourceService( void ) 958{ 959 return( gIOResources ); 960} 961 962void IOService::setPlatform( IOPlatformExpert * platform) 963{ 964 gIOPlatform = platform; 965 gIOResources->attachToParent( gIOServiceRoot, gIOServicePlane ); 966} 967 968void IOService::setPMRootDomain( class IOPMrootDomain * rootDomain) 969{ 970 gIOPMRootDomain = rootDomain; 971 publishResource("IOKit"); 972} 973 974/* 975 * Stacking change 976 */ 977 978bool IOService::lockForArbitration( bool isSuccessRequired ) 979{ 980 bool found; 981 bool success; 982 ArbitrationLockQueueElement * element; 983 ArbitrationLockQueueElement * active; 984 ArbitrationLockQueueElement * waiting; 985 986 enum { kPutOnFreeQueue, kPutOnActiveQueue, kPutOnWaitingQueue } action; 987 988 // lock global access 989 IOTakeLock( gArbitrationLockQueueLock ); 990 991 // obtain an unused queue element 992 if( !queue_empty( &gArbitrationLockQueueFree )) { 993 queue_remove_first( &gArbitrationLockQueueFree, 994 element, 995 ArbitrationLockQueueElement *, 996 link ); 997 } else { 998 element = IONew( ArbitrationLockQueueElement, 1 ); 999 assert( element ); 1000 } 1001 1002 // prepare the queue element 1003 element->thread = IOThreadSelf(); 1004 element->service = this; 1005 element->count = 1; 1006 element->required = isSuccessRequired; 1007 element->aborted = false; 1008 1009 // determine whether this object is already locked (ie. on active queue) 1010 found = false; 1011 queue_iterate( &gArbitrationLockQueueActive, 1012 active, 1013 ArbitrationLockQueueElement *, 1014 link ) 1015 { 1016 if( active->service == element->service ) { 1017 found = true; 1018 break; 1019 } 1020 } 1021 1022 if( found ) { // this object is already locked 1023 1024 // determine whether it is the same or a different thread trying to lock 1025 if( active->thread != element->thread ) { // it is a different thread 1026 1027 ArbitrationLockQueueElement * victim = 0; 1028 1029 // before placing this new thread on the waiting queue, we look for 1030 // a deadlock cycle... 1031 1032 while( 1 ) { 1033 // determine whether the active thread holding the object we 1034 // want is waiting for another object to be unlocked 1035 found = false; 1036 queue_iterate( &gArbitrationLockQueueWaiting, 1037 waiting, 1038 ArbitrationLockQueueElement *, 1039 link ) 1040 { 1041 if( waiting->thread == active->thread ) { 1042 assert( false == waiting->aborted ); 1043 found = true; 1044 break; 1045 } 1046 } 1047 1048 if( found ) { // yes, active thread waiting for another object 1049 1050 // this may be a candidate for rejection if the required 1051 // flag is not set, should we detect a deadlock later on 1052 if( false == waiting->required ) 1053 victim = waiting; 1054 1055 // find the thread that is holding this other object, that 1056 // is blocking the active thread from proceeding (fun :-) 1057 found = false; 1058 queue_iterate( &gArbitrationLockQueueActive, 1059 active, // (reuse active queue element) 1060 ArbitrationLockQueueElement *, 1061 link ) 1062 { 1063 if( active->service == waiting->service ) { 1064 found = true; 1065 break; 1066 } 1067 } 1068 1069 // someone must be holding it or it wouldn't be waiting 1070 assert( found ); 1071 1072 if( active->thread == element->thread ) { 1073 1074 // doh, it's waiting for the thread that originated 1075 // this whole lock (ie. current thread) -> deadlock 1076 if( false == element->required ) { // willing to fail? 1077 1078 // the originating thread doesn't have the required 1079 // flag, so it can fail 1080 success = false; // (fail originating lock request) 1081 break; // (out of while) 1082 1083 } else { // originating thread is not willing to fail 1084 1085 // see if we came across a waiting thread that did 1086 // not have the 'required' flag set: we'll fail it 1087 if( victim ) { 1088 1089 // we do have a willing victim, fail it's lock 1090 victim->aborted = true; 1091 1092 // take the victim off the waiting queue 1093 queue_remove( &gArbitrationLockQueueWaiting, 1094 victim, 1095 ArbitrationLockQueueElement *, 1096 link ); 1097 1098 // wake the victim 1099 IOLockWakeup( gArbitrationLockQueueLock, 1100 victim, 1101 /* one thread */ true ); 1102 1103 // allow this thread to proceed (ie. wait) 1104 success = true; // (put request on wait queue) 1105 break; // (out of while) 1106 } else { 1107 1108 // all the waiting threads we came across in 1109 // finding this loop had the 'required' flag 1110 // set, so we've got a deadlock we can't avoid 1111 panic("I/O Kit: Unrecoverable deadlock."); 1112 } 1113 } 1114 } else { 1115 // repeat while loop, redefining active thread to be the 1116 // thread holding "this other object" (see above), and 1117 // looking for threads waiting on it; note the active 1118 // variable points to "this other object" already... so 1119 // there nothing to do in this else clause. 1120 } 1121 } else { // no, active thread is not waiting for another object 1122 1123 success = true; // (put request on wait queue) 1124 break; // (out of while) 1125 } 1126 } // while forever 1127 1128 if( success ) { // put the request on the waiting queue? 1129 kern_return_t wait_result; 1130 1131 // place this thread on the waiting queue and put it to sleep; 1132 // we place it at the tail of the queue... 1133 queue_enter( &gArbitrationLockQueueWaiting, 1134 element, 1135 ArbitrationLockQueueElement *, 1136 link ); 1137 1138 // declare that this thread will wait for a given event 1139restart_sleep: wait_result = assert_wait( element, 1140 element->required ? THREAD_UNINT 1141 : THREAD_INTERRUPTIBLE ); 1142 1143 // unlock global access 1144 IOUnlock( gArbitrationLockQueueLock ); 1145 1146 // put thread to sleep, waiting for our event to fire... 1147 if (wait_result == THREAD_WAITING) 1148 wait_result = thread_block(THREAD_CONTINUE_NULL); 1149 1150 1151 // ...and we've been woken up; we might be in one of two states: 1152 // (a) we've been aborted and our queue element is not on 1153 // any of the three queues, but is floating around 1154 // (b) we're allowed to proceed with the lock and we have 1155 // already been moved from the waiting queue to the 1156 // active queue. 1157 // ...plus a 3rd state, should the thread have been interrupted: 1158 // (c) we're still on the waiting queue 1159 1160 // determine whether we were interrupted out of our sleep 1161 if( THREAD_INTERRUPTED == wait_result ) { 1162 1163 // re-lock global access 1164 IOTakeLock( gArbitrationLockQueueLock ); 1165 1166 // determine whether we're still on the waiting queue 1167 found = false; 1168 queue_iterate( &gArbitrationLockQueueWaiting, 1169 waiting, // (reuse waiting queue element) 1170 ArbitrationLockQueueElement *, 1171 link ) 1172 { 1173 if( waiting == element ) { 1174 found = true; 1175 break; 1176 } 1177 } 1178 1179 if( found ) { // yes, we're still on the waiting queue 1180 1181 // determine whether we're willing to fail 1182 if( false == element->required ) { 1183 1184 // mark us as aborted 1185 element->aborted = true; 1186 1187 // take us off the waiting queue 1188 queue_remove( &gArbitrationLockQueueWaiting, 1189 element, 1190 ArbitrationLockQueueElement *, 1191 link ); 1192 } else { // we are not willing to fail 1193 1194 // ignore interruption, go back to sleep 1195 goto restart_sleep; 1196 } 1197 } 1198 1199 // unlock global access 1200 IOUnlock( gArbitrationLockQueueLock ); 1201 1202 // proceed as though this were a normal wake up 1203 wait_result = THREAD_AWAKENED; 1204 } 1205 1206 assert( THREAD_AWAKENED == wait_result ); 1207 1208 // determine whether we've been aborted while we were asleep 1209 if( element->aborted ) { 1210 assert( false == element->required ); 1211 1212 // re-lock global access 1213 IOTakeLock( gArbitrationLockQueueLock ); 1214 1215 action = kPutOnFreeQueue; 1216 success = false; 1217 } else { // we weren't aborted, so we must be ready to go :-) 1218 1219 // we've already been moved from waiting to active queue 1220 return true; 1221 } 1222 1223 } else { // the lock request is to be failed 1224 1225 // return unused queue element to queue 1226 action = kPutOnFreeQueue; 1227 } 1228 } else { // it is the same thread, recursive access is allowed 1229 1230 // add one level of recursion 1231 active->count++; 1232 1233 // return unused queue element to queue 1234 action = kPutOnFreeQueue; 1235 success = true; 1236 } 1237 } else { // this object is not already locked, so let this thread through 1238 action = kPutOnActiveQueue; 1239 success = true; 1240 } 1241 1242 // put the new element on a queue 1243 if( kPutOnActiveQueue == action ) { 1244 queue_enter( &gArbitrationLockQueueActive, 1245 element, 1246 ArbitrationLockQueueElement *, 1247 link ); 1248 } else if( kPutOnFreeQueue == action ) { 1249 queue_enter( &gArbitrationLockQueueFree, 1250 element, 1251 ArbitrationLockQueueElement *, 1252 link ); 1253 } else { 1254 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above 1255 } 1256 1257 // unlock global access 1258 IOUnlock( gArbitrationLockQueueLock ); 1259 1260 return( success ); 1261} 1262 1263void IOService::unlockForArbitration( void ) 1264{ 1265 bool found; 1266 ArbitrationLockQueueElement * element; 1267 1268 // lock global access 1269 IOTakeLock( gArbitrationLockQueueLock ); 1270 1271 // find the lock element for this object (ie. on active queue) 1272 found = false; 1273 queue_iterate( &gArbitrationLockQueueActive, 1274 element, 1275 ArbitrationLockQueueElement *, 1276 link ) 1277 { 1278 if( element->service == this ) { 1279 found = true; 1280 break; 1281 } 1282 } 1283 1284 assert( found ); 1285 1286 // determine whether the lock has been taken recursively 1287 if( element->count > 1 ) { 1288 // undo one level of recursion 1289 element->count--; 1290 1291 } else { 1292 1293 // remove it from the active queue 1294 queue_remove( &gArbitrationLockQueueActive, 1295 element, 1296 ArbitrationLockQueueElement *, 1297 link ); 1298 1299 // put it on the free queue 1300 queue_enter( &gArbitrationLockQueueFree, 1301 element, 1302 ArbitrationLockQueueElement *, 1303 link ); 1304 1305 // determine whether a thread is waiting for object (head to tail scan) 1306 found = false; 1307 queue_iterate( &gArbitrationLockQueueWaiting, 1308 element, 1309 ArbitrationLockQueueElement *, 1310 link ) 1311 { 1312 if( element->service == this ) { 1313 found = true; 1314 break; 1315 } 1316 } 1317 1318 if ( found ) { // we found an interested thread on waiting queue 1319 1320 // remove it from the waiting queue 1321 queue_remove( &gArbitrationLockQueueWaiting, 1322 element, 1323 ArbitrationLockQueueElement *, 1324 link ); 1325 1326 // put it on the active queue 1327 queue_enter( &gArbitrationLockQueueActive, 1328 element, 1329 ArbitrationLockQueueElement *, 1330 link ); 1331 1332 // wake the waiting thread 1333 IOLockWakeup( gArbitrationLockQueueLock, 1334 element, 1335 /* one thread */ true ); 1336 } 1337 } 1338 1339 // unlock global access 1340 IOUnlock( gArbitrationLockQueueLock ); 1341} 1342 1343void IOService::applyToProviders( IOServiceApplierFunction applier, 1344 void * context ) 1345{ 1346 applyToParents( (IORegistryEntryApplierFunction) applier, 1347 context, gIOServicePlane ); 1348} 1349 1350void IOService::applyToClients( IOServiceApplierFunction applier, 1351 void * context ) 1352{ 1353 applyToChildren( (IORegistryEntryApplierFunction) applier, 1354 context, gIOServicePlane ); 1355} 1356 1357 1358/* 1359 * Client messages 1360 */ 1361 1362 1363// send a message to a client or interested party of this service 1364IOReturn IOService::messageClient( UInt32 type, OSObject * client, 1365 void * argument, vm_size_t argSize ) 1366{ 1367 IOReturn ret; 1368 IOService * service; 1369 _IOServiceInterestNotifier * notify; 1370 1371 if( (service = OSDynamicCast( IOService, client))) 1372 ret = service->message( type, this, argument ); 1373 1374 else if( (notify = OSDynamicCast( _IOServiceInterestNotifier, client))) { 1375 1376 _IOServiceNotifierInvocation invocation; 1377 bool willNotify; 1378 1379 invocation.thread = current_thread(); 1380 1381 LOCKWRITENOTIFY(); 1382 willNotify = (0 != (kIOServiceNotifyEnable & notify->state)); 1383 1384 if( willNotify) { 1385 queue_enter( ¬ify->handlerInvocations, &invocation, 1386 _IOServiceNotifierInvocation *, link ); 1387 } 1388 UNLOCKNOTIFY(); 1389 1390 if( willNotify) { 1391 1392 ret = (*notify->handler)( notify->target, notify->ref, 1393 type, this, argument, argSize ); 1394 1395 LOCKWRITENOTIFY(); 1396 queue_remove( ¬ify->handlerInvocations, &invocation, 1397 _IOServiceNotifierInvocation *, link ); 1398 if( kIOServiceNotifyWaiter & notify->state) { 1399 notify->state &= ~kIOServiceNotifyWaiter; 1400 WAKEUPNOTIFY( notify ); 1401 } 1402 UNLOCKNOTIFY(); 1403 1404 } else 1405 ret = kIOReturnSuccess; 1406 1407 } else 1408 ret = kIOReturnBadArgument; 1409 1410 return( ret ); 1411} 1412 1413static void 1414applyToInterestNotifiers(const IORegistryEntry *target, 1415 const OSSymbol * typeOfInterest, 1416 OSObjectApplierFunction applier, 1417 void * context ) 1418{ 1419 OSArray * copyArray = 0; 1420 1421 LOCKREADNOTIFY(); 1422 1423 IOCommand *notifyList = 1424 OSDynamicCast( IOCommand, target->getProperty( typeOfInterest )); 1425 1426 if( notifyList) { 1427 copyArray = OSArray::withCapacity(1); 1428 1429 // iterate over queue, entry is set to each element in the list 1430 iterqueue(¬ifyList->fCommandChain, entry) { 1431 _IOServiceInterestNotifier * notify; 1432 1433 queue_element(entry, notify, _IOServiceInterestNotifier *, chain); 1434 copyArray->setObject(notify); 1435 } 1436 } 1437 UNLOCKNOTIFY(); 1438 1439 if( copyArray) { 1440 unsigned int index; 1441 OSObject * next; 1442 1443 for( index = 0; (next = copyArray->getObject( index )); index++) 1444 (*applier)(next, context); 1445 copyArray->release(); 1446 } 1447} 1448 1449void IOService::applyToInterested( const OSSymbol * typeOfInterest, 1450 OSObjectApplierFunction applier, 1451 void * context ) 1452{ 1453 if (gIOGeneralInterest == typeOfInterest) 1454 applyToClients( (IOServiceApplierFunction) applier, context ); 1455 applyToInterestNotifiers(this, typeOfInterest, applier, context); 1456} 1457 1458struct MessageClientsContext { 1459 IOService * service; 1460 UInt32 type; 1461 void * argument; 1462 vm_size_t argSize; 1463 IOReturn ret; 1464}; 1465 1466static void messageClientsApplier( OSObject * object, void * ctx ) 1467{ 1468 IOReturn ret; 1469 MessageClientsContext * context = (MessageClientsContext *) ctx; 1470 1471 ret = context->service->messageClient( context->type, 1472 object, context->argument, context->argSize ); 1473 if( kIOReturnSuccess != ret) 1474 context->ret = ret; 1475} 1476 1477// send a message to all clients 1478IOReturn IOService::messageClients( UInt32 type, 1479 void * argument, vm_size_t argSize ) 1480{ 1481 MessageClientsContext context; 1482 1483 context.service = this; 1484 context.type = type; 1485 context.argument = argument; 1486 context.argSize = argSize; 1487 context.ret = kIOReturnSuccess; 1488 1489 applyToInterested( gIOGeneralInterest, 1490 &messageClientsApplier, &context ); 1491 1492 return( context.ret ); 1493} 1494 1495IOReturn IOService::acknowledgeNotification( IONotificationRef notification, 1496 IOOptionBits response ) 1497{ 1498 return( kIOReturnUnsupported ); 1499} 1500 1501IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, 1502 IOServiceInterestHandler handler, void * target, void * ref ) 1503{ 1504 _IOServiceInterestNotifier * notify = 0; 1505 1506 if( (typeOfInterest != gIOGeneralInterest) 1507 && (typeOfInterest != gIOBusyInterest) 1508 && (typeOfInterest != gIOAppPowerStateInterest) 1509 && (typeOfInterest != gIOConsoleSecurityInterest) 1510 && (typeOfInterest != gIOPriorityPowerStateInterest)) 1511 return( 0 ); 1512 1513 lockForArbitration(); 1514 if( 0 == (__state[0] & kIOServiceInactiveState)) { 1515 1516 notify = new _IOServiceInterestNotifier; 1517 if( notify && !notify->init()) { 1518 notify->release(); 1519 notify = 0; 1520 } 1521 1522 if( notify) { 1523 notify->handler = handler; 1524 notify->target = target; 1525 notify->ref = ref; 1526 notify->state = kIOServiceNotifyEnable; 1527 queue_init( ¬ify->handlerInvocations ); 1528 1529 ////// queue 1530 1531 LOCKWRITENOTIFY(); 1532 1533 // Get the head of the notifier linked list 1534 IOCommand *notifyList = (IOCommand *) getProperty( typeOfInterest ); 1535 if (!notifyList || !OSDynamicCast(IOCommand, notifyList)) { 1536 notifyList = OSTypeAlloc(IOCommand); 1537 if (notifyList) { 1538 notifyList->init(); 1539 setProperty( typeOfInterest, notifyList); 1540 notifyList->release(); 1541 } 1542 } 1543 1544 if (notifyList) { 1545 enqueue(¬ifyList->fCommandChain, ¬ify->chain); 1546 notify->retain(); // ref'ed while in list 1547 } 1548 1549 UNLOCKNOTIFY(); 1550 } 1551 } 1552 unlockForArbitration(); 1553 1554 return( notify ); 1555} 1556 1557static void cleanInterestList( OSObject * head ) 1558{ 1559 IOCommand *notifyHead = OSDynamicCast(IOCommand, head); 1560 if (!notifyHead) 1561 return; 1562 1563 LOCKWRITENOTIFY(); 1564 while ( queue_entry_t entry = dequeue(¬ifyHead->fCommandChain) ) { 1565 queue_next(entry) = queue_prev(entry) = 0; 1566 1567 _IOServiceInterestNotifier * notify; 1568 1569 queue_element(entry, notify, _IOServiceInterestNotifier *, chain); 1570 notify->release(); 1571 } 1572 UNLOCKNOTIFY(); 1573} 1574 1575void IOService::unregisterAllInterest( void ) 1576{ 1577 cleanInterestList( getProperty( gIOGeneralInterest )); 1578 cleanInterestList( getProperty( gIOBusyInterest )); 1579 cleanInterestList( getProperty( gIOAppPowerStateInterest )); 1580 cleanInterestList( getProperty( gIOPriorityPowerStateInterest )); 1581 cleanInterestList( getProperty( gIOConsoleSecurityInterest )); 1582} 1583 1584/* 1585 * _IOServiceInterestNotifier 1586 */ 1587 1588// wait for all threads, other than the current one, 1589// to exit the handler 1590 1591void _IOServiceInterestNotifier::wait() 1592{ 1593 _IOServiceNotifierInvocation * next; 1594 bool doWait; 1595 1596 do { 1597 doWait = false; 1598 queue_iterate( &handlerInvocations, next, 1599 _IOServiceNotifierInvocation *, link) { 1600 if( next->thread != current_thread() ) { 1601 doWait = true; 1602 break; 1603 } 1604 } 1605 if( doWait) { 1606 state |= kIOServiceNotifyWaiter; 1607 SLEEPNOTIFY(this); 1608 } 1609 1610 } while( doWait ); 1611} 1612 1613void _IOServiceInterestNotifier::free() 1614{ 1615 assert( queue_empty( &handlerInvocations )); 1616 OSObject::free(); 1617} 1618 1619void _IOServiceInterestNotifier::remove() 1620{ 1621 LOCKWRITENOTIFY(); 1622 1623 if( queue_next( &chain )) { 1624 remqueue(&chain); 1625 queue_next( &chain) = queue_prev( &chain) = 0; 1626 release(); 1627 } 1628 1629 state &= ~kIOServiceNotifyEnable; 1630 1631 wait(); 1632 1633 UNLOCKNOTIFY(); 1634 1635 release(); 1636} 1637 1638bool _IOServiceInterestNotifier::disable() 1639{ 1640 bool ret; 1641 1642 LOCKWRITENOTIFY(); 1643 1644 ret = (0 != (kIOServiceNotifyEnable & state)); 1645 state &= ~kIOServiceNotifyEnable; 1646 if( ret) 1647 wait(); 1648 1649 UNLOCKNOTIFY(); 1650 1651 return( ret ); 1652} 1653 1654void _IOServiceInterestNotifier::enable( bool was ) 1655{ 1656 LOCKWRITENOTIFY(); 1657 if( was) 1658 state |= kIOServiceNotifyEnable; 1659 else 1660 state &= ~kIOServiceNotifyEnable; 1661 UNLOCKNOTIFY(); 1662} 1663 1664/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 1665 1666/* 1667 * Termination 1668 */ 1669 1670#define tailQ(o) setObject(o) 1671#define headQ(o) setObject(0, o) 1672#define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }} 1673 1674static void _workLoopAction( IOWorkLoop::Action action, 1675 IOService * service, 1676 void * p0 = 0, void * p1 = 0, 1677 void * p2 = 0, void * p3 = 0 ) 1678{ 1679 IOWorkLoop * wl; 1680 1681 if( (wl = service->getWorkLoop())) { 1682 wl->retain(); 1683 wl->runAction( action, service, p0, p1, p2, p3 ); 1684 wl->release(); 1685 } else 1686 (*action)( service, p0, p1, p2, p3 ); 1687} 1688 1689bool IOService::requestTerminate( IOService * provider, IOOptionBits options ) 1690{ 1691 bool ok; 1692 1693 // if its our only provider 1694 ok = isParent( provider, gIOServicePlane, true); 1695 1696 // -- compat 1697 if( ok) { 1698 provider->terminateClient( this, options | kIOServiceRecursing ); 1699 ok = (0 != (__state[1] & kIOServiceRecursing)); 1700 } 1701 // -- 1702 1703 return( ok ); 1704} 1705 1706bool IOService::terminatePhase1( IOOptionBits options ) 1707{ 1708 IOService * victim; 1709 IOService * client; 1710 OSIterator * iter; 1711 OSArray * makeInactive; 1712 int waitResult = THREAD_AWAKENED; 1713 bool wait; 1714 bool ok; 1715 bool didInactive; 1716 bool startPhase2 = false; 1717 1718 TLOG("%s::terminatePhase1(%08llx)\n", getName(), (long long)options); 1719 1720 uint64_t regID = getRegistryEntryID(); 1721 IOServiceTrace( 1722 IOSERVICE_TERMINATE_PHASE1, 1723 (uintptr_t) regID, 1724 (uintptr_t) (regID >> 32), 1725 (uintptr_t) this, 1726 (uintptr_t) options); 1727 1728 // -- compat 1729 if( options & kIOServiceRecursing) { 1730 lockForArbitration(); 1731 __state[1] |= kIOServiceRecursing; 1732 unlockForArbitration(); 1733 return( true ); 1734 } 1735 // -- 1736 1737 makeInactive = OSArray::withCapacity( 16 ); 1738 if( !makeInactive) 1739 return( false ); 1740 1741 victim = this; 1742 victim->retain(); 1743 1744 while( victim ) { 1745 1746 didInactive = victim->lockForArbitration( true ); 1747 if( didInactive) { 1748 didInactive = (0 == (victim->__state[0] & kIOServiceInactiveState)); 1749 if( didInactive) { 1750 victim->__state[0] |= kIOServiceInactiveState; 1751 victim->__state[0] &= ~(kIOServiceRegisteredState | kIOServiceMatchedState 1752 | kIOServiceFirstPublishState | kIOServiceFirstMatchState); 1753 1754 if (victim == this) 1755 victim->__state[1] |= kIOServiceTermPhase1State; 1756 1757 victim->_adjustBusy( 1 ); 1758 1759 } else if (victim != this) do { 1760 1761 IOLockLock(gIOServiceBusyLock); 1762 wait = (victim->__state[1] & kIOServiceTermPhase1State); 1763 if( wait) { 1764 TLOG("%s::waitPhase1(%s)\n", getName(), victim->getName()); 1765 victim->__state[1] |= kIOServiceTerm1WaiterState; 1766 victim->unlockForArbitration(); 1767 assert_wait((event_t)&victim->__state[1], THREAD_UNINT); 1768 } 1769 IOLockUnlock(gIOServiceBusyLock); 1770 if( wait) { 1771 waitResult = thread_block(THREAD_CONTINUE_NULL); 1772 TLOG("%s::did waitPhase1(%s)\n", getName(), victim->getName()); 1773 victim->lockForArbitration(); 1774 } 1775 } while( wait && (waitResult != THREAD_TIMED_OUT)); 1776 1777 victim->unlockForArbitration(); 1778 } 1779 if( victim == this) 1780 startPhase2 = didInactive; 1781 if( didInactive) { 1782 1783 victim->deliverNotification( gIOTerminatedNotification, 0, 0xffffffff ); 1784 IOUserClient::destroyUserReferences( victim ); 1785 1786 iter = victim->getClientIterator(); 1787 if( iter) { 1788 while( (client = (IOService *) iter->getNextObject())) { 1789 TLOG("%s::requestTerminate(%s, %08llx)\n", 1790 client->getName(), victim->getName(), (long long)options); 1791 ok = client->requestTerminate( victim, options ); 1792 TLOG("%s::requestTerminate(%s, ok = %d)\n", 1793 client->getName(), victim->getName(), ok); 1794 1795 uint64_t regID1 = client->getRegistryEntryID(); 1796 uint64_t regID2 = victim->getRegistryEntryID(); 1797 IOServiceTrace( 1798 (ok ? IOSERVICE_TERMINATE_REQUEST_OK 1799 : IOSERVICE_TERMINATE_REQUEST_FAIL), 1800 (uintptr_t) regID1, 1801 (uintptr_t) (regID1 >> 32), 1802 (uintptr_t) regID2, 1803 (uintptr_t) (regID2 >> 32)); 1804 1805 if( ok) 1806 makeInactive->setObject( client ); 1807 } 1808 iter->release(); 1809 } 1810 } 1811 victim->release(); 1812 victim = (IOService *) makeInactive->getObject(0); 1813 if( victim) { 1814 victim->retain(); 1815 makeInactive->removeObject(0); 1816 } 1817 } 1818 1819 makeInactive->release(); 1820 1821 if( startPhase2) 1822 { 1823 lockForArbitration(); 1824 __state[1] &= ~kIOServiceTermPhase1State; 1825 if (kIOServiceTerm1WaiterState & __state[1]) 1826 { 1827 __state[1] &= ~kIOServiceTerm1WaiterState; 1828 TLOG("%s::wakePhase1\n", getName()); 1829 IOLockLock( gIOServiceBusyLock ); 1830 thread_wakeup( (event_t) &__state[1]); 1831 IOLockUnlock( gIOServiceBusyLock ); 1832 } 1833 unlockForArbitration(); 1834 1835 scheduleTerminatePhase2( options ); 1836 } 1837 return( true ); 1838} 1839 1840void IOService::setTerminateDefer(IOService * provider, bool defer) 1841{ 1842 lockForArbitration(); 1843 if (defer) __state[1] |= kIOServiceStartState; 1844 else __state[1] &= ~kIOServiceStartState; 1845 unlockForArbitration(); 1846 1847 if (provider && !defer) 1848 { 1849 provider->lockForArbitration(); 1850 if (provider->__state[0] & kIOServiceInactiveState) 1851 { 1852 provider->scheduleTerminatePhase2(); 1853 } 1854 provider->unlockForArbitration(); 1855 } 1856} 1857 1858void IOService::scheduleTerminatePhase2( IOOptionBits options ) 1859{ 1860 AbsoluteTime deadline; 1861 int waitResult = THREAD_AWAKENED; 1862 bool wait, haveDeadline = false; 1863 1864 options |= kIOServiceRequired; 1865 1866 retain(); 1867 1868 IOLockLock( gJobsLock ); 1869 1870 if( (options & kIOServiceSynchronous) 1871 && (current_thread() != gIOTerminateThread)) { 1872 1873 do { 1874 wait = (gIOTerminateThread != 0); 1875 if( wait) { 1876 // wait to become the terminate thread 1877 IOLockSleep( gJobsLock, &gIOTerminateThread, THREAD_UNINT); 1878 } 1879 } while( wait ); 1880 1881 gIOTerminateThread = current_thread(); 1882 gIOTerminatePhase2List->setObject( this ); 1883 gIOTerminateWork++; 1884 1885 do { 1886 while( gIOTerminateWork ) 1887 terminateWorker( options ); 1888 wait = (0 != (__state[1] & kIOServiceBusyStateMask)); 1889 if( wait) { 1890 // wait for the victim to go non-busy 1891 if( !haveDeadline) { 1892 clock_interval_to_deadline( 15, kSecondScale, &deadline ); 1893 haveDeadline = true; 1894 } 1895 waitResult = IOLockSleepDeadline( gJobsLock, &gIOTerminateWork, 1896 deadline, THREAD_UNINT ); 1897 if( waitResult == THREAD_TIMED_OUT) { 1898 IOLog("%s::terminate(kIOServiceSynchronous) timeout\n", getName()); 1899 } 1900 } 1901 } while(gIOTerminateWork || (wait && (waitResult != THREAD_TIMED_OUT))); 1902 1903 gIOTerminateThread = 0; 1904 IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false); 1905 1906 } else { 1907 // ! kIOServiceSynchronous 1908 1909 gIOTerminatePhase2List->setObject( this ); 1910 if( 0 == gIOTerminateWork++) { 1911 if( !gIOTerminateThread) 1912 kernel_thread_start(&terminateThread, (void *)(uintptr_t) options, &gIOTerminateThread); 1913 else 1914 IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); 1915 } 1916 } 1917 1918 IOLockUnlock( gJobsLock ); 1919 1920 release(); 1921} 1922 1923void IOService::terminateThread( void * arg, wait_result_t waitResult ) 1924{ 1925 IOLockLock( gJobsLock ); 1926 1927 while (gIOTerminateWork) 1928 terminateWorker( (uintptr_t) arg ); 1929 1930 thread_deallocate(gIOTerminateThread); 1931 gIOTerminateThread = 0; 1932 IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false); 1933 1934 IOLockUnlock( gJobsLock ); 1935} 1936 1937void IOService::scheduleStop( IOService * provider ) 1938{ 1939 TLOG("%s::scheduleStop(%s)\n", getName(), provider->getName()); 1940 1941 uint64_t regID1 = getRegistryEntryID(); 1942 uint64_t regID2 = provider->getRegistryEntryID(); 1943 IOServiceTrace( 1944 IOSERVICE_TERMINATE_SCHEDULE_STOP, 1945 (uintptr_t) regID1, 1946 (uintptr_t) (regID1 >> 32), 1947 (uintptr_t) regID2, 1948 (uintptr_t) (regID2 >> 32)); 1949 1950 IOLockLock( gJobsLock ); 1951 gIOStopList->tailQ( this ); 1952 gIOStopProviderList->tailQ( provider ); 1953 1954 if( 0 == gIOTerminateWork++) { 1955 if( !gIOTerminateThread) 1956 kernel_thread_start(&terminateThread, (void *) 0, &gIOTerminateThread); 1957 else 1958 IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); 1959 } 1960 1961 IOLockUnlock( gJobsLock ); 1962} 1963 1964void IOService::scheduleFinalize( void ) 1965{ 1966 TLOG("%s::scheduleFinalize\n", getName()); 1967 1968 uint64_t regID1 = getRegistryEntryID(); 1969 IOServiceTrace( 1970 IOSERVICE_TERMINATE_SCHEDULE_FINALIZE, 1971 (uintptr_t) regID1, 1972 (uintptr_t) (regID1 >> 32), 1973 0, 0); 1974 1975 IOLockLock( gJobsLock ); 1976 gIOFinalizeList->tailQ( this ); 1977 1978 if( 0 == gIOTerminateWork++) { 1979 if( !gIOTerminateThread) 1980 kernel_thread_start(&terminateThread, (void *) 0, &gIOTerminateThread); 1981 else 1982 IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); 1983 } 1984 1985 IOLockUnlock( gJobsLock ); 1986} 1987 1988bool IOService::willTerminate( IOService * provider, IOOptionBits options ) 1989{ 1990 return( true ); 1991} 1992 1993bool IOService::didTerminate( IOService * provider, IOOptionBits options, bool * defer ) 1994{ 1995 if( false == *defer) { 1996 1997 if( lockForArbitration( true )) { 1998 if( false == provider->handleIsOpen( this )) 1999 scheduleStop( provider ); 2000 // -- compat 2001 else { 2002 message( kIOMessageServiceIsRequestingClose, provider, (void *)(uintptr_t) options ); 2003 if( false == provider->handleIsOpen( this )) 2004 scheduleStop( provider ); 2005 } 2006 // -- 2007 unlockForArbitration(); 2008 } 2009 } 2010 2011 return( true ); 2012} 2013 2014void IOService::actionWillTerminate( IOService * victim, IOOptionBits options, 2015 OSArray * doPhase2List, 2016 void *unused2 __unused, 2017 void *unused3 __unused ) 2018{ 2019 OSIterator * iter; 2020 IOService * client; 2021 bool ok; 2022 2023 iter = victim->getClientIterator(); 2024 if( iter) { 2025 while( (client = (IOService *) iter->getNextObject())) { 2026 TLOG("%s::willTerminate(%s, %08llx)\n", 2027 client->getName(), victim->getName(), (long long)options); 2028 2029 uint64_t regID1 = client->getRegistryEntryID(); 2030 uint64_t regID2 = victim->getRegistryEntryID(); 2031 IOServiceTrace( 2032 IOSERVICE_TERMINATE_WILL, 2033 (uintptr_t) regID1, 2034 (uintptr_t) (regID1 >> 32), 2035 (uintptr_t) regID2, 2036 (uintptr_t) (regID2 >> 32)); 2037 2038 ok = client->willTerminate( victim, options ); 2039 doPhase2List->tailQ( client ); 2040 } 2041 iter->release(); 2042 } 2043} 2044 2045void IOService::actionDidTerminate( IOService * victim, IOOptionBits options, 2046 void *unused1 __unused, void *unused2 __unused, 2047 void *unused3 __unused ) 2048{ 2049 OSIterator * iter; 2050 IOService * client; 2051 bool defer = false; 2052 2053 victim->messageClients( kIOMessageServiceIsTerminated, (void *)(uintptr_t) options ); 2054 2055 iter = victim->getClientIterator(); 2056 if( iter) { 2057 while( (client = (IOService *) iter->getNextObject())) { 2058 TLOG("%s::didTerminate(%s, %08llx)\n", 2059 client->getName(), victim->getName(), (long long)options); 2060 client->didTerminate( victim, options, &defer ); 2061 2062 uint64_t regID1 = client->getRegistryEntryID(); 2063 uint64_t regID2 = victim->getRegistryEntryID(); 2064 IOServiceTrace( 2065 (defer ? IOSERVICE_TERMINATE_DID_DEFER 2066 : IOSERVICE_TERMINATE_DID), 2067 (uintptr_t) regID1, 2068 (uintptr_t) (regID1 >> 32), 2069 (uintptr_t) regID2, 2070 (uintptr_t) (regID2 >> 32)); 2071 2072 TLOG("%s::didTerminate(%s, defer %d)\n", 2073 client->getName(), victim->getName(), defer); 2074 } 2075 iter->release(); 2076 } 2077} 2078 2079void IOService::actionFinalize( IOService * victim, IOOptionBits options, 2080 void *unused1 __unused, void *unused2 __unused, 2081 void *unused3 __unused ) 2082{ 2083 TLOG("%s::finalize(%08llx)\n", victim->getName(), (long long)options); 2084 2085 uint64_t regID1 = victim->getRegistryEntryID(); 2086 IOServiceTrace( 2087 IOSERVICE_TERMINATE_FINALIZE, 2088 (uintptr_t) regID1, 2089 (uintptr_t) (regID1 >> 32), 2090 0, 0); 2091 2092 victim->finalize( options ); 2093} 2094 2095void IOService::actionStop( IOService * provider, IOService * client, 2096 void *unused1 __unused, void *unused2 __unused, 2097 void *unused3 __unused ) 2098{ 2099 TLOG("%s::stop(%s)\n", client->getName(), provider->getName()); 2100 2101 uint64_t regID1 = provider->getRegistryEntryID(); 2102 uint64_t regID2 = client->getRegistryEntryID(); 2103 IOServiceTrace( 2104 IOSERVICE_TERMINATE_STOP, 2105 (uintptr_t) regID1, 2106 (uintptr_t) (regID1 >> 32), 2107 (uintptr_t) regID2, 2108 (uintptr_t) (regID2 >> 32)); 2109 2110 client->stop( provider ); 2111 if( provider->isOpen( client )) 2112 provider->close( client ); 2113 TLOG("%s::detach(%s)\n", client->getName(), provider->getName()); 2114 client->detach( provider ); 2115} 2116 2117void IOService::terminateWorker( IOOptionBits options ) 2118{ 2119 OSArray * doPhase2List; 2120 OSArray * didPhase2List; 2121 OSSet * freeList; 2122 OSIterator * iter; 2123 UInt32 workDone; 2124 IOService * victim; 2125 IOService * client; 2126 IOService * provider; 2127 unsigned int idx; 2128 bool moreToDo; 2129 bool doPhase2; 2130 bool doPhase3; 2131 2132 options |= kIOServiceRequired; 2133 2134 doPhase2List = OSArray::withCapacity( 16 ); 2135 didPhase2List = OSArray::withCapacity( 16 ); 2136 freeList = OSSet::withCapacity( 16 ); 2137 if( (0 == doPhase2List) || (0 == didPhase2List) || (0 == freeList)) 2138 return; 2139 2140 do { 2141 workDone = gIOTerminateWork; 2142 2143 while( (victim = (IOService *) gIOTerminatePhase2List->getObject(0) )) { 2144 2145 victim->retain(); 2146 gIOTerminatePhase2List->removeObject(0); 2147 IOLockUnlock( gJobsLock ); 2148 2149 while( victim ) { 2150 2151 doPhase2 = victim->lockForArbitration( true ); 2152 if( doPhase2) { 2153 doPhase2 = (0 != (kIOServiceInactiveState & victim->__state[0])); 2154 if( doPhase2) { 2155 doPhase2 = (0 == (victim->__state[1] & kIOServiceTermPhase2State)) 2156 && (0 == (victim->__state[1] & kIOServiceConfigState)); 2157 2158 if (doPhase2 && (iter = victim->getClientIterator())) { 2159 while (doPhase2 && (client = (IOService *) iter->getNextObject())) { 2160 doPhase2 = (0 == (client->__state[1] & kIOServiceStartState)); 2161 } 2162 iter->release(); 2163 } 2164 if( doPhase2) 2165 victim->__state[1] |= kIOServiceTermPhase2State; 2166 } 2167 victim->unlockForArbitration(); 2168 } 2169 if( doPhase2) { 2170 if( 0 == victim->getClient()) { 2171 // no clients - will go to finalize 2172 IOLockLock( gJobsLock ); 2173 gIOFinalizeList->tailQ( victim ); 2174 IOLockUnlock( gJobsLock ); 2175 } else { 2176 _workLoopAction( (IOWorkLoop::Action) &actionWillTerminate, 2177 victim, (void *)(uintptr_t) options, (void *)(uintptr_t) doPhase2List ); 2178 } 2179 didPhase2List->headQ( victim ); 2180 } 2181 victim->release(); 2182 victim = (IOService *) doPhase2List->getObject(0); 2183 if( victim) { 2184 victim->retain(); 2185 doPhase2List->removeObject(0); 2186 } 2187 } 2188 2189 while( (victim = (IOService *) didPhase2List->getObject(0)) ) { 2190 2191 if( victim->lockForArbitration( true )) { 2192 victim->__state[1] |= kIOServiceTermPhase3State; 2193 victim->unlockForArbitration(); 2194 } 2195 _workLoopAction( (IOWorkLoop::Action) &actionDidTerminate, 2196 victim, (void *)(uintptr_t) options ); 2197 didPhase2List->removeObject(0); 2198 } 2199 IOLockLock( gJobsLock ); 2200 } 2201 2202 // phase 3 2203 do { 2204 doPhase3 = false; 2205 // finalize leaves 2206 while( (victim = (IOService *) gIOFinalizeList->getObject(0))) { 2207 2208 IOLockUnlock( gJobsLock ); 2209 _workLoopAction( (IOWorkLoop::Action) &actionFinalize, 2210 victim, (void *)(uintptr_t) options ); 2211 IOLockLock( gJobsLock ); 2212 // hold off free 2213 freeList->setObject( victim ); 2214 // safe if finalize list is append only 2215 gIOFinalizeList->removeObject(0); 2216 } 2217 2218 for( idx = 0; 2219 (!doPhase3) && (client = (IOService *) gIOStopList->getObject(idx)); ) { 2220 2221 provider = (IOService *) gIOStopProviderList->getObject(idx); 2222 assert( provider ); 2223 2224 if( !provider->isChild( client, gIOServicePlane )) { 2225 // may be multiply queued - nop it 2226 TLOG("%s::nop stop(%s)\n", client->getName(), provider->getName()); 2227 2228 uint64_t regID1 = provider->getRegistryEntryID(); 2229 uint64_t regID2 = client->getRegistryEntryID(); 2230 IOServiceTrace( 2231 IOSERVICE_TERMINATE_STOP_NOP, 2232 (uintptr_t) regID1, 2233 (uintptr_t) (regID1 >> 32), 2234 (uintptr_t) regID2, 2235 (uintptr_t) (regID2 >> 32)); 2236 2237 } else { 2238 // a terminated client is not ready for stop if it has clients, skip it 2239 if( (kIOServiceInactiveState & client->__state[0]) && client->getClient()) { 2240 TLOG("%s::defer stop(%s)\n", client->getName(), provider->getName()); 2241 2242 uint64_t regID1 = provider->getRegistryEntryID(); 2243 uint64_t regID2 = client->getRegistryEntryID(); 2244 IOServiceTrace( 2245 IOSERVICE_TERMINATE_STOP_DEFER, 2246 (uintptr_t) regID1, 2247 (uintptr_t) (regID1 >> 32), 2248 (uintptr_t) regID2, 2249 (uintptr_t) (regID2 >> 32)); 2250 2251 idx++; 2252 continue; 2253 } 2254 2255 IOLockUnlock( gJobsLock ); 2256 _workLoopAction( (IOWorkLoop::Action) &actionStop, 2257 provider, (void *) client ); 2258 IOLockLock( gJobsLock ); 2259 // check the finalize list now 2260 doPhase3 = true; 2261 } 2262 // hold off free 2263 freeList->setObject( client ); 2264 freeList->setObject( provider ); 2265 2266 // safe if stop list is append only 2267 gIOStopList->removeObject( idx ); 2268 gIOStopProviderList->removeObject( idx ); 2269 idx = 0; 2270 } 2271 2272 } while( doPhase3 ); 2273 2274 gIOTerminateWork -= workDone; 2275 moreToDo = (gIOTerminateWork != 0); 2276 2277 if( !moreToDo) { 2278 TLOG("iokit terminate done, %d stops remain\n", gIOStopList->getCount()); 2279 IOServiceTrace( 2280 IOSERVICE_TERMINATE_DONE, 2281 (uintptr_t) gIOStopList->getCount(), 0, 0, 0); 2282 } 2283 2284 } while( moreToDo ); 2285 2286 IOLockUnlock( gJobsLock ); 2287 2288 freeList->release(); 2289 doPhase2List->release(); 2290 didPhase2List->release(); 2291 2292 IOLockLock( gJobsLock ); 2293} 2294 2295bool IOService::finalize( IOOptionBits options ) 2296{ 2297 OSIterator * iter; 2298 IOService * provider; 2299 2300 iter = getProviderIterator(); 2301 assert( iter ); 2302 2303 if( iter) { 2304 while( (provider = (IOService *) iter->getNextObject())) { 2305 2306 // -- compat 2307 if( 0 == (__state[1] & kIOServiceTermPhase3State)) { 2308 /* we come down here on programmatic terminate */ 2309 stop( provider ); 2310 if( provider->isOpen( this )) 2311 provider->close( this ); 2312 detach( provider ); 2313 } else { 2314 //-- 2315 if( provider->lockForArbitration( true )) { 2316 if( 0 == (provider->__state[1] & kIOServiceTermPhase3State)) 2317 scheduleStop( provider ); 2318 provider->unlockForArbitration(); 2319 } 2320 } 2321 } 2322 iter->release(); 2323 } 2324 2325 return( true ); 2326} 2327 2328#undef tailQ 2329#undef headQ 2330 2331/* 2332 * Terminate 2333 */ 2334 2335void IOService::doServiceTerminate( IOOptionBits options ) 2336{ 2337} 2338 2339// a method in case someone needs to override it 2340bool IOService::terminateClient( IOService * client, IOOptionBits options ) 2341{ 2342 bool ok; 2343 2344 if( client->isParent( this, gIOServicePlane, true)) 2345 // we are the clients only provider 2346 ok = client->terminate( options ); 2347 else 2348 ok = true; 2349 2350 return( ok ); 2351} 2352 2353bool IOService::terminate( IOOptionBits options ) 2354{ 2355 options |= kIOServiceTerminate; 2356 2357 return( terminatePhase1( options )); 2358} 2359 2360/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2361 2362/* 2363 * Open & close 2364 */ 2365 2366struct ServiceOpenMessageContext 2367{ 2368 IOService * service; 2369 UInt32 type; 2370 IOService * excludeClient; 2371 IOOptionBits options; 2372}; 2373 2374static void serviceOpenMessageApplier( OSObject * object, void * ctx ) 2375{ 2376 ServiceOpenMessageContext * context = (ServiceOpenMessageContext *) ctx; 2377 2378 if( object != context->excludeClient) 2379 context->service->messageClient( context->type, object, (void *)(uintptr_t) context->options ); 2380} 2381 2382bool IOService::open( IOService * forClient, 2383 IOOptionBits options, 2384 void * arg ) 2385{ 2386 bool ok; 2387 ServiceOpenMessageContext context; 2388 2389 context.service = this; 2390 context.type = kIOMessageServiceIsAttemptingOpen; 2391 context.excludeClient = forClient; 2392 context.options = options; 2393 2394 applyToInterested( gIOGeneralInterest, 2395 &serviceOpenMessageApplier, &context ); 2396 2397 if( false == lockForArbitration(false) ) 2398 return false; 2399 2400 ok = (0 == (__state[0] & kIOServiceInactiveState)); 2401 if( ok) 2402 ok = handleOpen( forClient, options, arg ); 2403 2404 unlockForArbitration(); 2405 2406 return( ok ); 2407} 2408 2409void IOService::close( IOService * forClient, 2410 IOOptionBits options ) 2411{ 2412 bool wasClosed; 2413 bool last = false; 2414 2415 lockForArbitration(); 2416 2417 wasClosed = handleIsOpen( forClient ); 2418 if( wasClosed) { 2419 handleClose( forClient, options ); 2420 last = (__state[1] & kIOServiceTermPhase3State); 2421 } 2422 2423 unlockForArbitration(); 2424 2425 if( last) 2426 forClient->scheduleStop( this ); 2427 2428 else if( wasClosed) { 2429 2430 ServiceOpenMessageContext context; 2431 2432 context.service = this; 2433 context.type = kIOMessageServiceWasClosed; 2434 context.excludeClient = forClient; 2435 context.options = options; 2436 2437 applyToInterested( gIOGeneralInterest, 2438 &serviceOpenMessageApplier, &context ); 2439 } 2440} 2441 2442bool IOService::isOpen( const IOService * forClient ) const 2443{ 2444 IOService * self = (IOService *) this; 2445 bool ok; 2446 2447 self->lockForArbitration(); 2448 2449 ok = handleIsOpen( forClient ); 2450 2451 self->unlockForArbitration(); 2452 2453 return( ok ); 2454} 2455 2456bool IOService::handleOpen( IOService * forClient, 2457 IOOptionBits options, 2458 void * arg ) 2459{ 2460 bool ok; 2461 2462 ok = (0 == __owner); 2463 if( ok ) 2464 __owner = forClient; 2465 2466 else if( options & kIOServiceSeize ) { 2467 ok = (kIOReturnSuccess == messageClient( kIOMessageServiceIsRequestingClose, 2468 __owner, (void *)(uintptr_t) options )); 2469 if( ok && (0 == __owner )) 2470 __owner = forClient; 2471 else 2472 ok = false; 2473 } 2474 return( ok ); 2475} 2476 2477void IOService::handleClose( IOService * forClient, 2478 IOOptionBits options ) 2479{ 2480 if( __owner == forClient) 2481 __owner = 0; 2482} 2483 2484bool IOService::handleIsOpen( const IOService * forClient ) const 2485{ 2486 if( forClient) 2487 return( __owner == forClient ); 2488 else 2489 return( __owner != forClient ); 2490} 2491 2492/* 2493 * Probing & starting 2494 */ 2495static SInt32 IONotifyOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref ) 2496{ 2497 const _IOServiceNotifier * obj1 = (const _IOServiceNotifier *) inObj1; 2498 const _IOServiceNotifier * obj2 = (const _IOServiceNotifier *) inObj2; 2499 SInt32 val1; 2500 SInt32 val2; 2501 2502 val1 = 0; 2503 val2 = 0; 2504 2505 if ( obj1 ) 2506 val1 = obj1->priority; 2507 2508 if ( obj2 ) 2509 val2 = obj2->priority; 2510 2511 return ( val1 - val2 ); 2512} 2513 2514static SInt32 IOServiceObjectOrder( const OSObject * entry, void * ref) 2515{ 2516 OSDictionary * dict; 2517 IOService * service; 2518 _IOServiceNotifier * notify; 2519 OSSymbol * key = (OSSymbol *) ref; 2520 OSNumber * offset; 2521 2522 if( (dict = OSDynamicCast( OSDictionary, entry))) 2523 offset = OSDynamicCast(OSNumber, dict->getObject( key )); 2524 else if( (notify = OSDynamicCast( _IOServiceNotifier, entry))) 2525 return( notify->priority ); 2526 2527 else if( (service = OSDynamicCast( IOService, entry))) 2528 offset = OSDynamicCast(OSNumber, service->getProperty( key )); 2529 else { 2530 assert( false ); 2531 offset = 0; 2532 } 2533 2534 if( offset) 2535 return( (SInt32) offset->unsigned32BitValue()); 2536 else 2537 return( kIODefaultProbeScore ); 2538} 2539 2540SInt32 IOServiceOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref ) 2541{ 2542 const OSObject * obj1 = (const OSObject *) inObj1; 2543 const OSObject * obj2 = (const OSObject *) inObj2; 2544 SInt32 val1; 2545 SInt32 val2; 2546 2547 val1 = 0; 2548 val2 = 0; 2549 2550 if ( obj1 ) 2551 val1 = IOServiceObjectOrder( obj1, ref ); 2552 2553 if ( obj2 ) 2554 val2 = IOServiceObjectOrder( obj2, ref ); 2555 2556 return ( val1 - val2 ); 2557} 2558 2559IOService * IOService::copyClientWithCategory( const OSSymbol * category ) 2560{ 2561 IOService * service = 0; 2562 OSIterator * iter; 2563 const OSSymbol * nextCat; 2564 2565 iter = getClientIterator(); 2566 if( iter) { 2567 while( (service = (IOService *) iter->getNextObject())) { 2568 if( kIOServiceInactiveState & service->__state[0]) 2569 continue; 2570 nextCat = (const OSSymbol *) OSDynamicCast( OSSymbol, 2571 service->getProperty( gIOMatchCategoryKey )); 2572 if( category == nextCat) 2573 { 2574 service->retain(); 2575 break; 2576 } 2577 } 2578 iter->release(); 2579 } 2580 return( service ); 2581} 2582 2583IOService * IOService::getClientWithCategory( const OSSymbol * category ) 2584{ 2585 IOService * 2586 service = copyClientWithCategory(category); 2587 if (service) 2588 service->release(); 2589 return (service); 2590} 2591 2592bool IOService::invokeNotifer( _IOServiceNotifier * notify ) 2593{ 2594 _IOServiceNotifierInvocation invocation; 2595 bool willNotify; 2596 bool ret = true; 2597 2598 invocation.thread = current_thread(); 2599 2600 LOCKWRITENOTIFY(); 2601 willNotify = (0 != (kIOServiceNotifyEnable & notify->state)); 2602 2603 if( willNotify) { 2604 queue_enter( ¬ify->handlerInvocations, &invocation, 2605 _IOServiceNotifierInvocation *, link ); 2606 } 2607 UNLOCKNOTIFY(); 2608 2609 if( willNotify) { 2610 2611 ret = (*notify->handler)(notify->target, notify->ref, this, notify); 2612 2613 LOCKWRITENOTIFY(); 2614 queue_remove( ¬ify->handlerInvocations, &invocation, 2615 _IOServiceNotifierInvocation *, link ); 2616 if( kIOServiceNotifyWaiter & notify->state) { 2617 notify->state &= ~kIOServiceNotifyWaiter; 2618 WAKEUPNOTIFY( notify ); 2619 } 2620 UNLOCKNOTIFY(); 2621 } 2622 2623 return( ret ); 2624} 2625 2626/* 2627 * Alloc and probe matching classes, 2628 * called on the provider instance 2629 */ 2630 2631void IOService::probeCandidates( OSOrderedSet * matches ) 2632{ 2633 OSDictionary * match = 0; 2634 OSSymbol * symbol; 2635 IOService * inst; 2636 IOService * newInst; 2637 OSDictionary * props; 2638 SInt32 score; 2639 OSNumber * newPri; 2640 OSOrderedSet * familyMatches = 0; 2641 OSOrderedSet * startList; 2642 OSDictionary * startDict = 0; 2643 const OSSymbol * category; 2644 OSIterator * iter; 2645 _IOServiceNotifier * notify; 2646 OSObject * nextMatch = 0; 2647 bool started; 2648 bool needReloc = false; 2649#if IOMATCHDEBUG 2650 SInt64 debugFlags; 2651#endif 2652 IOService * client = NULL; 2653 2654 2655 assert( matches ); 2656 while( !needReloc && (nextMatch = matches->getFirstObject())) { 2657 2658 nextMatch->retain(); 2659 matches->removeObject(nextMatch); 2660 2661 if( (notify = OSDynamicCast( _IOServiceNotifier, nextMatch ))) { 2662 2663 lockForArbitration(); 2664 if( 0 == (__state[0] & kIOServiceInactiveState)) 2665 invokeNotifer( notify ); 2666 unlockForArbitration(); 2667 nextMatch->release(); 2668 nextMatch = 0; 2669 continue; 2670 2671 } else if( !(match = OSDynamicCast( OSDictionary, nextMatch ))) { 2672 nextMatch->release(); 2673 nextMatch = 0; 2674 continue; 2675 } 2676 2677 props = 0; 2678#if IOMATCHDEBUG 2679 debugFlags = getDebugFlags( match ); 2680#endif 2681 2682 do { 2683 category = OSDynamicCast( OSSymbol, 2684 match->getObject( gIOMatchCategoryKey )); 2685 if( 0 == category) 2686 category = gIODefaultMatchCategoryKey; 2687 2688 if( (client = copyClientWithCategory(category)) ) { 2689#if IOMATCHDEBUG 2690 if( (debugFlags & kIOLogMatch) && (this != gIOResources)) 2691 LOG("%s: match category %s exists\n", getName(), 2692 category->getCStringNoCopy()); 2693#endif 2694 nextMatch->release(); 2695 nextMatch = 0; 2696 2697 client->release(); 2698 client = NULL; 2699 2700 continue; 2701 } 2702 2703 // create a copy now in case its modified during matching 2704 props = OSDictionary::withDictionary( match, match->getCount()); 2705 if( 0 == props) 2706 continue; 2707 props->setCapacityIncrement(1); 2708 2709 // check the nub matches 2710 if( false == matchPassive(props, kIOServiceChangesOK | kIOServiceClassDone)) 2711 continue; 2712 2713 // Check to see if driver reloc has been loaded. 2714 needReloc = (false == gIOCatalogue->isModuleLoaded( match )); 2715 if( needReloc) { 2716#if IOMATCHDEBUG 2717 if( debugFlags & kIOLogCatalogue) 2718 LOG("%s: stalling for module\n", getName()); 2719#endif 2720 // If reloc hasn't been loaded, exit; 2721 // reprobing will occur after reloc has been loaded. 2722 continue; 2723 } 2724 2725 // reorder on family matchPropertyTable score. 2726 if( 0 == familyMatches) 2727 familyMatches = OSOrderedSet::withCapacity( 1, 2728 IOServiceOrdering, (void *) gIOProbeScoreKey ); 2729 if( familyMatches) 2730 familyMatches->setObject( props ); 2731 2732 } while( false ); 2733 2734 if (nextMatch) { 2735 nextMatch->release(); 2736 nextMatch = 0; 2737 } 2738 if( props) 2739 props->release(); 2740 } 2741 matches->release(); 2742 matches = 0; 2743 2744 if( familyMatches) { 2745 2746 while( !needReloc 2747 && (props = (OSDictionary *) familyMatches->getFirstObject())) { 2748 2749 props->retain(); 2750 familyMatches->removeObject( props ); 2751 2752 inst = 0; 2753 newInst = 0; 2754#if IOMATCHDEBUG 2755 debugFlags = getDebugFlags( props ); 2756#endif 2757 do { 2758 symbol = OSDynamicCast( OSSymbol, 2759 props->getObject( gIOClassKey)); 2760 if( !symbol) 2761 continue; 2762 2763 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), OBFUSCATE(symbol), OBFUSCATE(props)); 2764 2765 // alloc the driver instance 2766 inst = (IOService *) OSMetaClass::allocClassWithName( symbol); 2767 2768 if( !inst) { 2769 IOLog("Couldn't alloc class \"%s\"\n", 2770 symbol->getCStringNoCopy()); 2771 continue; 2772 } 2773 2774 // init driver instance 2775 if( !(inst->init( props ))) { 2776#if IOMATCHDEBUG 2777 if( debugFlags & kIOLogStart) 2778 IOLog("%s::init fails\n", symbol->getCStringNoCopy()); 2779#endif 2780 continue; 2781 } 2782 if( __state[1] & kIOServiceSynchronousState) 2783 inst->__state[1] |= kIOServiceSynchronousState; 2784 2785 // give the driver the default match category if not specified 2786 category = OSDynamicCast( OSSymbol, 2787 props->getObject( gIOMatchCategoryKey )); 2788 if( 0 == category) 2789 category = gIODefaultMatchCategoryKey; 2790 inst->setProperty( gIOMatchCategoryKey, (OSObject *) category ); 2791 // attach driver instance 2792 if( !(inst->attach( this ))) 2793 continue; 2794 2795 // pass in score from property table 2796 score = familyMatches->orderObject( props ); 2797 2798 // & probe the new driver instance 2799#if IOMATCHDEBUG 2800 if( debugFlags & kIOLogProbe) 2801 LOG("%s::probe(%s)\n", 2802 inst->getMetaClass()->getClassName(), getName()); 2803#endif 2804 2805 newInst = inst->probe( this, &score ); 2806 inst->detach( this ); 2807 if( 0 == newInst) { 2808#if IOMATCHDEBUG 2809 if( debugFlags & kIOLogProbe) 2810 IOLog("%s::probe fails\n", symbol->getCStringNoCopy()); 2811#endif 2812 continue; 2813 } 2814 2815 // save the score 2816 newPri = OSNumber::withNumber( score, 32 ); 2817 if( newPri) { 2818 newInst->setProperty( gIOProbeScoreKey, newPri ); 2819 newPri->release(); 2820 } 2821 2822 // add to start list for the match category 2823 if( 0 == startDict) 2824 startDict = OSDictionary::withCapacity( 1 ); 2825 assert( startDict ); 2826 startList = (OSOrderedSet *) 2827 startDict->getObject( category ); 2828 if( 0 == startList) { 2829 startList = OSOrderedSet::withCapacity( 1, 2830 IOServiceOrdering, (void *) gIOProbeScoreKey ); 2831 if( startDict && startList) { 2832 startDict->setObject( category, startList ); 2833 startList->release(); 2834 } 2835 } 2836 assert( startList ); 2837 if( startList) 2838 startList->setObject( newInst ); 2839 2840 } while( false ); 2841 2842 props->release(); 2843 if( inst) 2844 inst->release(); 2845 } 2846 familyMatches->release(); 2847 familyMatches = 0; 2848 } 2849 2850 // start the best (until success) of each category 2851 2852 iter = OSCollectionIterator::withCollection( startDict ); 2853 if( iter) { 2854 while( (category = (const OSSymbol *) iter->getNextObject())) { 2855 2856 startList = (OSOrderedSet *) startDict->getObject( category ); 2857 assert( startList ); 2858 if( !startList) 2859 continue; 2860 2861 started = false; 2862 while( true // (!started) 2863 && (inst = (IOService *)startList->getFirstObject())) { 2864 2865 inst->retain(); 2866 startList->removeObject(inst); 2867 2868#if IOMATCHDEBUG 2869 debugFlags = getDebugFlags( inst->getPropertyTable() ); 2870 2871 if( debugFlags & kIOLogStart) { 2872 if( started) 2873 LOG( "match category exists, skipping " ); 2874 LOG( "%s::start(%s) <%d>\n", inst->getName(), 2875 getName(), inst->getRetainCount()); 2876 } 2877#endif 2878 if( false == started) 2879 started = startCandidate( inst ); 2880#if IOMATCHDEBUG 2881 if( (debugFlags & kIOLogStart) && (false == started)) 2882 LOG( "%s::start(%s) <%d> failed\n", inst->getName(), getName(), 2883 inst->getRetainCount()); 2884#endif 2885 inst->release(); 2886 } 2887 } 2888 iter->release(); 2889 } 2890 2891 2892 // adjust the busy count by +1 if matching is stalled for a module, 2893 // or -1 if a previously stalled matching is complete. 2894 lockForArbitration(); 2895 SInt32 adjBusy = 0; 2896 uint64_t regID = getRegistryEntryID(); 2897 2898 if( needReloc) { 2899 adjBusy = (__state[1] & kIOServiceModuleStallState) ? 0 : 1; 2900 if( adjBusy) { 2901 2902 IOServiceTrace( 2903 IOSERVICE_MODULESTALL, 2904 (uintptr_t) regID, 2905 (uintptr_t) (regID >> 32), 2906 (uintptr_t) this, 2907 0); 2908 2909 __state[1] |= kIOServiceModuleStallState; 2910 } 2911 2912 } else if( __state[1] & kIOServiceModuleStallState) { 2913 2914 IOServiceTrace( 2915 IOSERVICE_MODULEUNSTALL, 2916 (uintptr_t) regID, 2917 (uintptr_t) (regID >> 32), 2918 (uintptr_t) this, 2919 0); 2920 2921 __state[1] &= ~kIOServiceModuleStallState; 2922 adjBusy = -1; 2923 } 2924 if( adjBusy) 2925 _adjustBusy( adjBusy ); 2926 unlockForArbitration(); 2927 2928 if( startDict) 2929 startDict->release(); 2930} 2931 2932/* 2933 * Start a previously attached & probed instance, 2934 * called on exporting object instance 2935 */ 2936 2937bool IOService::startCandidate( IOService * service ) 2938{ 2939 bool ok; 2940 2941 ok = service->attach( this ); 2942 2943 if( ok) 2944 { 2945 if (this != gIOResources) 2946 { 2947 // stall for any nub resources 2948 checkResources(); 2949 // stall for any driver resources 2950 service->checkResources(); 2951 } 2952 2953 AbsoluteTime startTime; 2954 AbsoluteTime endTime; 2955 UInt64 nano; 2956 2957 if (kIOLogStart & gIOKitDebug) 2958 clock_get_uptime(&startTime); 2959 2960 ok = service->start(this); 2961 2962 if (kIOLogStart & gIOKitDebug) 2963 { 2964 clock_get_uptime(&endTime); 2965 2966 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) 2967 { 2968 SUB_ABSOLUTETIME(&endTime, &startTime); 2969 absolutetime_to_nanoseconds(endTime, &nano); 2970 if (nano > 500000000ULL) 2971 IOLog("%s::start took %ld ms\n", service->getName(), (long)(UInt32)(nano / 1000000ULL)); 2972 } 2973 } 2974 if( !ok) 2975 service->detach( this ); 2976 } 2977 return( ok ); 2978} 2979 2980void IOService::publishResource( const char * key, OSObject * value ) 2981{ 2982 const OSSymbol * sym; 2983 2984 if( (sym = OSSymbol::withCString( key))) { 2985 publishResource( sym, value); 2986 sym->release(); 2987 } 2988} 2989 2990void IOService::publishResource( const OSSymbol * key, OSObject * value ) 2991{ 2992 if( 0 == value) 2993 value = (OSObject *) gIOServiceKey; 2994 2995 gIOResources->setProperty( key, value); 2996 2997 if( IORecursiveLockHaveLock( gNotificationLock)) 2998 return; 2999 3000 gIOResourceGenerationCount++; 3001 gIOResources->registerService(); 3002} 3003 3004bool IOService::addNeededResource( const char * key ) 3005{ 3006 OSObject * resourcesProp; 3007 OSSet * set; 3008 OSString * newKey; 3009 bool ret; 3010 3011 resourcesProp = getProperty( gIOResourceMatchKey ); 3012 3013 newKey = OSString::withCString( key ); 3014 if( (0 == resourcesProp) || (0 == newKey)) 3015 return( false); 3016 3017 set = OSDynamicCast( OSSet, resourcesProp ); 3018 if( !set) { 3019 set = OSSet::withCapacity( 1 ); 3020 if( set) 3021 set->setObject( resourcesProp ); 3022 } 3023 else 3024 set->retain(); 3025 3026 set->setObject( newKey ); 3027 newKey->release(); 3028 ret = setProperty( gIOResourceMatchKey, set ); 3029 set->release(); 3030 3031 return( ret ); 3032} 3033 3034bool IOService::checkResource( OSObject * matching ) 3035{ 3036 OSString * str; 3037 OSDictionary * table; 3038 3039 if( (str = OSDynamicCast( OSString, matching ))) { 3040 if( gIOResources->getProperty( str )) 3041 return( true ); 3042 } 3043 3044 if( str) 3045 table = resourceMatching( str ); 3046 else if( (table = OSDynamicCast( OSDictionary, matching ))) 3047 table->retain(); 3048 else { 3049 IOLog("%s: Can't match using: %s\n", getName(), 3050 matching->getMetaClass()->getClassName()); 3051 /* false would stall forever */ 3052 return( true ); 3053 } 3054 3055 if( gIOKitDebug & kIOLogConfig) 3056 LOG("config(%p): stalling %s\n", OBFUSCATE(IOThreadSelf()), getName()); 3057 3058 waitForService( table ); 3059 3060 if( gIOKitDebug & kIOLogConfig) 3061 LOG("config(%p): waking\n", OBFUSCATE(IOThreadSelf()) ); 3062 3063 return( true ); 3064} 3065 3066bool IOService::checkResources( void ) 3067{ 3068 OSObject * resourcesProp; 3069 OSSet * set; 3070 OSIterator * iter; 3071 bool ok; 3072 3073 resourcesProp = getProperty( gIOResourceMatchKey ); 3074 if( 0 == resourcesProp) 3075 return( true ); 3076 3077 if( (set = OSDynamicCast( OSSet, resourcesProp ))) { 3078 3079 iter = OSCollectionIterator::withCollection( set ); 3080 ok = (0 != iter); 3081 while( ok && (resourcesProp = iter->getNextObject()) ) 3082 ok = checkResource( resourcesProp ); 3083 if( iter) 3084 iter->release(); 3085 3086 } else 3087 ok = checkResource( resourcesProp ); 3088 3089 return( ok ); 3090} 3091 3092 3093void _IOConfigThread::configThread( void ) 3094{ 3095 _IOConfigThread * inst; 3096 3097 do { 3098 if( !(inst = new _IOConfigThread)) 3099 continue; 3100 if( !inst->init()) 3101 continue; 3102 thread_t unused; 3103 if (KERN_SUCCESS != kernel_thread_start(&_IOConfigThread::main, inst, &unused)) 3104 continue; 3105 3106 return; 3107 3108 } while( false); 3109 3110 if( inst) 3111 inst->release(); 3112 3113 return; 3114} 3115 3116void _IOConfigThread::free( void ) 3117{ 3118 thread_deallocate(current_thread()); 3119 OSObject::free(); 3120} 3121 3122void IOService::doServiceMatch( IOOptionBits options ) 3123{ 3124 _IOServiceNotifier * notify; 3125 OSIterator * iter; 3126 OSOrderedSet * matches; 3127 SInt32 catalogGeneration; 3128 bool keepGuessing = true; 3129 bool reRegistered = true; 3130 bool didRegister; 3131 3132// job->nub->deliverNotification( gIOPublishNotification, 3133// kIOServiceRegisteredState, 0xffffffff ); 3134 3135 while( keepGuessing ) { 3136 3137 matches = gIOCatalogue->findDrivers( this, &catalogGeneration ); 3138 // the matches list should always be created by findDrivers() 3139 if( matches) { 3140 3141 lockForArbitration(); 3142 if( 0 == (__state[0] & kIOServiceFirstPublishState)) { 3143 getMetaClass()->addInstance(this); 3144 deliverNotification( gIOFirstPublishNotification, 3145 kIOServiceFirstPublishState, 0xffffffff ); 3146 } 3147 LOCKREADNOTIFY(); 3148 __state[1] &= ~kIOServiceNeedConfigState; 3149 __state[1] |= kIOServiceConfigState; 3150 didRegister = (0 == (kIOServiceRegisteredState & __state[0])); 3151 __state[0] |= kIOServiceRegisteredState; 3152 3153 keepGuessing &= (0 == (__state[0] & kIOServiceInactiveState)); 3154 if (reRegistered && keepGuessing) { 3155 iter = OSCollectionIterator::withCollection( (OSOrderedSet *) 3156 gNotifications->getObject( gIOPublishNotification ) ); 3157 if( iter) { 3158 while((notify = (_IOServiceNotifier *) 3159 iter->getNextObject())) { 3160 3161 if( matchPassive(notify->matching, 0) 3162 && (kIOServiceNotifyEnable & notify->state)) 3163 matches->setObject( notify ); 3164 } 3165 iter->release(); 3166 } 3167 } 3168 3169 UNLOCKNOTIFY(); 3170 unlockForArbitration(); 3171 3172 if (keepGuessing && matches->getCount() && (kIOReturnSuccess == getResources())) 3173 probeCandidates( matches ); 3174 else 3175 matches->release(); 3176 } 3177 3178 lockForArbitration(); 3179 reRegistered = (0 != (__state[1] & kIOServiceNeedConfigState)); 3180 keepGuessing = 3181 (reRegistered || (catalogGeneration != 3182 gIOCatalogue->getGenerationCount())) 3183 && (0 == (__state[0] & kIOServiceInactiveState)); 3184 3185 if( keepGuessing) 3186 unlockForArbitration(); 3187 } 3188 3189 if( (0 == (__state[0] & kIOServiceInactiveState)) 3190 && (0 == (__state[1] & kIOServiceModuleStallState)) ) { 3191 deliverNotification( gIOMatchedNotification, 3192 kIOServiceMatchedState, 0xffffffff ); 3193 if( 0 == (__state[0] & kIOServiceFirstMatchState)) 3194 deliverNotification( gIOFirstMatchNotification, 3195 kIOServiceFirstMatchState, 0xffffffff ); 3196 } 3197 3198 __state[1] &= ~kIOServiceConfigState; 3199 if( __state[0] & kIOServiceInactiveState) 3200 scheduleTerminatePhase2(); 3201 3202 _adjustBusy( -1 ); 3203 unlockForArbitration(); 3204} 3205 3206UInt32 IOService::_adjustBusy( SInt32 delta ) 3207{ 3208 IOService * next; 3209 UInt32 count; 3210 UInt32 result; 3211 bool wasQuiet, nowQuiet, needWake; 3212 3213 next = this; 3214 result = __state[1] & kIOServiceBusyStateMask; 3215 3216 if( delta) do { 3217 if( next != this) 3218 next->lockForArbitration(); 3219 count = next->__state[1] & kIOServiceBusyStateMask; 3220 wasQuiet = (0 == count); 3221 if (((delta < 0) && wasQuiet) || ((delta > 0) && (kIOServiceBusyMax == count))) 3222 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next->getName(), count, delta); 3223 else 3224 count += delta; 3225 next->__state[1] = (next->__state[1] & ~kIOServiceBusyStateMask) | count; 3226 nowQuiet = (0 == count); 3227 needWake = (0 != (kIOServiceBusyWaiterState & next->__state[1])); 3228 3229 if( needWake) { 3230 next->__state[1] &= ~kIOServiceBusyWaiterState; 3231 IOLockLock( gIOServiceBusyLock ); 3232 thread_wakeup( (event_t) next); 3233 IOLockUnlock( gIOServiceBusyLock ); 3234 } 3235 if( next != this) 3236 next->unlockForArbitration(); 3237 3238 if( (wasQuiet || nowQuiet) ) { 3239 uint64_t regID = next->getRegistryEntryID(); 3240 3241 IOServiceTrace( 3242 ((wasQuiet/*nowBusy*/) ? IOSERVICE_BUSY : IOSERVICE_NONBUSY), 3243 (uintptr_t) regID, 3244 (uintptr_t) (regID >> 32), 3245 (uintptr_t) next, 3246 0); 3247 3248 if (wasQuiet) 3249 { 3250 next->__timeBusy = mach_absolute_time(); 3251 } 3252 else 3253 { 3254 next->__accumBusy += mach_absolute_time() - next->__timeBusy; 3255 next->__timeBusy = 0; 3256 } 3257 3258 MessageClientsContext context; 3259 3260 context.service = next; 3261 context.type = kIOMessageServiceBusyStateChange; 3262 context.argument = (void *) wasQuiet; /*nowBusy*/ 3263 context.argSize = 0; 3264 3265 applyToInterestNotifiers( next, gIOBusyInterest, 3266 &messageClientsApplier, &context ); 3267 3268#if !NO_KEXTD 3269 if( nowQuiet && (next == gIOServiceRoot)) { 3270 OSKext::considerUnloads(); 3271 IOServiceTrace(IOSERVICE_REGISTRY_QUIET, 0, 0, 0, 0); 3272 } 3273#endif 3274 } 3275 3276 delta = nowQuiet ? -1 : +1; 3277 3278 } while( (wasQuiet || nowQuiet) && (next = next->getProvider())); 3279 3280 return( result ); 3281} 3282 3283void IOService::adjustBusy( SInt32 delta ) 3284{ 3285 lockForArbitration(); 3286 _adjustBusy( delta ); 3287 unlockForArbitration(); 3288} 3289 3290uint64_t IOService::getAccumulatedBusyTime( void ) 3291{ 3292 uint64_t accumBusy = __accumBusy; 3293 uint64_t timeBusy = __timeBusy; 3294 uint64_t nano; 3295 3296 do 3297 { 3298 accumBusy = __accumBusy; 3299 timeBusy = __timeBusy; 3300 if (timeBusy) 3301 accumBusy += mach_absolute_time() - timeBusy; 3302 } 3303 while (timeBusy != __timeBusy); 3304 3305 absolutetime_to_nanoseconds(*(AbsoluteTime *)&accumBusy, &nano); 3306 3307 return (nano); 3308} 3309 3310UInt32 IOService::getBusyState( void ) 3311{ 3312 return( __state[1] & kIOServiceBusyStateMask ); 3313} 3314 3315IOReturn IOService::waitForState( UInt32 mask, UInt32 value, 3316 mach_timespec_t * timeout ) 3317{ 3318 panic("waitForState"); 3319 return (kIOReturnUnsupported); 3320} 3321 3322IOReturn IOService::waitForState( UInt32 mask, UInt32 value, 3323 uint64_t timeout ) 3324{ 3325 bool wait; 3326 int waitResult = THREAD_AWAKENED; 3327 bool computeDeadline = true; 3328 AbsoluteTime abstime; 3329 3330 do { 3331 lockForArbitration(); 3332 IOLockLock( gIOServiceBusyLock ); 3333 wait = (value != (__state[1] & mask)); 3334 if( wait) { 3335 __state[1] |= kIOServiceBusyWaiterState; 3336 unlockForArbitration(); 3337 if( timeout != UINT64_MAX ) { 3338 if( computeDeadline ) { 3339 AbsoluteTime nsinterval; 3340 nanoseconds_to_absolutetime(timeout, &nsinterval ); 3341 clock_absolutetime_interval_to_deadline(nsinterval, &abstime); 3342 computeDeadline = false; 3343 } 3344 assert_wait_deadline((event_t)this, THREAD_UNINT, __OSAbsoluteTime(abstime)); 3345 } 3346 else 3347 assert_wait((event_t)this, THREAD_UNINT ); 3348 } else 3349 unlockForArbitration(); 3350 IOLockUnlock( gIOServiceBusyLock ); 3351 if( wait) 3352 waitResult = thread_block(THREAD_CONTINUE_NULL); 3353 3354 } while( wait && (waitResult != THREAD_TIMED_OUT)); 3355 3356 if( waitResult == THREAD_TIMED_OUT) 3357 return( kIOReturnTimeout ); 3358 else 3359 return( kIOReturnSuccess ); 3360} 3361 3362IOReturn IOService::waitQuiet( uint64_t timeout ) 3363{ 3364 IOReturn ret; 3365 ret = waitForState( kIOServiceBusyStateMask, 0, timeout ); 3366 if ((kIOReturnTimeout == ret) && (timeout >= 30000000000) && (kIOWaitQuietPanics & gIOKitDebug)) 3367 { 3368 panic("IOService 0x%llx (%s) busy timeout", getRegistryEntryID(), getName()); 3369 } 3370 return (ret); 3371} 3372 3373IOReturn IOService::waitQuiet( mach_timespec_t * timeout ) 3374{ 3375 uint64_t timeoutNS; 3376 3377 if (timeout) 3378 { 3379 timeoutNS = timeout->tv_sec; 3380 timeoutNS *= kSecondScale; 3381 timeoutNS += timeout->tv_nsec; 3382 } 3383 else 3384 timeoutNS = UINT64_MAX; 3385 3386 return (waitQuiet(timeoutNS)); 3387} 3388 3389bool IOService::serializeProperties( OSSerialize * s ) const 3390{ 3391#if 0 3392 ((IOService *)this)->setProperty( ((IOService *)this)->__state, 3393 sizeof( __state), "__state"); 3394#endif 3395 return( super::serializeProperties(s) ); 3396} 3397 3398 3399void _IOConfigThread::main(void * arg, wait_result_t result) 3400{ 3401 _IOConfigThread * self = (_IOConfigThread *) arg; 3402 _IOServiceJob * job; 3403 IOService * nub; 3404 bool alive = true; 3405 kern_return_t kr; 3406 thread_precedence_policy_data_t precedence = { -1 }; 3407 3408 kr = thread_policy_set(current_thread(), 3409 THREAD_PRECEDENCE_POLICY, 3410 (thread_policy_t) &precedence, 3411 THREAD_PRECEDENCE_POLICY_COUNT); 3412 if (KERN_SUCCESS != kr) 3413 IOLog("thread_policy_set(%d)\n", kr); 3414 3415 do { 3416 3417// randomDelay(); 3418 3419 semaphore_wait( gJobsSemaphore ); 3420 3421 IOTakeLock( gJobsLock ); 3422 job = (_IOServiceJob *) gJobs->getFirstObject(); 3423 job->retain(); 3424 gJobs->removeObject(job); 3425 if( job) { 3426 gOutstandingJobs--; 3427// gNumConfigThreads--; // we're out of service 3428 gNumWaitingThreads--; // we're out of service 3429 } 3430 IOUnlock( gJobsLock ); 3431 3432 if( job) { 3433 3434 nub = job->nub; 3435 3436 if( gIOKitDebug & kIOLogConfig) 3437 LOG("config(%p): starting on %s, %d\n", 3438 OBFUSCATE(IOThreadSelf()), job->nub->getName(), job->type); 3439 3440 switch( job->type) { 3441 3442 case kMatchNubJob: 3443 nub->doServiceMatch( job->options ); 3444 break; 3445 3446 default: 3447 LOG("config(%p): strange type (%d)\n", 3448 OBFUSCATE(IOThreadSelf()), job->type ); 3449 break; 3450 } 3451 3452 nub->release(); 3453 job->release(); 3454 3455 IOTakeLock( gJobsLock ); 3456 alive = (gOutstandingJobs > gNumWaitingThreads); 3457 if( alive) 3458 gNumWaitingThreads++; // back in service 3459// gNumConfigThreads++; 3460 else { 3461 if( 0 == --gNumConfigThreads) { 3462// IOLog("MATCH IDLE\n"); 3463 IOLockWakeup( gJobsLock, (event_t) &gNumConfigThreads, /* one-thread */ false ); 3464 } 3465 } 3466 IOUnlock( gJobsLock ); 3467 } 3468 3469 } while( alive ); 3470 3471 if( gIOKitDebug & kIOLogConfig) 3472 LOG("config(%p): terminating\n", OBFUSCATE(IOThreadSelf()) ); 3473 3474 self->release(); 3475} 3476 3477IOReturn IOService::waitMatchIdle( UInt32 msToWait ) 3478{ 3479 bool wait; 3480 int waitResult = THREAD_AWAKENED; 3481 bool computeDeadline = true; 3482 AbsoluteTime deadline; 3483 3484 IOLockLock( gJobsLock ); 3485 do { 3486 wait = (0 != gNumConfigThreads); 3487 if( wait) { 3488 if( msToWait) { 3489 if( computeDeadline ) { 3490 clock_interval_to_deadline( 3491 msToWait, kMillisecondScale, &deadline ); 3492 computeDeadline = false; 3493 } 3494 waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads, 3495 deadline, THREAD_UNINT ); 3496 } else { 3497 waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads, 3498 THREAD_UNINT ); 3499 } 3500 } 3501 } while( wait && (waitResult != THREAD_TIMED_OUT)); 3502 IOLockUnlock( gJobsLock ); 3503 3504 if( waitResult == THREAD_TIMED_OUT) 3505 return( kIOReturnTimeout ); 3506 else 3507 return( kIOReturnSuccess ); 3508} 3509 3510void _IOServiceJob::pingConfig( _IOServiceJob * job ) 3511{ 3512 int count; 3513 bool create; 3514 3515 assert( job ); 3516 3517 IOTakeLock( gJobsLock ); 3518 3519 gOutstandingJobs++; 3520 gJobs->setLastObject( job ); 3521 3522 count = gNumWaitingThreads; 3523// if( gNumConfigThreads) count++;// assume we're called from a config thread 3524 3525 create = ( (gOutstandingJobs > count) 3526 && (gNumConfigThreads < kMaxConfigThreads) ); 3527 if( create) { 3528 gNumConfigThreads++; 3529 gNumWaitingThreads++; 3530 } 3531 3532 IOUnlock( gJobsLock ); 3533 3534 job->release(); 3535 3536 if( create) { 3537 if( gIOKitDebug & kIOLogConfig) 3538 LOG("config(%d): creating\n", gNumConfigThreads - 1); 3539 _IOConfigThread::configThread(); 3540 } 3541 3542 semaphore_signal( gJobsSemaphore ); 3543} 3544 3545struct IOServiceMatchContext 3546{ 3547 OSDictionary * table; 3548 OSObject * result; 3549 uint32_t options; 3550 uint32_t state; 3551 uint32_t count; 3552 uint32_t done; 3553}; 3554 3555bool IOService::instanceMatch(const OSObject * entry, void * context) 3556{ 3557 IOServiceMatchContext * ctx = (typeof(ctx)) context; 3558 IOService * service = (typeof(service)) entry; 3559 OSDictionary * table = ctx->table; 3560 uint32_t options = ctx->options; 3561 uint32_t state = ctx->state; 3562 uint32_t done; 3563 bool match; 3564 3565 done = 0; 3566 do 3567 { 3568 match = ((state == (state & service->__state[0])) 3569 && (0 == (service->__state[0] & kIOServiceInactiveState))); 3570 if (!match) break; 3571 ctx->count += table->getCount(); 3572 match = service->matchInternal(table, options, &done); 3573 ctx->done += done; 3574 } 3575 while (false); 3576 if (!match) 3577 return (false); 3578 3579 if ((kIONotifyOnce & options) && (ctx->done == ctx->count)) 3580 { 3581 service->retain(); 3582 ctx->result = service; 3583 return (true); 3584 } 3585 else if (!ctx->result) 3586 { 3587 ctx->result = OSSet::withObjects((const OSObject **) &service, 1, 1); 3588 } 3589 else 3590 { 3591 ((OSSet *)ctx->result)->setObject(service); 3592 } 3593 return (false); 3594} 3595 3596// internal - call with gNotificationLock 3597OSObject * IOService::copyExistingServices( OSDictionary * matching, 3598 IOOptionBits inState, IOOptionBits options ) 3599{ 3600 OSObject * current = 0; 3601 OSIterator * iter; 3602 IOService * service; 3603 OSObject * obj; 3604 OSString * str; 3605 3606 if( !matching) 3607 return( 0 ); 3608 3609#if MATCH_DEBUG 3610 OSSerialize * s = OSSerialize::withCapacity(128); 3611 matching->serialize(s); 3612#endif 3613 3614 if((obj = matching->getObject(gIOProviderClassKey)) 3615 && gIOResourcesKey 3616 && gIOResourcesKey->isEqualTo(obj) 3617 && (service = gIOResources)) 3618 { 3619 if( (inState == (service->__state[0] & inState)) 3620 && (0 == (service->__state[0] & kIOServiceInactiveState)) 3621 && service->matchPassive(matching, options)) 3622 { 3623 if( options & kIONotifyOnce) 3624 { 3625 service->retain(); 3626 current = service; 3627 } 3628 else 3629 current = OSSet::withObjects((const OSObject **) &service, 1, 1 ); 3630 } 3631 } 3632 else 3633 { 3634 IOServiceMatchContext ctx; 3635 ctx.table = matching; 3636 ctx.state = inState; 3637 ctx.count = 0; 3638 ctx.done = 0; 3639 ctx.options = options; 3640 ctx.result = 0; 3641 3642 if ((str = OSDynamicCast(OSString, obj))) 3643 { 3644 const OSSymbol * sym = OSSymbol::withString(str); 3645 OSMetaClass::applyToInstancesOfClassName(sym, instanceMatch, &ctx); 3646 sym->release(); 3647 } 3648 else 3649 { 3650 IOService::gMetaClass.applyToInstances(instanceMatch, &ctx); 3651 } 3652 3653 3654 current = ctx.result; 3655 3656 options |= kIOServiceInternalDone | kIOServiceClassDone; 3657 if (current && (ctx.done != ctx.count)) 3658 { 3659 OSSet * 3660 source = OSDynamicCast(OSSet, current); 3661 current = 0; 3662 while ((service = (IOService *) source->getAnyObject())) 3663 { 3664 if (service->matchPassive(matching, options)) 3665 { 3666 if( options & kIONotifyOnce) 3667 { 3668 service->retain(); 3669 current = service; 3670 break; 3671 } 3672 if( current) 3673 { 3674 ((OSSet *)current)->setObject( service ); 3675 } 3676 else 3677 { 3678 current = OSSet::withObjects( 3679 (const OSObject **) &service, 1, 1 ); 3680 } 3681 } 3682 source->removeObject(service); 3683 } 3684 source->release(); 3685 } 3686 } 3687 3688#if MATCH_DEBUG 3689 { 3690 OSObject * _current = 0; 3691 3692 iter = IORegistryIterator::iterateOver( gIOServicePlane, 3693 kIORegistryIterateRecursively ); 3694 if( iter) { 3695 do { 3696 iter->reset(); 3697 while( (service = (IOService *) iter->getNextObject())) { 3698 if( (inState == (service->__state[0] & inState)) 3699 && (0 == (service->__state[0] & kIOServiceInactiveState)) 3700 && service->matchPassive(matching, 0)) { 3701 3702 if( options & kIONotifyOnce) { 3703 service->retain(); 3704 _current = service; 3705 break; 3706 } 3707 if( _current) 3708 ((OSSet *)_current)->setObject( service ); 3709 else 3710 _current = OSSet::withObjects( 3711 (const OSObject **) &service, 1, 1 ); 3712 } 3713 } 3714 } while( !service && !iter->isValid()); 3715 iter->release(); 3716 } 3717 3718 3719 if ( ((current != 0) != (_current != 0)) 3720 || (current && _current && !current->isEqualTo(_current))) 3721 { 3722 OSSerialize * s1 = OSSerialize::withCapacity(128); 3723 OSSerialize * s2 = OSSerialize::withCapacity(128); 3724 current->serialize(s1); 3725 _current->serialize(s2); 3726 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", OBFUSCATE(current), 3727 OBFUSCATE(_current), s->text(), s1->text(), s2->text()); 3728 s1->release(); 3729 s2->release(); 3730 } 3731 3732 if (_current) _current->release(); 3733 } 3734 3735 s->release(); 3736#endif 3737 3738 if( current && (0 == (options & (kIONotifyOnce | kIOServiceExistingSet)))) { 3739 iter = OSCollectionIterator::withCollection( (OSSet *)current ); 3740 current->release(); 3741 current = iter; 3742 } 3743 3744 return( current ); 3745} 3746 3747// public version 3748OSIterator * IOService::getMatchingServices( OSDictionary * matching ) 3749{ 3750 OSIterator * iter; 3751 3752 // is a lock even needed? 3753 LOCKWRITENOTIFY(); 3754 3755 iter = (OSIterator *) copyExistingServices( matching, 3756 kIOServiceMatchedState ); 3757 3758 UNLOCKNOTIFY(); 3759 3760 return( iter ); 3761} 3762 3763IOService * IOService::copyMatchingService( OSDictionary * matching ) 3764{ 3765 IOService * service; 3766 3767 // is a lock even needed? 3768 LOCKWRITENOTIFY(); 3769 3770 service = (IOService *) copyExistingServices( matching, 3771 kIOServiceMatchedState, kIONotifyOnce ); 3772 3773 UNLOCKNOTIFY(); 3774 3775 return( service ); 3776} 3777 3778struct _IOServiceMatchingNotificationHandlerRef 3779{ 3780 IOServiceNotificationHandler handler; 3781 void * ref; 3782}; 3783 3784static bool _IOServiceMatchingNotificationHandler( void * target, void * refCon, 3785 IOService * newService, 3786 IONotifier * notifier ) 3787{ 3788 return ((*((_IOServiceNotifier *) notifier)->compatHandler)(target, refCon, newService)); 3789} 3790 3791// internal - call with gNotificationLock 3792IONotifier * IOService::setNotification( 3793 const OSSymbol * type, OSDictionary * matching, 3794 IOServiceMatchingNotificationHandler handler, void * target, void * ref, 3795 SInt32 priority ) 3796{ 3797 _IOServiceNotifier * notify = 0; 3798 OSOrderedSet * set; 3799 3800 if( !matching) 3801 return( 0 ); 3802 3803 notify = new _IOServiceNotifier; 3804 if( notify && !notify->init()) { 3805 notify->release(); 3806 notify = 0; 3807 } 3808 3809 if( notify) { 3810 notify->handler = handler; 3811 notify->target = target; 3812 notify->matching = matching; 3813 matching->retain(); 3814 if (handler == &_IOServiceMatchingNotificationHandler) 3815 { 3816 notify->compatHandler = ((_IOServiceMatchingNotificationHandlerRef *)ref)->handler; 3817 notify->ref = ((_IOServiceMatchingNotificationHandlerRef *)ref)->ref; 3818 } 3819 else 3820 notify->ref = ref; 3821 notify->priority = priority; 3822 notify->state = kIOServiceNotifyEnable; 3823 queue_init( ¬ify->handlerInvocations ); 3824 3825 ////// queue 3826 3827 if( 0 == (set = (OSOrderedSet *) gNotifications->getObject( type ))) { 3828 set = OSOrderedSet::withCapacity( 1, 3829 IONotifyOrdering, 0 ); 3830 if( set) { 3831 gNotifications->setObject( type, set ); 3832 set->release(); 3833 } 3834 } 3835 notify->whence = set; 3836 if( set) 3837 set->setObject( notify ); 3838 } 3839 3840 return( notify ); 3841} 3842 3843// internal - call with gNotificationLock 3844IONotifier * IOService::doInstallNotification( 3845 const OSSymbol * type, OSDictionary * matching, 3846 IOServiceMatchingNotificationHandler handler, 3847 void * target, void * ref, 3848 SInt32 priority, OSIterator ** existing ) 3849{ 3850 OSIterator * exist; 3851 IONotifier * notify; 3852 IOOptionBits inState; 3853 3854 if( !matching) 3855 return( 0 ); 3856 3857 if( type == gIOPublishNotification) 3858 inState = kIOServiceRegisteredState; 3859 3860 else if( type == gIOFirstPublishNotification) 3861 inState = kIOServiceFirstPublishState; 3862 3863 else if( (type == gIOMatchedNotification) 3864 || (type == gIOFirstMatchNotification)) 3865 inState = kIOServiceMatchedState; 3866 else if( type == gIOTerminatedNotification) 3867 inState = 0; 3868 else 3869 return( 0 ); 3870 3871 notify = setNotification( type, matching, handler, target, ref, priority ); 3872 3873 if( inState) 3874 // get the current set 3875 exist = (OSIterator *) copyExistingServices( matching, inState ); 3876 else 3877 exist = 0; 3878 3879 *existing = exist; 3880 3881 return( notify ); 3882} 3883 3884#if !defined(__LP64__) 3885IONotifier * IOService::installNotification(const OSSymbol * type, OSDictionary * matching, 3886 IOServiceNotificationHandler handler, 3887 void * target, void * refCon, 3888 SInt32 priority, OSIterator ** existing ) 3889{ 3890 IONotifier * result; 3891 _IOServiceMatchingNotificationHandlerRef ref; 3892 ref.handler = handler; 3893 ref.ref = refCon; 3894 3895 result = (_IOServiceNotifier *) installNotification( type, matching, 3896 &_IOServiceMatchingNotificationHandler, 3897 target, &ref, priority, existing ); 3898 if (result) 3899 matching->release(); 3900 3901 return (result); 3902} 3903#endif /* !defined(__LP64__) */ 3904 3905 3906IONotifier * IOService::installNotification( 3907 const OSSymbol * type, OSDictionary * matching, 3908 IOServiceMatchingNotificationHandler handler, 3909 void * target, void * ref, 3910 SInt32 priority, OSIterator ** existing ) 3911{ 3912 IONotifier * notify; 3913 3914 LOCKWRITENOTIFY(); 3915 3916 notify = doInstallNotification( type, matching, handler, target, ref, 3917 priority, existing ); 3918 3919 UNLOCKNOTIFY(); 3920 3921 return( notify ); 3922} 3923 3924IONotifier * IOService::addNotification( 3925 const OSSymbol * type, OSDictionary * matching, 3926 IOServiceNotificationHandler handler, 3927 void * target, void * refCon, 3928 SInt32 priority ) 3929{ 3930 IONotifier * result; 3931 _IOServiceMatchingNotificationHandlerRef ref; 3932 3933 ref.handler = handler; 3934 ref.ref = refCon; 3935 3936 result = addMatchingNotification(type, matching, &_IOServiceMatchingNotificationHandler, 3937 target, &ref, priority); 3938 3939 if (result) 3940 matching->release(); 3941 3942 return (result); 3943} 3944 3945IONotifier * IOService::addMatchingNotification( 3946 const OSSymbol * type, OSDictionary * matching, 3947 IOServiceMatchingNotificationHandler handler, 3948 void * target, void * ref, 3949 SInt32 priority ) 3950{ 3951 OSIterator * existing = NULL; 3952 _IOServiceNotifier * notify; 3953 IOService * next; 3954 3955 notify = (_IOServiceNotifier *) installNotification( type, matching, 3956 handler, target, ref, priority, &existing ); 3957 3958 // send notifications for existing set 3959 if( existing) { 3960 3961 notify->retain(); // in case handler remove()s 3962 while( (next = (IOService *) existing->getNextObject())) { 3963 3964 next->lockForArbitration(); 3965 if( 0 == (next->__state[0] & kIOServiceInactiveState)) 3966 next->invokeNotifer( notify ); 3967 next->unlockForArbitration(); 3968 } 3969 notify->release(); 3970 existing->release(); 3971 } 3972 3973 return( notify ); 3974} 3975 3976bool IOService::syncNotificationHandler( 3977 void * /* target */, void * ref, 3978 IOService * newService, 3979 IONotifier * notifier ) 3980{ 3981 3982 LOCKWRITENOTIFY(); 3983 if (!*((IOService **) ref)) 3984 { 3985 newService->retain(); 3986 (*(IOService **) ref) = newService; 3987 WAKEUPNOTIFY(ref); 3988 } 3989 UNLOCKNOTIFY(); 3990 3991 return( false ); 3992} 3993 3994IOService * IOService::waitForMatchingService( OSDictionary * matching, 3995 uint64_t timeout) 3996{ 3997 IONotifier * notify = 0; 3998 // priority doesn't help us much since we need a thread wakeup 3999 SInt32 priority = 0; 4000 IOService * result; 4001 4002 if (!matching) 4003 return( 0 ); 4004 4005 result = NULL; 4006 4007 LOCKWRITENOTIFY(); 4008 do 4009 { 4010 result = (IOService *) copyExistingServices( matching, 4011 kIOServiceMatchedState, kIONotifyOnce ); 4012 if (result) 4013 break; 4014 notify = IOService::setNotification( gIOMatchedNotification, matching, 4015 &IOService::syncNotificationHandler, (void *) 0, 4016 &result, priority ); 4017 if (!notify) 4018 break; 4019 if (UINT64_MAX != timeout) 4020 { 4021 AbsoluteTime deadline; 4022 nanoseconds_to_absolutetime(timeout, &deadline); 4023 clock_absolutetime_interval_to_deadline(deadline, &deadline); 4024 SLEEPNOTIFYTO(&result, deadline); 4025 } 4026 else 4027 { 4028 SLEEPNOTIFY(&result); 4029 } 4030 } 4031 while( false ); 4032 4033 UNLOCKNOTIFY(); 4034 4035 if (notify) 4036 notify->remove(); // dequeues 4037 4038 return( result ); 4039} 4040 4041IOService * IOService::waitForService( OSDictionary * matching, 4042 mach_timespec_t * timeout ) 4043{ 4044 IOService * result; 4045 uint64_t timeoutNS; 4046 4047 if (timeout) 4048 { 4049 timeoutNS = timeout->tv_sec; 4050 timeoutNS *= kSecondScale; 4051 timeoutNS += timeout->tv_nsec; 4052 } 4053 else 4054 timeoutNS = UINT64_MAX; 4055 4056 result = waitForMatchingService(matching, timeoutNS); 4057 4058 matching->release(); 4059 if (result) 4060 result->release(); 4061 4062 return (result); 4063} 4064 4065void IOService::deliverNotification( const OSSymbol * type, 4066 IOOptionBits orNewState, IOOptionBits andNewState ) 4067{ 4068 _IOServiceNotifier * notify; 4069 OSIterator * iter; 4070 OSArray * willSend = 0; 4071 4072 lockForArbitration(); 4073 4074 if( (0 == (__state[0] & kIOServiceInactiveState)) 4075 || (type == gIOTerminatedNotification)) { 4076 4077 LOCKREADNOTIFY(); 4078 4079 iter = OSCollectionIterator::withCollection( (OSOrderedSet *) 4080 gNotifications->getObject( type ) ); 4081 4082 if( iter) { 4083 while( (notify = (_IOServiceNotifier *) iter->getNextObject())) { 4084 4085 if( matchPassive(notify->matching, 0) 4086 && (kIOServiceNotifyEnable & notify->state)) { 4087 if( 0 == willSend) 4088 willSend = OSArray::withCapacity(8); 4089 if( willSend) 4090 willSend->setObject( notify ); 4091 } 4092 } 4093 iter->release(); 4094 } 4095 4096 __state[0] = (__state[0] | orNewState) & andNewState; 4097 4098 UNLOCKNOTIFY(); 4099 } 4100 4101 if( willSend) { 4102 for( unsigned int idx = 0; 4103 (notify = (_IOServiceNotifier *) willSend->getObject(idx)); 4104 idx++) { 4105 invokeNotifer( notify ); 4106 } 4107 willSend->release(); 4108 } 4109 unlockForArbitration(); 4110} 4111 4112IOOptionBits IOService::getState( void ) const 4113{ 4114 return( __state[0] ); 4115} 4116 4117/* 4118 * Helpers to make matching objects for simple cases 4119 */ 4120 4121OSDictionary * IOService::serviceMatching( const OSString * name, 4122 OSDictionary * table ) 4123{ 4124 4125 const OSString * str; 4126 4127 str = OSSymbol::withString(name); 4128 if( !str) 4129 return( 0 ); 4130 4131 if( !table) 4132 table = OSDictionary::withCapacity( 2 ); 4133 if( table) 4134 table->setObject(gIOProviderClassKey, (OSObject *)str ); 4135 str->release(); 4136 4137 return( table ); 4138} 4139 4140OSDictionary * IOService::serviceMatching( const char * name, 4141 OSDictionary * table ) 4142{ 4143 const OSString * str; 4144 4145 str = OSSymbol::withCString( name ); 4146 if( !str) 4147 return( 0 ); 4148 4149 table = serviceMatching( str, table ); 4150 str->release(); 4151 return( table ); 4152} 4153 4154OSDictionary * IOService::nameMatching( const OSString * name, 4155 OSDictionary * table ) 4156{ 4157 if( !table) 4158 table = OSDictionary::withCapacity( 2 ); 4159 if( table) 4160 table->setObject( gIONameMatchKey, (OSObject *)name ); 4161 4162 return( table ); 4163} 4164 4165OSDictionary * IOService::nameMatching( const char * name, 4166 OSDictionary * table ) 4167{ 4168 const OSString * str; 4169 4170 str = OSSymbol::withCString( name ); 4171 if( !str) 4172 return( 0 ); 4173 4174 table = nameMatching( str, table ); 4175 str->release(); 4176 return( table ); 4177} 4178 4179OSDictionary * IOService::resourceMatching( const OSString * str, 4180 OSDictionary * table ) 4181{ 4182 table = serviceMatching( gIOResourcesKey, table ); 4183 if( table) 4184 table->setObject( gIOResourceMatchKey, (OSObject *) str ); 4185 4186 return( table ); 4187} 4188 4189OSDictionary * IOService::resourceMatching( const char * name, 4190 OSDictionary * table ) 4191{ 4192 const OSSymbol * str; 4193 4194 str = OSSymbol::withCString( name ); 4195 if( !str) 4196 return( 0 ); 4197 4198 table = resourceMatching( str, table ); 4199 str->release(); 4200 4201 return( table ); 4202} 4203 4204OSDictionary * IOService::propertyMatching( const OSSymbol * key, const OSObject * value, 4205 OSDictionary * table ) 4206{ 4207 OSDictionary * properties; 4208 4209 properties = OSDictionary::withCapacity( 2 ); 4210 if( !properties) 4211 return( 0 ); 4212 properties->setObject( key, value ); 4213 4214 if( !table) 4215 table = OSDictionary::withCapacity( 2 ); 4216 if( table) 4217 table->setObject( gIOPropertyMatchKey, properties ); 4218 4219 properties->release(); 4220 4221 return( table ); 4222} 4223 4224OSDictionary * IOService::registryEntryIDMatching( uint64_t entryID, 4225 OSDictionary * table ) 4226{ 4227 OSNumber * num; 4228 4229 num = OSNumber::withNumber( entryID, 64 ); 4230 if( !num) 4231 return( 0 ); 4232 4233 if( !table) 4234 table = OSDictionary::withCapacity( 2 ); 4235 if( table) 4236 table->setObject( gIORegistryEntryIDKey, num ); 4237 4238 if (num) 4239 num->release(); 4240 4241 return( table ); 4242} 4243 4244 4245/* 4246 * _IOServiceNotifier 4247 */ 4248 4249// wait for all threads, other than the current one, 4250// to exit the handler 4251 4252void _IOServiceNotifier::wait() 4253{ 4254 _IOServiceNotifierInvocation * next; 4255 bool doWait; 4256 4257 do { 4258 doWait = false; 4259 queue_iterate( &handlerInvocations, next, 4260 _IOServiceNotifierInvocation *, link) { 4261 if( next->thread != current_thread() ) { 4262 doWait = true; 4263 break; 4264 } 4265 } 4266 if( doWait) { 4267 state |= kIOServiceNotifyWaiter; 4268 SLEEPNOTIFY(this); 4269 } 4270 4271 } while( doWait ); 4272} 4273 4274void _IOServiceNotifier::free() 4275{ 4276 assert( queue_empty( &handlerInvocations )); 4277 OSObject::free(); 4278} 4279 4280void _IOServiceNotifier::remove() 4281{ 4282 LOCKWRITENOTIFY(); 4283 4284 if( whence) { 4285 whence->removeObject( (OSObject *) this ); 4286 whence = 0; 4287 } 4288 if( matching) { 4289 matching->release(); 4290 matching = 0; 4291 } 4292 4293 state &= ~kIOServiceNotifyEnable; 4294 4295 wait(); 4296 4297 UNLOCKNOTIFY(); 4298 4299 release(); 4300} 4301 4302bool _IOServiceNotifier::disable() 4303{ 4304 bool ret; 4305 4306 LOCKWRITENOTIFY(); 4307 4308 ret = (0 != (kIOServiceNotifyEnable & state)); 4309 state &= ~kIOServiceNotifyEnable; 4310 if( ret) 4311 wait(); 4312 4313 UNLOCKNOTIFY(); 4314 4315 return( ret ); 4316} 4317 4318void _IOServiceNotifier::enable( bool was ) 4319{ 4320 LOCKWRITENOTIFY(); 4321 if( was) 4322 state |= kIOServiceNotifyEnable; 4323 else 4324 state &= ~kIOServiceNotifyEnable; 4325 UNLOCKNOTIFY(); 4326} 4327 4328/* 4329 * IOResources 4330 */ 4331 4332IOService * IOResources::resources( void ) 4333{ 4334 IOResources * inst; 4335 4336 inst = new IOResources; 4337 if( inst && !inst->init()) { 4338 inst->release(); 4339 inst = 0; 4340 } 4341 4342 return( inst ); 4343} 4344 4345bool IOResources::init( OSDictionary * dictionary ) 4346{ 4347 // Do super init first 4348 if ( !super::init() ) 4349 return false; 4350 4351 // Allow PAL layer to publish a value 4352 const char *property_name; 4353 int property_value; 4354 4355 pal_get_resource_property( &property_name, &property_value ); 4356 4357 if( property_name ) { 4358 OSNumber *num; 4359 const OSSymbol * sym; 4360 4361 if( (num = OSNumber::withNumber(property_value, 32)) != 0 ) { 4362 if( (sym = OSSymbol::withCString( property_name)) != 0 ) { 4363 this->setProperty( sym, num ); 4364 sym->release(); 4365 } 4366 num->release(); 4367 } 4368 } 4369 4370 return true; 4371} 4372 4373IOWorkLoop * IOResources::getWorkLoop() const 4374{ 4375 // If we are the resource root 4376 // then use the platform's workloop 4377 if (this == (IOResources *) gIOResources) 4378 return getPlatform()->getWorkLoop(); 4379 else 4380 return IOService::getWorkLoop(); 4381} 4382 4383bool IOResources::matchPropertyTable( OSDictionary * table ) 4384{ 4385 OSObject * prop; 4386 OSString * str; 4387 OSSet * set; 4388 OSIterator * iter; 4389 bool ok = true; 4390 4391 prop = table->getObject( gIOResourceMatchKey ); 4392 str = OSDynamicCast( OSString, prop ); 4393 if( str) 4394 ok = (0 != getProperty( str )); 4395 4396 else if( (set = OSDynamicCast( OSSet, prop))) { 4397 4398 iter = OSCollectionIterator::withCollection( set ); 4399 ok = (iter != 0); 4400 while( ok && (str = OSDynamicCast( OSString, iter->getNextObject()) )) 4401 ok = (0 != getProperty( str )); 4402 4403 if( iter) 4404 iter->release(); 4405 } 4406 4407 return( ok ); 4408} 4409 4410void IOService::consoleLockTimer(thread_call_param_t p0, thread_call_param_t p1) 4411{ 4412 IOService::updateConsoleUsers(NULL, 0); 4413} 4414 4415void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessage) 4416{ 4417 IORegistryEntry * regEntry; 4418 OSObject * locked = kOSBooleanFalse; 4419 uint32_t idx; 4420 bool publish; 4421 OSDictionary * user; 4422 static IOMessage sSystemPower; 4423 4424 regEntry = IORegistryEntry::getRegistryRoot(); 4425 4426 if (!gIOChosenEntry) 4427 gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane); 4428 4429 IOLockLock(gIOConsoleUsersLock); 4430 4431 if (systemMessage) 4432 { 4433 sSystemPower = systemMessage; 4434#if HIBERNATION 4435 if ((kIOMessageSystemHasPoweredOn == systemMessage) && IOHibernateWasScreenLocked()) 4436 { 4437 locked = kOSBooleanTrue; 4438 } 4439#endif /* HIBERNATION */ 4440 } 4441 4442 if (consoleUsers) 4443 { 4444 OSNumber * num = 0; 4445 gIOConsoleLoggedIn = false; 4446 for (idx = 0; 4447 (user = OSDynamicCast(OSDictionary, consoleUsers->getObject(idx))); 4448 idx++) 4449 { 4450 gIOConsoleLoggedIn |= ((kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey)) 4451 && (kOSBooleanTrue == user->getObject(gIOConsoleSessionLoginDoneKey))); 4452 if (!num) 4453 { 4454 num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionScreenLockedTimeKey)); 4455 } 4456 } 4457 gIOConsoleLockTime = num ? num->unsigned32BitValue() : 0; 4458 } 4459 4460 if (!gIOConsoleLoggedIn 4461 || (kIOMessageSystemWillSleep == sSystemPower) 4462 || (kIOMessageSystemPagingOff == sSystemPower)) 4463 { 4464 locked = kOSBooleanTrue; 4465 } 4466 else if (gIOConsoleLockTime) 4467 { 4468 clock_sec_t now; 4469 clock_usec_t microsecs; 4470 4471 clock_get_calendar_microtime(&now, µsecs); 4472 if (gIOConsoleLockTime > now) 4473 { 4474 AbsoluteTime deadline; 4475 clock_interval_to_deadline(gIOConsoleLockTime - now, kSecondScale, &deadline); 4476 thread_call_enter_delayed(gIOConsoleLockCallout, deadline); 4477 } 4478 else 4479 { 4480 locked = kOSBooleanTrue; 4481 } 4482 } 4483 4484 publish = (consoleUsers || (locked != regEntry->getProperty(gIOConsoleLockedKey))); 4485 if (publish) 4486 { 4487 regEntry->setProperty(gIOConsoleLockedKey, locked); 4488 if (consoleUsers) 4489 { 4490 regEntry->setProperty(gIOConsoleUsersKey, consoleUsers); 4491 } 4492 OSIncrementAtomic( &gIOConsoleUsersSeed ); 4493 } 4494 4495#if HIBERNATION 4496 if (gIOChosenEntry) 4497 { 4498 if (locked == kOSBooleanTrue) gIOScreenLockState = kIOScreenLockLocked; 4499 else if (gIOConsoleLockTime) gIOScreenLockState = kIOScreenLockUnlocked; 4500 else gIOScreenLockState = kIOScreenLockNoLock; 4501 gIOChosenEntry->setProperty(kIOScreenLockStateKey, &gIOScreenLockState, sizeof(gIOScreenLockState)); 4502 } 4503#endif /* HIBERNATION */ 4504 4505 IOLockUnlock(gIOConsoleUsersLock); 4506 4507 if (publish) 4508 { 4509 publishResource( gIOConsoleUsersSeedKey, gIOConsoleUsersSeedValue ); 4510 4511 MessageClientsContext context; 4512 4513 context.service = getServiceRoot(); 4514 context.type = kIOMessageConsoleSecurityChange; 4515 context.argument = (void *) regEntry; 4516 context.argSize = 0; 4517 4518 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest, 4519 &messageClientsApplier, &context ); 4520 } 4521} 4522 4523IOReturn IOResources::setProperties( OSObject * properties ) 4524{ 4525 IOReturn err; 4526 const OSSymbol * key; 4527 OSDictionary * dict; 4528 OSCollectionIterator * iter; 4529 4530 err = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator); 4531 if ( kIOReturnSuccess != err) 4532 return( err ); 4533 4534 dict = OSDynamicCast(OSDictionary, properties); 4535 if( 0 == dict) 4536 return( kIOReturnBadArgument); 4537 4538 iter = OSCollectionIterator::withCollection( dict); 4539 if( 0 == iter) 4540 return( kIOReturnBadArgument); 4541 4542 while( (key = OSDynamicCast(OSSymbol, iter->getNextObject()))) 4543 { 4544 if (gIOConsoleUsersKey == key) do 4545 { 4546 OSArray * consoleUsers; 4547 consoleUsers = OSDynamicCast(OSArray, dict->getObject(key)); 4548 if (!consoleUsers) 4549 continue; 4550 IOService::updateConsoleUsers(consoleUsers, 0); 4551 } 4552 while (false); 4553 4554 publishResource( key, dict->getObject(key) ); 4555 } 4556 4557 iter->release(); 4558 4559 return( kIOReturnSuccess ); 4560} 4561 4562/* 4563 * Helpers for matching dictionaries. 4564 * Keys existing in matching are checked in properties. 4565 * Keys may be a string or OSCollection of IOStrings 4566 */ 4567 4568bool IOService::compareProperty( OSDictionary * matching, 4569 const char * key ) 4570{ 4571 OSObject * value; 4572 bool ok; 4573 4574 value = matching->getObject( key ); 4575 if( value) 4576 ok = value->isEqualTo( getProperty( key )); 4577 else 4578 ok = true; 4579 4580 return( ok ); 4581} 4582 4583 4584bool IOService::compareProperty( OSDictionary * matching, 4585 const OSString * key ) 4586{ 4587 OSObject * value; 4588 bool ok; 4589 4590 value = matching->getObject( key ); 4591 if( value) 4592 ok = value->isEqualTo( getProperty( key )); 4593 else 4594 ok = true; 4595 4596 return( ok ); 4597} 4598 4599bool IOService::compareProperties( OSDictionary * matching, 4600 OSCollection * keys ) 4601{ 4602 OSCollectionIterator * iter; 4603 const OSString * key; 4604 bool ok = true; 4605 4606 if( !matching || !keys) 4607 return( false ); 4608 4609 iter = OSCollectionIterator::withCollection( keys ); 4610 4611 if( iter) { 4612 while( ok && (key = OSDynamicCast( OSString, iter->getNextObject()))) 4613 ok = compareProperty( matching, key ); 4614 4615 iter->release(); 4616 } 4617 keys->release(); // !! consume a ref !! 4618 4619 return( ok ); 4620} 4621 4622/* Helper to add a location matching dict to the table */ 4623 4624OSDictionary * IOService::addLocation( OSDictionary * table ) 4625{ 4626 OSDictionary * dict; 4627 4628 if( !table) 4629 return( 0 ); 4630 4631 dict = OSDictionary::withCapacity( 1 ); 4632 if( dict) { 4633 table->setObject( gIOLocationMatchKey, dict ); 4634 dict->release(); 4635 } 4636 4637 return( dict ); 4638} 4639 4640/* 4641 * Go looking for a provider to match a location dict. 4642 */ 4643 4644IOService * IOService::matchLocation( IOService * /* client */ ) 4645{ 4646 IOService * parent; 4647 4648 parent = getProvider(); 4649 4650 if( parent) 4651 parent = parent->matchLocation( this ); 4652 4653 return( parent ); 4654} 4655 4656bool IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t * did) 4657{ 4658 OSString * matched; 4659 OSObject * obj; 4660 OSString * str; 4661 IORegistryEntry * entry; 4662 OSNumber * num; 4663 bool match = true; 4664 bool changesOK = (0 != (kIOServiceChangesOK & options)); 4665 uint32_t count; 4666 uint32_t done; 4667 4668 do 4669 { 4670 count = table->getCount(); 4671 done = 0; 4672 str = OSDynamicCast(OSString, table->getObject(gIOProviderClassKey)); 4673 if (str) { 4674 done++; 4675 match = ((kIOServiceClassDone & options) || (0 != metaCast(str))); 4676#if MATCH_DEBUG 4677 match = (0 != metaCast( str )); 4678 if ((kIOServiceClassDone & options) && !match) panic("classDone"); 4679#endif 4680 if ((!match) || (done == count)) break; 4681 } 4682 4683 obj = table->getObject( gIONameMatchKey ); 4684 if( obj) { 4685 done++; 4686 match = compareNames( obj, changesOK ? &matched : 0 ); 4687 if (!match) break; 4688 if( changesOK && matched) { 4689 // leave a hint as to which name matched 4690 table->setObject( gIONameMatchedKey, matched ); 4691 matched->release(); 4692 } 4693 if (done == count) break; 4694 } 4695 4696 str = OSDynamicCast( OSString, table->getObject( gIOLocationMatchKey )); 4697 if (str) 4698 { 4699 const OSSymbol * sym; 4700 done++; 4701 match = false; 4702 sym = copyLocation(); 4703 if (sym) { 4704 match = sym->isEqualTo( str ); 4705 sym->release(); 4706 } 4707 if ((!match) || (done == count)) break; 4708 } 4709 4710 obj = table->getObject( gIOPropertyMatchKey ); 4711 if( obj) 4712 { 4713 OSDictionary * dict; 4714 OSDictionary * nextDict; 4715 OSIterator * iter; 4716 done++; 4717 match = false; 4718 dict = dictionaryWithProperties(); 4719 if( dict) { 4720 nextDict = OSDynamicCast( OSDictionary, obj); 4721 if( nextDict) 4722 iter = 0; 4723 else 4724 iter = OSCollectionIterator::withCollection( 4725 OSDynamicCast(OSCollection, obj)); 4726 4727 while( nextDict 4728 || (iter && (0 != (nextDict = OSDynamicCast(OSDictionary, 4729 iter->getNextObject()))))) { 4730 match = dict->isEqualTo( nextDict, nextDict); 4731 if( match) 4732 break; 4733 nextDict = 0; 4734 } 4735 dict->release(); 4736 if( iter) 4737 iter->release(); 4738 } 4739 if ((!match) || (done == count)) break; 4740 } 4741 4742 str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey )); 4743 if( str) { 4744 done++; 4745 entry = IORegistryEntry::fromPath( str->getCStringNoCopy() ); 4746 match = (this == entry); 4747 if( entry) 4748 entry->release(); 4749 if ((!match) || (done == count)) break; 4750 } 4751 4752 num = OSDynamicCast( OSNumber, table->getObject( gIORegistryEntryIDKey )); 4753 if (num) { 4754 done++; 4755 match = (getRegistryEntryID() == num->unsigned64BitValue()); 4756 if ((!match) || (done == count)) break; 4757 } 4758 4759 num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey )); 4760 if( num) 4761 { 4762 OSIterator * iter; 4763 IOService * service = 0; 4764 UInt32 serviceCount = 0; 4765 4766 done++; 4767 iter = getClientIterator(); 4768 if( iter) { 4769 while( (service = (IOService *) iter->getNextObject())) { 4770 if( kIOServiceInactiveState & service->__state[0]) 4771 continue; 4772 if( 0 == service->getProperty( gIOMatchCategoryKey )) 4773 continue; 4774 ++serviceCount; 4775 } 4776 iter->release(); 4777 } 4778 match = (serviceCount == num->unsigned32BitValue()); 4779 if ((!match) || (done == count)) break; 4780 } 4781 4782#define propMatch(key) \ 4783 obj = table->getObject(key); \ 4784 if (obj) \ 4785 { \ 4786 OSObject * prop; \ 4787 done++; \ 4788 prop = copyProperty(key); \ 4789 match = obj->isEqualTo(prop); \ 4790 if (prop) prop->release(); \ 4791 if ((!match) || (done == count)) break; \ 4792 } 4793 propMatch(kIOBSDNameKey) 4794 propMatch(kIOBSDMajorKey) 4795 propMatch(kIOBSDMinorKey) 4796 propMatch(kIOBSDUnitKey) 4797#undef propMatch 4798 } 4799 while (false); 4800 4801 if (did) *did = done; 4802 return (match); 4803} 4804 4805bool IOService::passiveMatch( OSDictionary * table, bool changesOK ) 4806{ 4807 return (matchPassive(table, changesOK ? kIOServiceChangesOK : 0)); 4808} 4809 4810bool IOService::matchPassive(OSDictionary * table, uint32_t options) 4811{ 4812 IOService * where; 4813 OSDictionary * nextTable; 4814 SInt32 score; 4815 OSNumber * newPri; 4816 bool match = true; 4817 bool matchParent = false; 4818 uint32_t count; 4819 uint32_t done; 4820 4821 assert( table ); 4822 4823#if MATCH_DEBUG 4824 OSDictionary * root = table; 4825#endif 4826 4827 where = this; 4828 do 4829 { 4830 do 4831 { 4832 count = table->getCount(); 4833 if (!(kIOServiceInternalDone & options)) 4834 { 4835 match = where->matchInternal(table, options, &done); 4836 // don't call family if we've done all the entries in the table 4837 if ((!match) || (done == count)) break; 4838 } 4839 4840 // pass in score from property table 4841 score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey); 4842 4843 // do family specific matching 4844 match = where->matchPropertyTable( table, &score ); 4845 4846 if( !match) { 4847#if IOMATCHDEBUG 4848 if( kIOLogMatch & getDebugFlags( table )) 4849 LOG("%s: family specific matching fails\n", where->getName()); 4850#endif 4851 break; 4852 } 4853 4854 if (kIOServiceChangesOK & options) { 4855 // save the score 4856 newPri = OSNumber::withNumber( score, 32 ); 4857 if( newPri) { 4858 table->setObject( gIOProbeScoreKey, newPri ); 4859 newPri->release(); 4860 } 4861 } 4862 4863 options = 0; 4864 matchParent = false; 4865 4866 nextTable = OSDynamicCast(OSDictionary, 4867 table->getObject( gIOParentMatchKey )); 4868 if( nextTable) { 4869 // look for a matching entry anywhere up to root 4870 match = false; 4871 matchParent = true; 4872 table = nextTable; 4873 break; 4874 } 4875 4876 table = OSDynamicCast(OSDictionary, 4877 table->getObject( gIOLocationMatchKey )); 4878 if (table) { 4879 // look for a matching entry at matchLocation() 4880 match = false; 4881 where = where->getProvider(); 4882 if (where && (where = where->matchLocation(where))) continue; 4883 } 4884 break; 4885 } 4886 while (true); 4887 } 4888 while( matchParent && (!match) && (where = where->getProvider()) ); 4889 4890#if MATCH_DEBUG 4891 if (where != this) 4892 { 4893 OSSerialize * s = OSSerialize::withCapacity(128); 4894 root->serialize(s); 4895 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match, s->text()); 4896 s->release(); 4897 } 4898#endif 4899 4900 return( match ); 4901} 4902 4903 4904IOReturn IOService::newUserClient( task_t owningTask, void * securityID, 4905 UInt32 type, OSDictionary * properties, 4906 IOUserClient ** handler ) 4907{ 4908 const OSSymbol *userClientClass = 0; 4909 IOUserClient *client; 4910 OSObject *temp; 4911 4912 if (kIOReturnSuccess == newUserClient( owningTask, securityID, type, handler )) 4913 return kIOReturnSuccess; 4914 4915 // First try my own properties for a user client class name 4916 temp = getProperty(gIOUserClientClassKey); 4917 if (temp) { 4918 if (OSDynamicCast(OSSymbol, temp)) 4919 userClientClass = (const OSSymbol *) temp; 4920 else if (OSDynamicCast(OSString, temp)) { 4921 userClientClass = OSSymbol::withString((OSString *) temp); 4922 if (userClientClass) 4923 setProperty(kIOUserClientClassKey, 4924 (OSObject *) userClientClass); 4925 } 4926 } 4927 4928 // Didn't find one so lets just bomb out now without further ado. 4929 if (!userClientClass) 4930 return kIOReturnUnsupported; 4931 4932 // This reference is consumed by the IOServiceOpen call 4933 temp = OSMetaClass::allocClassWithName(userClientClass); 4934 if (!temp) 4935 return kIOReturnNoMemory; 4936 4937 if (OSDynamicCast(IOUserClient, temp)) 4938 client = (IOUserClient *) temp; 4939 else { 4940 temp->release(); 4941 return kIOReturnUnsupported; 4942 } 4943 4944 if ( !client->initWithTask(owningTask, securityID, type, properties) ) { 4945 client->release(); 4946 return kIOReturnBadArgument; 4947 } 4948 4949 if ( !client->attach(this) ) { 4950 client->release(); 4951 return kIOReturnUnsupported; 4952 } 4953 4954 if ( !client->start(this) ) { 4955 client->detach(this); 4956 client->release(); 4957 return kIOReturnUnsupported; 4958 } 4959 4960 *handler = client; 4961 return kIOReturnSuccess; 4962} 4963 4964IOReturn IOService::newUserClient( task_t owningTask, void * securityID, 4965 UInt32 type, IOUserClient ** handler ) 4966{ 4967 return( kIOReturnUnsupported ); 4968} 4969 4970IOReturn IOService::requestProbe( IOOptionBits options ) 4971{ 4972 return( kIOReturnUnsupported); 4973} 4974 4975/* 4976 * Convert an IOReturn to text. Subclasses which add additional 4977 * IOReturn's should override this method and call 4978 * super::stringFromReturn if the desired value is not found. 4979 */ 4980 4981const char * IOService::stringFromReturn( IOReturn rtn ) 4982{ 4983 static const IONamedValue IOReturn_values[] = { 4984 {kIOReturnSuccess, "success" }, 4985 {kIOReturnError, "general error" }, 4986 {kIOReturnNoMemory, "memory allocation error" }, 4987 {kIOReturnNoResources, "resource shortage" }, 4988 {kIOReturnIPCError, "Mach IPC failure" }, 4989 {kIOReturnNoDevice, "no such device" }, 4990 {kIOReturnNotPrivileged, "privilege violation" }, 4991 {kIOReturnBadArgument, "invalid argument" }, 4992 {kIOReturnLockedRead, "device is read locked" }, 4993 {kIOReturnLockedWrite, "device is write locked" }, 4994 {kIOReturnExclusiveAccess, "device is exclusive access" }, 4995 {kIOReturnBadMessageID, "bad IPC message ID" }, 4996 {kIOReturnUnsupported, "unsupported function" }, 4997 {kIOReturnVMError, "virtual memory error" }, 4998 {kIOReturnInternalError, "internal driver error" }, 4999 {kIOReturnIOError, "I/O error" }, 5000 {kIOReturnCannotLock, "cannot acquire lock" }, 5001 {kIOReturnNotOpen, "device is not open" }, 5002 {kIOReturnNotReadable, "device is not readable" }, 5003 {kIOReturnNotWritable, "device is not writeable" }, 5004 {kIOReturnNotAligned, "alignment error" }, 5005 {kIOReturnBadMedia, "media error" }, 5006 {kIOReturnStillOpen, "device is still open" }, 5007 {kIOReturnRLDError, "rld failure" }, 5008 {kIOReturnDMAError, "DMA failure" }, 5009 {kIOReturnBusy, "device is busy" }, 5010 {kIOReturnTimeout, "I/O timeout" }, 5011 {kIOReturnOffline, "device is offline" }, 5012 {kIOReturnNotReady, "device is not ready" }, 5013 {kIOReturnNotAttached, "device/channel is not attached" }, 5014 {kIOReturnNoChannels, "no DMA channels available" }, 5015 {kIOReturnNoSpace, "no space for data" }, 5016 {kIOReturnPortExists, "device port already exists" }, 5017 {kIOReturnCannotWire, "cannot wire physical memory" }, 5018 {kIOReturnNoInterrupt, "no interrupt attached" }, 5019 {kIOReturnNoFrames, "no DMA frames enqueued" }, 5020 {kIOReturnMessageTooLarge, "message is too large" }, 5021 {kIOReturnNotPermitted, "operation is not permitted" }, 5022 {kIOReturnNoPower, "device is without power" }, 5023 {kIOReturnNoMedia, "media is not present" }, 5024 {kIOReturnUnformattedMedia, "media is not formatted" }, 5025 {kIOReturnUnsupportedMode, "unsupported mode" }, 5026 {kIOReturnUnderrun, "data underrun" }, 5027 {kIOReturnOverrun, "data overrun" }, 5028 {kIOReturnDeviceError, "device error" }, 5029 {kIOReturnNoCompletion, "no completion routine" }, 5030 {kIOReturnAborted, "operation was aborted" }, 5031 {kIOReturnNoBandwidth, "bus bandwidth would be exceeded" }, 5032 {kIOReturnNotResponding, "device is not responding" }, 5033 {kIOReturnInvalid, "unanticipated driver error" }, 5034 {0, NULL } 5035 }; 5036 5037 return IOFindNameForValue(rtn, IOReturn_values); 5038} 5039 5040/* 5041 * Convert an IOReturn to an errno. 5042 */ 5043int IOService::errnoFromReturn( IOReturn rtn ) 5044{ 5045 if (unix_err(err_get_code(rtn)) == rtn) 5046 return err_get_code(rtn); 5047 5048 switch(rtn) { 5049 // (obvious match) 5050 case kIOReturnSuccess: 5051 return(0); 5052 case kIOReturnNoMemory: 5053 return(ENOMEM); 5054 case kIOReturnNoDevice: 5055 return(ENXIO); 5056 case kIOReturnVMError: 5057 return(EFAULT); 5058 case kIOReturnNotPermitted: 5059 return(EPERM); 5060 case kIOReturnNotPrivileged: 5061 return(EACCES); 5062 case kIOReturnIOError: 5063 return(EIO); 5064 case kIOReturnNotWritable: 5065 return(EROFS); 5066 case kIOReturnBadArgument: 5067 return(EINVAL); 5068 case kIOReturnUnsupported: 5069 return(ENOTSUP); 5070 case kIOReturnBusy: 5071 return(EBUSY); 5072 case kIOReturnNoPower: 5073 return(EPWROFF); 5074 case kIOReturnDeviceError: 5075 return(EDEVERR); 5076 case kIOReturnTimeout: 5077 return(ETIMEDOUT); 5078 case kIOReturnMessageTooLarge: 5079 return(EMSGSIZE); 5080 case kIOReturnNoSpace: 5081 return(ENOSPC); 5082 case kIOReturnCannotLock: 5083 return(ENOLCK); 5084 5085 // (best match) 5086 case kIOReturnBadMessageID: 5087 case kIOReturnNoCompletion: 5088 case kIOReturnNotAligned: 5089 return(EINVAL); 5090 case kIOReturnNotReady: 5091 return(EBUSY); 5092 case kIOReturnRLDError: 5093 return(EBADMACHO); 5094 case kIOReturnPortExists: 5095 case kIOReturnStillOpen: 5096 return(EEXIST); 5097 case kIOReturnExclusiveAccess: 5098 case kIOReturnLockedRead: 5099 case kIOReturnLockedWrite: 5100 case kIOReturnNotOpen: 5101 case kIOReturnNotReadable: 5102 return(EACCES); 5103 case kIOReturnCannotWire: 5104 case kIOReturnNoResources: 5105 return(ENOMEM); 5106 case kIOReturnAborted: 5107 case kIOReturnOffline: 5108 case kIOReturnNotResponding: 5109 return(EBUSY); 5110 case kIOReturnBadMedia: 5111 case kIOReturnNoMedia: 5112 case kIOReturnNotAttached: 5113 case kIOReturnUnformattedMedia: 5114 return(ENXIO); // (media error) 5115 case kIOReturnDMAError: 5116 case kIOReturnOverrun: 5117 case kIOReturnUnderrun: 5118 return(EIO); // (transfer error) 5119 case kIOReturnNoBandwidth: 5120 case kIOReturnNoChannels: 5121 case kIOReturnNoFrames: 5122 case kIOReturnNoInterrupt: 5123 return(EIO); // (hardware error) 5124 case kIOReturnError: 5125 case kIOReturnInternalError: 5126 case kIOReturnInvalid: 5127 return(EIO); // (generic error) 5128 case kIOReturnIPCError: 5129 return(EIO); // (ipc error) 5130 default: 5131 return(EIO); // (all other errors) 5132 } 5133} 5134 5135IOReturn IOService::message( UInt32 type, IOService * provider, 5136 void * argument ) 5137{ 5138 /* 5139 * Generic entry point for calls from the provider. A return value of 5140 * kIOReturnSuccess indicates that the message was received, and where 5141 * applicable, that it was successful. 5142 */ 5143 5144 return kIOReturnUnsupported; 5145} 5146 5147/* 5148 * Device memory 5149 */ 5150 5151IOItemCount IOService::getDeviceMemoryCount( void ) 5152{ 5153 OSArray * array; 5154 IOItemCount count; 5155 5156 array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)); 5157 if( array) 5158 count = array->getCount(); 5159 else 5160 count = 0; 5161 5162 return( count); 5163} 5164 5165IODeviceMemory * IOService::getDeviceMemoryWithIndex( unsigned int index ) 5166{ 5167 OSArray * array; 5168 IODeviceMemory * range; 5169 5170 array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)); 5171 if( array) 5172 range = (IODeviceMemory *) array->getObject( index ); 5173 else 5174 range = 0; 5175 5176 return( range); 5177} 5178 5179IOMemoryMap * IOService::mapDeviceMemoryWithIndex( unsigned int index, 5180 IOOptionBits options ) 5181{ 5182 IODeviceMemory * range; 5183 IOMemoryMap * map; 5184 5185 range = getDeviceMemoryWithIndex( index ); 5186 if( range) 5187 map = range->map( options ); 5188 else 5189 map = 0; 5190 5191 return( map ); 5192} 5193 5194OSArray * IOService::getDeviceMemory( void ) 5195{ 5196 return( OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey))); 5197} 5198 5199 5200void IOService::setDeviceMemory( OSArray * array ) 5201{ 5202 setProperty( gIODeviceMemoryKey, array); 5203} 5204 5205/* 5206 * For machines where the transfers on an I/O bus can stall because 5207 * the CPU is in an idle mode, These APIs allow a driver to specify 5208 * the maximum bus stall that they can handle. 0 indicates no limit. 5209 */ 5210void IOService:: 5211setCPUSnoopDelay(UInt32 __unused ns) 5212{ 5213#if defined(__i386__) || defined(__x86_64__) 5214 ml_set_maxsnoop(ns); 5215#endif /* defined(__i386__) || defined(__x86_64__) */ 5216} 5217 5218UInt32 IOService:: 5219getCPUSnoopDelay() 5220{ 5221#if defined(__i386__) || defined(__x86_64__) 5222 return ml_get_maxsnoop(); 5223#else 5224 return 0; 5225#endif /* defined(__i386__) || defined(__x86_64__) */ 5226} 5227 5228#if defined(__i386__) || defined(__x86_64__) 5229static void 5230requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType) 5231{ 5232 static const UInt kNoReplace = -1U; // Must be an illegal index 5233 UInt replace = kNoReplace; 5234 bool setCpuDelay = false; 5235 5236 IORecursiveLockLock(sCpuDelayLock); 5237 5238 UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry); 5239 CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy(); 5240 IOService * holder = NULL; 5241 5242 if (ns) { 5243 const CpuDelayEntry ne = {service, ns, delayType}; 5244 holder = service; 5245 // Set maximum delay. 5246 for (UInt i = 0; i < count; i++) { 5247 IOService *thisService = entries[i].fService; 5248 bool sameType = (delayType == entries[i].fDelayType); 5249 if ((service == thisService) && sameType) 5250 replace = i; 5251 else if (!thisService) { 5252 if (kNoReplace == replace) 5253 replace = i; 5254 } 5255 else if (sameType) { 5256 const UInt32 thisMax = entries[i].fMaxDelay; 5257 if (thisMax < ns) 5258 { 5259 ns = thisMax; 5260 holder = thisService; 5261 } 5262 } 5263 } 5264 5265 setCpuDelay = true; 5266 if (kNoReplace == replace) 5267 sCpuDelayData->appendBytes(&ne, sizeof(ne)); 5268 else 5269 entries[replace] = ne; 5270 } 5271 else { 5272 ns = -1U; // Set to max unsigned, i.e. no restriction 5273 5274 for (UInt i = 0; i < count; i++) { 5275 // Clear a maximum delay. 5276 IOService *thisService = entries[i].fService; 5277 if (thisService && (delayType == entries[i].fDelayType)) { 5278 UInt32 thisMax = entries[i].fMaxDelay; 5279 if (service == thisService) 5280 replace = i; 5281 else if (thisMax < ns) { 5282 ns = thisMax; 5283 holder = thisService; 5284 } 5285 } 5286 } 5287 5288 // Check if entry found 5289 if (kNoReplace != replace) { 5290 entries[replace].fService = 0; // Null the entry 5291 setCpuDelay = true; 5292 } 5293 } 5294 5295 if (setCpuDelay) 5296 { 5297 // Must be safe to call from locked context 5298 if (delayType == kCpuDelayBusStall) 5299 { 5300 ml_set_maxbusdelay(ns); 5301 } 5302 else if (delayType == kCpuDelayInterrupt) 5303 { 5304 ml_set_maxintdelay(ns); 5305 } 5306 5307 OSArray * handlers = sCpuLatencyHandlers[delayType]; 5308 IOService * target; 5309 if (handlers) for (unsigned int idx = 0; 5310 (target = (IOService *) handlers->getObject(idx)); 5311 idx++) 5312 { 5313 target->callPlatformFunction(sCPULatencyFunctionName[delayType], false, 5314 (void *) (uintptr_t) ns, holder, 5315 NULL, NULL); 5316 } 5317 } 5318 5319 IORecursiveLockUnlock(sCpuDelayLock); 5320} 5321 5322static IOReturn 5323setLatencyHandler(UInt32 delayType, IOService * target, bool enable) 5324{ 5325 IOReturn result = kIOReturnNotFound; 5326 OSArray * array; 5327 unsigned int idx; 5328 5329 IORecursiveLockLock(sCpuDelayLock); 5330 5331 do 5332 { 5333 if (enable && !sCpuLatencyHandlers[delayType]) 5334 sCpuLatencyHandlers[delayType] = OSArray::withCapacity(4); 5335 array = sCpuLatencyHandlers[delayType]; 5336 if (!array) 5337 break; 5338 idx = array->getNextIndexOfObject(target, 0); 5339 if (!enable) 5340 { 5341 if (-1U != idx) 5342 { 5343 array->removeObject(idx); 5344 result = kIOReturnSuccess; 5345 } 5346 } 5347 else 5348 { 5349 if (-1U != idx) { 5350 result = kIOReturnExclusiveAccess; 5351 break; 5352 } 5353 array->setObject(target); 5354 5355 UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry); 5356 CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy(); 5357 UInt32 ns = -1U; // Set to max unsigned, i.e. no restriction 5358 IOService * holder = NULL; 5359 5360 for (UInt i = 0; i < count; i++) { 5361 if (entries[i].fService 5362 && (delayType == entries[i].fDelayType) 5363 && (entries[i].fMaxDelay < ns)) { 5364 ns = entries[i].fMaxDelay; 5365 holder = entries[i].fService; 5366 } 5367 } 5368 target->callPlatformFunction(sCPULatencyFunctionName[delayType], false, 5369 (void *) (uintptr_t) ns, holder, 5370 NULL, NULL); 5371 result = kIOReturnSuccess; 5372 } 5373 } 5374 while (false); 5375 5376 IORecursiveLockUnlock(sCpuDelayLock); 5377 5378 return (result); 5379} 5380 5381#endif /* defined(__i386__) || defined(__x86_64__) */ 5382 5383void IOService:: 5384requireMaxBusStall(UInt32 __unused ns) 5385{ 5386#if defined(__i386__) || defined(__x86_64__) 5387 requireMaxCpuDelay(this, ns, kCpuDelayBusStall); 5388#endif 5389} 5390 5391void IOService:: 5392requireMaxInterruptDelay(uint32_t __unused ns) 5393{ 5394#if defined(__i386__) || defined(__x86_64__) 5395 requireMaxCpuDelay(this, ns, kCpuDelayInterrupt); 5396#endif 5397} 5398 5399/* 5400 * Device interrupts 5401 */ 5402 5403IOReturn IOService::resolveInterrupt(IOService *nub, int source) 5404{ 5405 IOInterruptController *interruptController; 5406 OSArray *array; 5407 OSData *data; 5408 OSSymbol *interruptControllerName; 5409 long numSources; 5410 IOInterruptSource *interruptSources; 5411 5412 // Get the parents list from the nub. 5413 array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptControllersKey)); 5414 if (array == 0) return kIOReturnNoResources; 5415 5416 // Allocate space for the IOInterruptSources if needed... then return early. 5417 if (nub->_interruptSources == 0) { 5418 numSources = array->getCount(); 5419 interruptSources = (IOInterruptSource *)IOMalloc(numSources * sizeof(IOInterruptSource)); 5420 if (interruptSources == 0) return kIOReturnNoMemory; 5421 5422 bzero(interruptSources, numSources * sizeof(IOInterruptSource)); 5423 5424 nub->_numInterruptSources = numSources; 5425 nub->_interruptSources = interruptSources; 5426 return kIOReturnSuccess; 5427 } 5428 5429 interruptControllerName = OSDynamicCast(OSSymbol,array->getObject(source)); 5430 if (interruptControllerName == 0) return kIOReturnNoResources; 5431 5432 interruptController = getPlatform()->lookUpInterruptController(interruptControllerName); 5433 if (interruptController == 0) return kIOReturnNoResources; 5434 5435 // Get the interrupt numbers from the nub. 5436 array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptSpecifiersKey)); 5437 if (array == 0) return kIOReturnNoResources; 5438 data = OSDynamicCast(OSData, array->getObject(source)); 5439 if (data == 0) return kIOReturnNoResources; 5440 5441 // Set the interruptController and interruptSource in the nub's table. 5442 interruptSources = nub->_interruptSources; 5443 interruptSources[source].interruptController = interruptController; 5444 interruptSources[source].vectorData = data; 5445 5446 return kIOReturnSuccess; 5447} 5448 5449IOReturn IOService::lookupInterrupt(int source, bool resolve, IOInterruptController **interruptController) 5450{ 5451 IOReturn ret; 5452 5453 /* Make sure the _interruptSources are set */ 5454 if (_interruptSources == 0) { 5455 ret = resolveInterrupt(this, source); 5456 if (ret != kIOReturnSuccess) return ret; 5457 } 5458 5459 /* Make sure the local source number is valid */ 5460 if ((source < 0) || (source >= _numInterruptSources)) 5461 return kIOReturnNoInterrupt; 5462 5463 /* Look up the contoller for the local source */ 5464 *interruptController = _interruptSources[source].interruptController; 5465 5466 if (*interruptController == NULL) { 5467 if (!resolve) return kIOReturnNoInterrupt; 5468 5469 /* Try to reslove the interrupt */ 5470 ret = resolveInterrupt(this, source); 5471 if (ret != kIOReturnSuccess) return ret; 5472 5473 *interruptController = _interruptSources[source].interruptController; 5474 } 5475 5476 return kIOReturnSuccess; 5477} 5478 5479IOReturn IOService::registerInterrupt(int source, OSObject *target, 5480 IOInterruptAction handler, 5481 void *refCon) 5482{ 5483 IOInterruptController *interruptController; 5484 IOReturn ret; 5485 5486 ret = lookupInterrupt(source, true, &interruptController); 5487 if (ret != kIOReturnSuccess) return ret; 5488 5489 /* Register the source */ 5490 return interruptController->registerInterrupt(this, source, target, 5491 (IOInterruptHandler)handler, 5492 refCon); 5493} 5494 5495IOReturn IOService::unregisterInterrupt(int source) 5496{ 5497 IOInterruptController *interruptController; 5498 IOReturn ret; 5499 5500 ret = lookupInterrupt(source, false, &interruptController); 5501 if (ret != kIOReturnSuccess) return ret; 5502 5503 /* Unregister the source */ 5504 return interruptController->unregisterInterrupt(this, source); 5505} 5506 5507IOReturn IOService::getInterruptType(int source, int *interruptType) 5508{ 5509 IOInterruptController *interruptController; 5510 IOReturn ret; 5511 5512 ret = lookupInterrupt(source, true, &interruptController); 5513 if (ret != kIOReturnSuccess) return ret; 5514 5515 /* Return the type */ 5516 return interruptController->getInterruptType(this, source, interruptType); 5517} 5518 5519IOReturn IOService::enableInterrupt(int source) 5520{ 5521 IOInterruptController *interruptController; 5522 IOReturn ret; 5523 5524 ret = lookupInterrupt(source, false, &interruptController); 5525 if (ret != kIOReturnSuccess) return ret; 5526 5527 /* Enable the source */ 5528 return interruptController->enableInterrupt(this, source); 5529} 5530 5531IOReturn IOService::disableInterrupt(int source) 5532{ 5533 IOInterruptController *interruptController; 5534 IOReturn ret; 5535 5536 ret = lookupInterrupt(source, false, &interruptController); 5537 if (ret != kIOReturnSuccess) return ret; 5538 5539 /* Disable the source */ 5540 return interruptController->disableInterrupt(this, source); 5541} 5542 5543IOReturn IOService::causeInterrupt(int source) 5544{ 5545 IOInterruptController *interruptController; 5546 IOReturn ret; 5547 5548 ret = lookupInterrupt(source, false, &interruptController); 5549 if (ret != kIOReturnSuccess) return ret; 5550 5551 /* Cause an interrupt for the source */ 5552 return interruptController->causeInterrupt(this, source); 5553} 5554 5555IOReturn IOService::configureReport(IOReportChannelList *channelList, 5556 IOReportConfigureAction action, 5557 void *result, 5558 void *destination) 5559{ 5560 unsigned cnt; 5561 5562 for (cnt = 0; cnt < channelList->nchannels; cnt++) { 5563 if ( channelList->channels[cnt].channel_id == kPMPowerStatesChID ) { 5564 if (pwrMgt) configurePowerStatesReport(action, result); 5565 else return kIOReturnUnsupported; 5566 } 5567 else if ( channelList->channels[cnt].channel_id == kPMCurrStateChID ) { 5568 if (pwrMgt) configureSimplePowerReport(action, result); 5569 else return kIOReturnUnsupported; 5570 } 5571 } 5572 5573 return kIOReturnSuccess; 5574} 5575 5576IOReturn IOService::updateReport(IOReportChannelList *channelList, 5577 IOReportUpdateAction action, 5578 void *result, 5579 void *destination) 5580{ 5581 unsigned cnt; 5582 5583 for (cnt = 0; cnt < channelList->nchannels; cnt++) { 5584 if ( channelList->channels[cnt].channel_id == kPMPowerStatesChID ) { 5585 if (pwrMgt) updatePowerStatesReport(action, result, destination); 5586 else return kIOReturnUnsupported; 5587 } 5588 else if ( channelList->channels[cnt].channel_id == kPMCurrStateChID ) { 5589 if (pwrMgt) updateSimplePowerReport(action, result, destination); 5590 else return kIOReturnUnsupported; 5591 } 5592 } 5593 5594 return kIOReturnSuccess; 5595} 5596 5597#if __LP64__ 5598OSMetaClassDefineReservedUsed(IOService, 0); 5599OSMetaClassDefineReservedUsed(IOService, 1); 5600OSMetaClassDefineReservedUnused(IOService, 2); 5601OSMetaClassDefineReservedUnused(IOService, 3); 5602OSMetaClassDefineReservedUnused(IOService, 4); 5603OSMetaClassDefineReservedUnused(IOService, 5); 5604OSMetaClassDefineReservedUnused(IOService, 6); 5605OSMetaClassDefineReservedUnused(IOService, 7); 5606#else 5607OSMetaClassDefineReservedUsed(IOService, 0); 5608OSMetaClassDefineReservedUsed(IOService, 1); 5609OSMetaClassDefineReservedUsed(IOService, 2); 5610OSMetaClassDefineReservedUsed(IOService, 3); 5611OSMetaClassDefineReservedUsed(IOService, 4); 5612OSMetaClassDefineReservedUsed(IOService, 5); 5613OSMetaClassDefineReservedUsed(IOService, 6); 5614OSMetaClassDefineReservedUsed(IOService, 7); 5615#endif 5616OSMetaClassDefineReservedUnused(IOService, 8); 5617OSMetaClassDefineReservedUnused(IOService, 9); 5618OSMetaClassDefineReservedUnused(IOService, 10); 5619OSMetaClassDefineReservedUnused(IOService, 11); 5620OSMetaClassDefineReservedUnused(IOService, 12); 5621OSMetaClassDefineReservedUnused(IOService, 13); 5622OSMetaClassDefineReservedUnused(IOService, 14); 5623OSMetaClassDefineReservedUnused(IOService, 15); 5624OSMetaClassDefineReservedUnused(IOService, 16); 5625OSMetaClassDefineReservedUnused(IOService, 17); 5626OSMetaClassDefineReservedUnused(IOService, 18); 5627OSMetaClassDefineReservedUnused(IOService, 19); 5628OSMetaClassDefineReservedUnused(IOService, 20); 5629OSMetaClassDefineReservedUnused(IOService, 21); 5630OSMetaClassDefineReservedUnused(IOService, 22); 5631OSMetaClassDefineReservedUnused(IOService, 23); 5632OSMetaClassDefineReservedUnused(IOService, 24); 5633OSMetaClassDefineReservedUnused(IOService, 25); 5634OSMetaClassDefineReservedUnused(IOService, 26); 5635OSMetaClassDefineReservedUnused(IOService, 27); 5636OSMetaClassDefineReservedUnused(IOService, 28); 5637OSMetaClassDefineReservedUnused(IOService, 29); 5638OSMetaClassDefineReservedUnused(IOService, 30); 5639OSMetaClassDefineReservedUnused(IOService, 31); 5640OSMetaClassDefineReservedUnused(IOService, 32); 5641OSMetaClassDefineReservedUnused(IOService, 33); 5642OSMetaClassDefineReservedUnused(IOService, 34); 5643OSMetaClassDefineReservedUnused(IOService, 35); 5644OSMetaClassDefineReservedUnused(IOService, 36); 5645OSMetaClassDefineReservedUnused(IOService, 37); 5646OSMetaClassDefineReservedUnused(IOService, 38); 5647OSMetaClassDefineReservedUnused(IOService, 39); 5648OSMetaClassDefineReservedUnused(IOService, 40); 5649OSMetaClassDefineReservedUnused(IOService, 41); 5650OSMetaClassDefineReservedUnused(IOService, 42); 5651OSMetaClassDefineReservedUnused(IOService, 43); 5652OSMetaClassDefineReservedUnused(IOService, 44); 5653OSMetaClassDefineReservedUnused(IOService, 45); 5654OSMetaClassDefineReservedUnused(IOService, 46); 5655OSMetaClassDefineReservedUnused(IOService, 47); 5656