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