1/* 2 * Copyright (c) 1998-2006 Apple Computer, 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#include <IOKit/IOWorkLoop.h> 29#include <IOKit/IOCommandGate.h> 30#include <IOKit/IOTimerEventSource.h> 31#include <IOKit/IOPlatformExpert.h> 32#include <IOKit/IOKitDebug.h> 33#include <IOKit/IOTimeStamp.h> 34#include <IOKit/pwr_mgt/RootDomain.h> 35#include <IOKit/pwr_mgt/IOPMPrivate.h> 36#include <IOKit/IODeviceTreeSupport.h> 37#include <IOKit/IOMessage.h> 38#include <IOKit/IOReturn.h> 39#include "RootDomainUserClient.h" 40#include "IOKit/pwr_mgt/IOPowerConnection.h" 41#include "IOPMPowerStateQueue.h" 42#include <IOKit/IOCatalogue.h> 43#if HIBERNATION 44#include <IOKit/IOHibernatePrivate.h> 45#endif 46#include <sys/syslog.h> 47#include <sys/sysctl.h> 48#include <sys/time.h> 49#include "IOServicePrivate.h" // _IOServiceInterestNotifier 50 51 52#if __i386__ 53__BEGIN_DECLS 54#include "IOPMrootDomainInternal.h" 55__END_DECLS 56#endif 57 58 59//#define DEBUG 1 60#if DEBUG 61#define DEBUG_LOG(x...) do { kprintf(x); } while (0) 62#else 63#define DEBUG_LOG(x...) 64#endif 65#define HaltRestartLog(x...) do { kprintf(x); } while (0) 66 67extern "C" { 68IOReturn OSMetaClassSystemSleepOrWake( UInt32 ); 69} 70 71extern const IORegistryPlane * gIOPowerPlane; 72 73IOReturn broadcast_aggressiveness ( OSObject *, void *, void *, void *, void * ); 74static void sleepTimerExpired(thread_call_param_t); 75static void wakeupClamshellTimerExpired ( thread_call_param_t us); 76static void notifySystemShutdown( IOService * root, unsigned long event ); 77 78// "IOPMSetSleepSupported" callPlatformFunction name 79static const OSSymbol *sleepSupportedPEFunction = NULL; 80 81#define kIOSleepSupportedKey "IOSleepSupported" 82 83#define kRD_AllPowerSources (kIOPMSupportedOnAC \ 84 | kIOPMSupportedOnBatt \ 85 | kIOPMSupportedOnUPS) 86 87#define number_of_power_states 5 88#define OFF_STATE 0 89#define RESTART_STATE 1 90#define SLEEP_STATE 2 91#define DOZE_STATE 3 92#define ON_STATE 4 93 94#define ON_POWER kIOPMPowerOn 95#define RESTART_POWER kIOPMRestart 96#define SLEEP_POWER kIOPMAuxPowerOn 97#define DOZE_POWER kIOPMDoze 98 99enum 100{ 101 // not idle around autowake time, secs 102 kAutoWakePreWindow = 45, 103 kAutoWakePostWindow = 15 104}; 105 106 107#define kLocalEvalClamshellCommand (1 << 15) 108 109static IOPMPowerState ourPowerStates[number_of_power_states] = { 110 // state 0, off 111 {1,0, 0, 0,0,0,0,0,0,0,0,0}, 112 // state 1, restart 113 {1,kIOPMRestartCapability, kIOPMRestart, RESTART_POWER,0,0,0,0,0,0,0,0}, 114 // state 2, sleep 115 {1,kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER,0,0,0,0,0,0,0,0}, 116 // state 3, doze 117 {1,kIOPMDoze, kIOPMDoze, DOZE_POWER,0,0,0,0,0,0,0,0}, 118 // state 4, on 119 {1,kIOPMPowerOn, kIOPMPowerOn, ON_POWER,0,0,0,0,0,0,0,0}, 120}; 121 122static IOPMrootDomain * gRootDomain; 123static UInt32 gSleepOrShutdownPending = 0; 124 125struct timeval gIOLastSleepTime; 126struct timeval gIOLastWakeTime; 127 128// Constants used as arguments to IOPMrootDomain::informCPUStateChange 129#define kCPUUnknownIndex 9999999 130enum { 131 kInformAC = 0, 132 kInformLid = 1, 133 kInformableCount = 2 134}; 135 136class PMSettingObject : public OSObject 137{ 138 OSDeclareDefaultStructors(PMSettingObject) 139private: 140 IOPMrootDomain *parent; 141 IOPMSettingControllerCallback func; 142 OSObject *target; 143 uintptr_t refcon; 144 uint32_t *publishedFeatureID; 145 int releaseAtCount; 146public: 147 static PMSettingObject *pmSettingObject( 148 IOPMrootDomain *parent_arg, 149 IOPMSettingControllerCallback handler_arg, 150 OSObject *target_arg, 151 uintptr_t refcon_arg, 152 uint32_t supportedPowerSources, 153 const OSSymbol *settings[]); 154 155 void setPMSetting(const OSSymbol *type, OSObject *obj); 156 157 void taggedRelease(const void *tag, const int when) const; 158 void free(void); 159}; 160 161/* 162 * Internal helper object for Shutdown/Restart notifications. 163 */ 164#define kPMHaltMaxWorkers 8 165#define kPMHaltTimeoutMS 100 166 167class PMHaltWorker : public OSObject 168{ 169 OSDeclareDefaultStructors( PMHaltWorker ) 170 171public: 172 IOService * service; // service being worked on 173 AbsoluteTime startTime; // time when work started 174 int depth; // work on nubs at this PM-tree depth 175 int visits; // number of nodes visited (debug) 176 IOLock * lock; 177 bool timeout; // service took too long 178 179 static PMHaltWorker * worker( void ); 180 static void main( void * arg ); 181 static void work( PMHaltWorker * me ); 182 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now ); 183 virtual void free( void ); 184}; 185 186OSDefineMetaClassAndStructors( PMHaltWorker, OSObject ) 187 188 189#define super IOService 190OSDefineMetaClassAndStructors(IOPMrootDomain,IOService) 191 192extern "C" 193{ 194 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref) 195 { 196 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref ); 197 } 198 199 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref) 200 { 201 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref ); 202 } 203 204 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon) 205 { 206 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon ); 207 } 208 209 IOReturn vetoSleepWakeNotification(void * PMrefcon) 210 { 211 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon ); 212 } 213 214 IOReturn rootDomainRestart ( void ) 215 { 216 return gRootDomain->restartSystem(); 217 } 218 219 IOReturn rootDomainShutdown ( void ) 220 { 221 return gRootDomain->shutdownSystem(); 222 } 223 224 void IOSystemShutdownNotification ( void ) 225 { 226 IOCatalogue::disableExternalLinker(); 227 for ( int i = 0; i < 100; i++ ) 228 { 229 if ( OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) ) break; 230 IOSleep( 100 ); 231 } 232 } 233 234 int sync_internal(void); 235} 236 237/* 238A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain 239children it has, but within the constraint of the power state provided by its parent. The driver expresses its desire by 240calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children 241express their desires by calling requestPowerDomainState(). 242 243The Root Power Domain owns the policy for idle and demand sleep and doze for the system. It is a power-managed IOService just 244like the others in the system. It implements several power states which correspond to what we see as Sleep, Doze, etc. 245 246The sleep/doze policy is as follows: 247Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards. 248Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero. 249The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep. 250 251These three conditions are enforced using the "driver clamp" by calling changePowerStateTo(). For example, if the case is 252opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or 253the state of the other clamp. 254 255Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item. 256In this case the root's parent actually initiates the power state change so that the root has no choice and does not give 257applications the opportunity to veto the change. 258 259Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep. When this is true, the root's 260children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE) 261to hold itself on until the sleep timer expires. This timer is set for the difference between the sleep timeout slider and 262the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel. For example, if 263the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes, 264when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root 265sets its timer for 25 minutes (30 - 5). When the timer expires, it releases its clamp and now nothing is holding it awake, 266so it falls asleep. 267 268Demand sleep is prevented when the system is booting. When preferences are transmitted by the loginwindow at the end of 269boot, a flag is cleared, and this allows subsequent Demand Sleep. 270 271The system will not Sleep, but will Doze if some object calls setSleepSupported(kPCICantSleep) during a power change to the sleep state (this can be done by the PCI Aux Power Supply drivers, Slots99, MacRISC299, etc.). This is not enforced with 272a clamp, but sets a flag which is noticed before actually sleeping the kernel. If the flag is set, the root steps up 273one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and 274ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler 275to be tickled)). 276*/ 277 278// ********************************************************************************** 279 280IOPMrootDomain * IOPMrootDomain::construct( void ) 281{ 282 IOPMrootDomain *root; 283 284 root = new IOPMrootDomain; 285 if( root) 286 root->init(); 287 288 return( root ); 289} 290 291// ********************************************************************************** 292 293static void disk_sync_callout(thread_call_param_t p0, thread_call_param_t p1) 294{ 295 IOService *rootDomain = (IOService *) p0; 296 unsigned long pmRef = (unsigned long) p1; 297 298 DEBUG_LOG("disk_sync_callout: start\n"); 299 300#if HIBERNATION 301 IOHibernateSystemSleep(); 302#endif 303 sync_internal(); 304 rootDomain->allowPowerChange(pmRef); 305 DEBUG_LOG("disk_sync_callout: finish\n"); 306} 307 308// ********************************************************************************** 309 310static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime ) 311{ 312 AbsoluteTime endTime; 313 UInt64 nano = 0; 314 315 clock_get_uptime(&endTime); 316 if (CMP_ABSOLUTETIME(&endTime, startTime) > 0) 317 { 318 SUB_ABSOLUTETIME(&endTime, startTime); 319 absolutetime_to_nanoseconds(endTime, &nano); 320 } 321 322 return (UInt32)(nano / 1000000ULL); 323} 324 325// ********************************************************************************** 326// start 327// 328// We don't do much here. The real initialization occurs when the platform 329// expert informs us we are the root. 330// ********************************************************************************** 331 332#define kRootDomainSettingsCount 16 333 334static SYSCTL_STRUCT(_kern, OID_AUTO, sleeptime, 335 CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN, 336 &gIOLastSleepTime, timeval, ""); 337 338static SYSCTL_STRUCT(_kern, OID_AUTO, waketime, 339 CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN, 340 &gIOLastWakeTime, timeval, ""); 341 342static const OSSymbol * gIOPMSettingAutoWakeSecondsKey; 343 344bool IOPMrootDomain::start ( IOService * nub ) 345{ 346 OSIterator *psIterator; 347 OSDictionary *tmpDict; 348 349 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey); 350 351 const OSSymbol *settingsArr[kRootDomainSettingsCount] = 352 { 353 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey), 354 gIOPMSettingAutoWakeSecondsKey, 355 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey), 356 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey), 357 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey), 358 OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey), 359 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey), 360 OSSymbol::withCString(kIOPMSettingWakeOnRingKey), 361 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey), 362 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey), 363 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey), 364 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey), 365 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey), 366 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey), 367 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey), 368 OSSymbol::withCString(kIOPMStateConsoleShutdown) 369 }; 370 371 372 pmPowerStateQueue = 0; 373 374 _reserved = (ExpansionData *)IOMalloc(sizeof(ExpansionData)); 375 if(!_reserved) return false; 376 377 super::start(nub); 378 379 gRootDomain = this; 380 381 PMinit(); 382 383 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported"); 384 canSleep = true; 385 setProperty(kIOSleepSupportedKey,true); 386 387 userDisabledAllSleep = false; 388 allowSleep = true; 389 sleepIsSupported = true; 390 systemBooting = true; 391 sleepSlider = 0; 392 idleSleepPending = false; 393 wrangler = NULL; 394 sleepASAP = false; 395 clamshellIsClosed = false; 396 clamshellExists = false; 397 ignoringClamshell = true; 398 ignoringClamshellDuringWakeup = false; 399 acAdaptorConnect = true; 400 401 idxPMCPUClamshell = kCPUUnknownIndex; 402 idxPMCPULimitedPower = kCPUUnknownIndex; 403 404 tmpDict = OSDictionary::withCapacity(1); 405 setProperty(kRootDomainSupportedFeatures, tmpDict); 406 tmpDict->release(); 407 408 settingsCallbacks = OSDictionary::withCapacity(1); 409 410 // Create a list of the valid PM settings that we'll relay to 411 // interested clients in setProperties() => setPMSetting() 412 allowedPMSettings = OSArray::withObjects( 413 (const OSObject **)settingsArr, 414 kRootDomainSettingsCount, 415 0); 416 417 fPMSettingsDict = OSDictionary::withCapacity(5); 418 419 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(this); 420 getPMworkloop()->addEventSource(pmPowerStateQueue); 421 422 featuresDictLock = IOLockAlloc(); 423 settingsCtrlLock = IORecursiveLockAlloc(); 424 425 extraSleepTimer = thread_call_allocate( 426 (thread_call_func_t)sleepTimerExpired, 427 (thread_call_param_t) this); 428 clamshellWakeupIgnore = thread_call_allocate( 429 (thread_call_func_t)wakeupClamshellTimerExpired, 430 (thread_call_param_t) this); 431 diskSyncCalloutEntry = thread_call_allocate( 432 &disk_sync_callout, 433 (thread_call_param_t) this); 434 435 // create our parent 436 patriarch = new IORootParent; 437 patriarch->init(); 438 patriarch->attach(this); 439 patriarch->start(this); 440 patriarch->addPowerChild(this); 441 442 registerPowerDriver(this,ourPowerStates,number_of_power_states); 443 444 setPMRootDomain(this); 445 // set a clamp until we sleep 446 changePowerStateToPriv(ON_STATE); 447 448 // install power change handler 449 registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0); 450 451#if !NO_KERNEL_HID 452 // Register for a notification when IODisplayWrangler is published 453 _displayWranglerNotifier = addNotification( 454 gIOPublishNotification, serviceMatching("IODisplayWrangler"), 455 &displayWranglerPublished, this, 0); 456#endif 457 458 // Battery location published - ApplePMU support only 459 _batteryPublishNotifier = addNotification( 460 gIOPublishNotification, serviceMatching("IOPMPowerSource"), 461 &batteryPublished, this, this); 462 463 464 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient"); 465 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName); 466 ucClassName->release(); 467 468 // IOBacklightDisplay can take a long time to load at boot, or it may 469 // not load at all if you're booting with clamshell closed. We publish 470 // 'DisplayDims' here redundantly to get it published early and at all. 471 psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") ); 472 if( psIterator && psIterator->getNextObject() ) 473 { 474 // There's at least one battery on the system, so we publish 475 // 'DisplayDims' support for the LCD. 476 publishFeature("DisplayDims"); 477 } 478 if(psIterator) { 479 psIterator->release(); 480 } 481 482 483 sysctl_register_oid(&sysctl__kern_sleeptime); 484 sysctl_register_oid(&sysctl__kern_waketime); 485 486#if HIBERNATION 487 IOHibernateSystemInit(this); 488#endif 489 490 registerService(); // let clients find us 491 492 return true; 493} 494 495// ********************************************************************************** 496// setProperties 497// 498// Receive a setProperty call 499// The "System Boot" property means the system is completely booted. 500// ********************************************************************************** 501IOReturn IOPMrootDomain::setProperties ( OSObject *props_obj) 502{ 503 IOReturn return_value = kIOReturnSuccess; 504 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj); 505 OSBoolean *b; 506 OSNumber *n; 507 OSString *str; 508 OSSymbol *type; 509 OSObject *obj; 510 unsigned int i; 511 512 const OSSymbol *boot_complete_string = 513 OSSymbol::withCString("System Boot Complete"); 514 const OSSymbol *sys_shutdown_string = 515 OSSymbol::withCString("System Shutdown"); 516 const OSSymbol *stall_halt_string = 517 OSSymbol::withCString("StallSystemAtHalt"); 518 const OSSymbol *battery_warning_disabled_string = 519 OSSymbol::withCString("BatteryWarningsDisabled"); 520 const OSSymbol *idle_seconds_string = 521 OSSymbol::withCString("System Idle Seconds"); 522#if HIBERNATION 523 const OSSymbol *hibernatemode_string = 524 OSSymbol::withCString(kIOHibernateModeKey); 525 const OSSymbol *hibernatefile_string = 526 OSSymbol::withCString(kIOHibernateFileKey); 527 const OSSymbol *hibernatefreeratio_string = 528 OSSymbol::withCString(kIOHibernateFreeRatioKey); 529 const OSSymbol *hibernatefreetime_string = 530 OSSymbol::withCString(kIOHibernateFreeTimeKey); 531#endif 532 const OSSymbol *sleepdisabled_string = 533 OSSymbol::withCString("SleepDisabled"); 534 535 if(!dict) 536 { 537 return_value = kIOReturnBadArgument; 538 goto exit; 539 } 540 541 if ((n = OSDynamicCast(OSNumber, dict->getObject(idle_seconds_string)))) 542 { 543 setProperty(idle_seconds_string, n); 544 idleSeconds = n->unsigned32BitValue(); 545 } 546 547 if( systemBooting 548 && boot_complete_string 549 && dict->getObject(boot_complete_string)) 550 { 551 systemBooting = false; 552 adjustPowerState(); 553 554 // If lid is closed, re-send lid closed notification 555 // now that booting is complete. 556 if( clamshellIsClosed ) 557 { 558 this->receivePowerNotification(kLocalEvalClamshellCommand); 559 } 560 } 561 562 if( battery_warning_disabled_string 563 && dict->getObject(battery_warning_disabled_string)) 564 { 565 setProperty( battery_warning_disabled_string, 566 dict->getObject(battery_warning_disabled_string)); 567 } 568 569 if( sys_shutdown_string 570 && (b = OSDynamicCast(OSBoolean, dict->getObject(sys_shutdown_string)))) 571 { 572 573 if(kOSBooleanTrue == b) 574 { 575 /* We set systemShutdown = true during shutdown 576 to prevent sleep at unexpected times while loginwindow is trying 577 to shutdown apps and while the OS is trying to transition to 578 complete power of. 579 580 Set to true during shutdown, as soon as loginwindow shows 581 the "shutdown countdown dialog", through individual app 582 termination, and through black screen kernel shutdown. 583 */ 584 kprintf("systemShutdown true\n"); 585 systemShutdown = true; 586 } else { 587 /* 588 A shutdown was initiated, but then the shutdown 589 was cancelled, clearing systemShutdown to false here. 590 */ 591 kprintf("systemShutdown false\n"); 592 systemShutdown = false; 593 } 594 } 595 596 if( stall_halt_string 597 && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) ) 598 { 599 setProperty(stall_halt_string, b); 600 } 601 602#if HIBERNATION 603 if ( hibernatemode_string 604 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string)))) 605 { 606 setProperty(hibernatemode_string, n); 607 } 608 if ( hibernatefreeratio_string 609 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string)))) 610 { 611 setProperty(hibernatefreeratio_string, n); 612 } 613 if ( hibernatefreetime_string 614 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string)))) 615 { 616 setProperty(hibernatefreetime_string, n); 617 } 618 if ( hibernatefile_string 619 && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string)))) 620 { 621 setProperty(hibernatefile_string, str); 622 } 623#endif 624 625 if( sleepdisabled_string 626 && (b = OSDynamicCast(OSBoolean, dict->getObject(sleepdisabled_string))) ) 627 { 628 setProperty(sleepdisabled_string, b); 629 630 userDisabledAllSleep = (kOSBooleanTrue == b); 631 } 632 633 // Relay our allowed PM settings onto our registered PM clients 634 for(i = 0; i < allowedPMSettings->getCount(); i++) { 635 636 type = (OSSymbol *)allowedPMSettings->getObject(i); 637 if(!type) continue; 638 639 obj = dict->getObject(type); 640 if(!obj) continue; 641 642 if ((gIOPMSettingAutoWakeSecondsKey == type) && ((n = OSDynamicCast(OSNumber, obj)))) 643 { 644 UInt32 rsecs = n->unsigned32BitValue(); 645 if (!rsecs) 646 autoWakeStart = autoWakeEnd = 0; 647 else 648 { 649 AbsoluteTime deadline; 650 clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline); 651 autoWakeEnd = AbsoluteTime_to_scalar(&deadline); 652 if (rsecs > kAutoWakePreWindow) 653 rsecs -= kAutoWakePreWindow; 654 else 655 rsecs = 0; 656 clock_interval_to_deadline(rsecs, kSecondScale, &deadline); 657 autoWakeStart = AbsoluteTime_to_scalar(&deadline); 658 } 659 } 660 661 return_value = setPMSetting(type, obj); 662 663 if(kIOReturnSuccess != return_value) goto exit; 664 } 665 666exit: 667 if(sleepdisabled_string) sleepdisabled_string->release(); 668 if(boot_complete_string) boot_complete_string->release(); 669 if(stall_halt_string) stall_halt_string->release(); 670 if(idle_seconds_string) idle_seconds_string->release(); 671 return return_value; 672} 673 674 675//********************************************************************************* 676// youAreRoot 677// 678// Power Managment is informing us that we are the root power domain. 679// We know we are not the root however, since we have just instantiated a parent 680// for ourselves and made it the root. We override this method so it will have 681// no effect 682//********************************************************************************* 683IOReturn IOPMrootDomain::youAreRoot ( void ) 684{ 685 return IOPMNoErr; 686} 687 688// ********************************************************************************** 689// command_received 690// 691// No longer used 692// ********************************************************************************** 693void IOPMrootDomain::command_received ( void * w, void * x, void * y, void * z ) 694{ 695 super::command_received(w,x,y,z); 696} 697 698 699// ********************************************************************************** 700// broadcast_aggressiveness 701// 702// ********************************************************************************** 703IOReturn broadcast_aggressiveness ( OSObject * root, void * x, void * y, void *, void * ) 704{ 705 ((IOPMrootDomain *)root)->broadcast_it((unsigned long)x,(unsigned long)y); 706 return IOPMNoErr; 707} 708 709 710// ********************************************************************************** 711// broadcast_it 712// 713// We are behind the command gate to broadcast an aggressiveness factor. We let the 714// superclass do it, but we need to snoop on factors that affect idle sleep. 715// ********************************************************************************** 716void IOPMrootDomain::broadcast_it (unsigned long type, unsigned long value) 717{ 718 super::setAggressiveness(type,value); 719 720 // Save user's spin down timer to restore after we replace it for idle sleep 721 if( type == kPMMinutesToSpinDown ) user_spindown = value; 722 723 // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer 724 if (getAggressiveness(kPMMinutesToDim, (unsigned long *)&longestNonSleepSlider) 725 != kIOReturnSuccess) 726 longestNonSleepSlider = 0; 727 728 if ( type == kPMMinutesToSleep ) { 729 DEBUG_LOG("PM idle time -> %ld secs (ena %d)\n", idleSeconds, (value != 0)); 730 if (0x7fffffff == value) 731 value = idleSeconds; 732 733 if ( (sleepSlider == 0) && (value != 0) ) { 734 if (!wrangler) 735 { 736 sleepASAP = false; 737 changePowerStateToPriv(ON_STATE); 738 if (idleSeconds) 739 { 740 AbsoluteTime deadline; 741 // stay awake for at least idleSeconds 742 clock_interval_to_deadline(idleSeconds, kSecondScale, &deadline); 743 thread_call_enter_delayed(extraSleepTimer, deadline); 744 // this gets turned off when we sleep again 745 idleSleepPending = true; 746 } 747 } 748 else 749 { 750 // If sleepASAP is already set, then calling adjustPowerState() here 751 // will put the system to sleep immediately which is bad. Note that 752 // this aggressiveness change can occur without waking up the display 753 // by (dis)connecting the AC adapter. To get around this, the power 754 // clamp is restore to ON state then dropped after waiting for the 755 // sleep timer to expire. 756 757 if (sleepASAP) 758 { 759 AbsoluteTime deadline; 760 // stay awake for at least sleepSlider minutes 761 clock_interval_to_deadline(value * 60, kSecondScale, &deadline); 762 thread_call_enter_delayed(extraSleepTimer, deadline); 763 // this gets turned off when we sleep again 764 idleSleepPending = true; 765 sleepASAP = false; 766 } 767 } 768 } 769 sleepSlider = value; 770 if ( sleepSlider == 0 ) { 771 // idle sleep is now disabled 772 adjustPowerState(); 773 // make sure we're powered 774 patriarch->wakeSystem(); 775 } 776 } 777 if ( sleepSlider > longestNonSleepSlider ) { 778 extraSleepDelay = sleepSlider - longestNonSleepSlider ; 779 } 780 else { 781 extraSleepDelay = 0; 782 } 783} 784 785 786// ********************************************************************************** 787// sleepTimerExpired 788// 789// ********************************************************************************** 790static void sleepTimerExpired ( thread_call_param_t us) 791{ 792 ((IOPMrootDomain *)us)->handleSleepTimerExpiration(); 793 } 794 795 796static void wakeupClamshellTimerExpired ( thread_call_param_t us) 797{ 798 ((IOPMrootDomain *)us)->stopIgnoringClamshellEventsDuringWakeup(); 799} 800 801 802// ********************************************************************************** 803// handleSleepTimerExpiration 804// 805// The time between the sleep idle timeout and the next longest one has elapsed. 806// It's time to sleep. Start that by removing the clamp that's holding us awake. 807// ********************************************************************************** 808void IOPMrootDomain::handleSleepTimerExpiration ( void ) 809{ 810 DEBUG_LOG("SleepTimerExpired\n"); 811 812 AbsoluteTime time; 813 814 clock_get_uptime(&time); 815 if ((AbsoluteTime_to_scalar(&time) > autoWakeStart) && (AbsoluteTime_to_scalar(&time) < autoWakeEnd)) 816 { 817 thread_call_enter_delayed(extraSleepTimer, *((AbsoluteTime *) &autoWakeEnd)); 818 return; 819 } 820 821 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down) 822 if(0 != user_spindown) 823 setQuickSpinDownTimeout(); 824 825 sleepASAP = true; 826 adjustPowerState(); 827} 828 829 830void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void) 831{ 832 // Allow clamshell-induced sleep now 833 ignoringClamshellDuringWakeup = false; 834 835 // Re-send clamshell event, in case it causes a sleep 836 if(clamshellIsClosed) 837 this->receivePowerNotification( kLocalEvalClamshellCommand ); 838} 839 840//********************************************************************************* 841// setAggressiveness 842// 843// Some aggressiveness factor has changed. We broadcast it to the hierarchy while on 844// the Power Mangement workloop thread. This enables objects in the 845// hierarchy to successfully alter their idle timers, which are all on the 846// same thread. 847//********************************************************************************* 848 849IOReturn IOPMrootDomain::setAggressiveness ( unsigned long type, unsigned long newLevel ) 850{ 851 IOWorkLoop * pmWorkLoop = getPMworkloop(); 852 if (pmWorkLoop) 853 pmWorkLoop->runAction(broadcast_aggressiveness,this,(void *)type,(void *)newLevel); 854 855 return kIOReturnSuccess; 856} 857 858 859// ********************************************************************************** 860// sleepSystem 861// 862// ********************************************************************************** 863/* public */ 864IOReturn IOPMrootDomain::sleepSystem ( void ) 865{ 866 return sleepSystemOptions (NULL); 867} 868 869/* private */ 870IOReturn IOPMrootDomain::sleepSystemOptions ( OSDictionary *options ) 871{ 872 /* sleepSystem is a public function, and may be called by any kernel driver. 873 * And that's bad - drivers should sleep the system by calling 874 * receivePowerNotification() instead. Drivers should not use sleepSystem. 875 * 876 * Note that user space app calls to IOPMSleepSystem() will also travel 877 * this code path and thus be correctly identified as software sleeps. 878 */ 879 880 if (options && options->getObject("OSSwitch")) 881 { 882 883 // Log specific sleep cause for OS Switch hibernation 884 return privateSleepSystem( kIOPMOSSwitchHibernationKey) ; 885 886 } else { 887 888 return privateSleepSystem( kIOPMSoftwareSleepKey); 889 890 } 891} 892 893/* private */ 894IOReturn IOPMrootDomain::privateSleepSystem ( const char *sleepReason ) 895{ 896 // Record sleep cause in IORegistry 897 if (sleepReason) { 898 setProperty(kRootDomainSleepReasonKey, sleepReason); 899 } 900 901 if(systemShutdown) { 902 kprintf("Preventing system sleep on grounds of systemShutdown.\n"); 903 } 904 905 if( userDisabledAllSleep ) 906 { 907 /* Prevent sleep of all kinds if directed to by user space */ 908 return kIOReturnNotPermitted; 909 } 910 911 if ( !systemBooting 912 && !systemShutdown 913 && allowSleep) 914 { 915 if ( !sleepIsSupported ) { 916 setSleepSupported( kPCICantSleep ); 917 kprintf("Sleep prevented by kIOPMPreventSystemSleep flag\n"); 918 } 919 patriarch->sleepSystem(); 920 return kIOReturnSuccess; 921 } else { 922 // Unable to sleep because system is in the process of booting or shutting down, 923 // or sleep has otherwise been disallowed. 924 return kIOReturnError; 925 } 926} 927 928 929// ********************************************************************************** 930// shutdownSystem 931// 932// ********************************************************************************** 933IOReturn IOPMrootDomain::shutdownSystem ( void ) 934{ 935 //patriarch->shutDownSystem(); 936 return kIOReturnUnsupported; 937} 938 939 940// ********************************************************************************** 941// restartSystem 942// 943// ********************************************************************************** 944IOReturn IOPMrootDomain::restartSystem ( void ) 945{ 946 //patriarch->restartSystem(); 947 return kIOReturnUnsupported; 948} 949 950 951// ********************************************************************************** 952// powerChangeDone 953// 954// This overrides powerChangeDone in IOService. 955// 956// Finder sleep and idle sleep move us from the ON state to the SLEEP_STATE. 957// In this case: 958// If we just finished going to the SLEEP_STATE, and the platform is capable of true sleep, 959// sleep the kernel. Otherwise switch up to the DOZE_STATE which will keep almost 960// everything as off as it can get. 961// 962// ********************************************************************************** 963void IOPMrootDomain::powerChangeDone ( unsigned long previousState ) 964{ 965 OSNumber * propertyPtr; 966 unsigned short theProperty; 967 AbsoluteTime deadline; 968 969 DEBUG_LOG("PowerChangeDone: %ld -> %ld\n", previousState, getPowerState()); 970 971 switch ( getPowerState() ) { 972 case SLEEP_STATE: 973 if ( previousState != ON_STATE ) 974 break; 975 976 if ( canSleep && sleepIsSupported ) 977 { 978 // re-enable this timer for next sleep 979 idleSleepPending = false; 980 981 uint32_t secs, microsecs; 982 clock_get_calendar_microtime(&secs, µsecs); 983 logtime(secs); 984 gIOLastSleepTime.tv_sec = secs; 985 gIOLastSleepTime.tv_usec = microsecs; 986 987#if HIBERNATION 988 IOLog("System %sSleep\n", gIOHibernateState ? "Safe" : ""); 989 990 IOHibernateSystemHasSlept(); 991#else 992 IOLog("System Sleep\n"); 993#endif 994 995 getPlatform()->sleepKernel(); 996 997 // The CPU(s) are off at this point. When they're awakened by CPU interrupt, 998 // code will resume execution here. 999 1000 // Now we're waking... 1001#if HIBERNATION 1002 IOHibernateSystemWake(); 1003#endif 1004 1005 // stay awake for at least 30 seconds 1006 clock_interval_to_deadline(30, kSecondScale, &deadline); 1007 thread_call_enter_delayed(extraSleepTimer, deadline); 1008 // this gets turned off when we sleep again 1009 idleSleepPending = true; 1010 1011 // Ignore closed clamshell during wakeup and for a few seconds 1012 // after wakeup is complete 1013 ignoringClamshellDuringWakeup = true; 1014 1015 // sleep transition complete 1016 gSleepOrShutdownPending = 0; 1017 1018 // trip the reset of the calendar clock 1019 clock_wakeup_calendar(); 1020 1021 // get us some power 1022 patriarch->wakeSystem(); 1023 1024 // early stage wake notification 1025 tellClients(kIOMessageSystemWillPowerOn); 1026 1027 // tell the tree we're waking 1028#if HIBERNATION 1029 IOLog("System %sWake\n", gIOHibernateState ? "SafeSleep " : ""); 1030#endif 1031 systemWake(); 1032 1033 // Allow drivers to request extra processing time before clamshell 1034 // sleep if kIOREMSleepEnabledKey is present. 1035 // Ignore clamshell events for at least 5 seconds 1036 if(getProperty(kIOREMSleepEnabledKey)) { 1037 // clamshellWakeupIgnore callout clears ignoreClamshellDuringWakeup bit 1038 clock_interval_to_deadline(5, kSecondScale, &deadline); 1039 if(clamshellWakeupIgnore) { 1040 thread_call_enter_delayed(clamshellWakeupIgnore, deadline); 1041 } 1042 } else ignoringClamshellDuringWakeup = false; 1043 1044 // Find out what woke us 1045 propertyPtr = OSDynamicCast(OSNumber,getProperty("WakeEvent")); 1046 if ( propertyPtr ) { 1047 theProperty = propertyPtr->unsigned16BitValue(); 1048 IOLog("Wake event %04x\n",theProperty); 1049 if ( (theProperty & 0x0008) || //lid 1050 (theProperty & 0x0800) || // front panel button 1051 (theProperty & 0x0020) || // external keyboard 1052 (theProperty & 0x0001) ) { // internal keyboard 1053 // We've identified the wakeup event as UI driven 1054 reportUserInput(); 1055 } 1056 } else { 1057 // Since we can't identify the wakeup event, treat it as UI activity 1058 reportUserInput(); 1059 } 1060 1061 // Wake for thirty seconds 1062 changePowerStateToPriv(ON_STATE); 1063 } else { 1064 // allow us to step up a power state 1065 patriarch->sleepToDoze(); 1066 1067 // ignore children's request for higher power during doze. 1068 powerOverrideOnPriv(); 1069 changePowerStateToPriv(DOZE_STATE); 1070 } 1071 break; 1072 1073 case DOZE_STATE: 1074 if ( previousState != DOZE_STATE ) 1075 { 1076 IOLog("System Doze\n"); 1077 } 1078 // re-enable this timer for next sleep 1079 idleSleepPending = false; 1080 gSleepOrShutdownPending = 0; 1081 1082 // Invalidate prior activity tickles to allow wake from doze. 1083 if (wrangler) wrangler->changePowerStateTo(0); 1084 break; 1085 1086 case RESTART_STATE: 1087 IOLog("System Restart\n"); 1088 PEHaltRestart(kPERestartCPU); 1089 break; 1090 1091 case OFF_STATE: 1092 IOLog("System Halt\n"); 1093 PEHaltRestart(kPEHaltCPU); 1094 break; 1095 } 1096} 1097 1098 1099// ********************************************************************************** 1100// wakeFromDoze 1101// 1102// The Display Wrangler calls here when it switches to its highest state. If the 1103// system is currently dozing, allow it to wake by making sure the parent is 1104// providing power. 1105// ********************************************************************************** 1106void IOPMrootDomain::wakeFromDoze( void ) 1107{ 1108 if ( getPowerState() == DOZE_STATE ) 1109 { 1110 // Reset sleep support till next sleep attempt. 1111 // A machine's support of sleep vs. doze can change over the course of 1112 // a running system, so we recalculate it before every sleep. 1113 setSleepSupported(0); 1114 1115 changePowerStateToPriv(ON_STATE); 1116 powerOverrideOffPriv(); 1117 1118 // early wake notification 1119 tellClients(kIOMessageSystemWillPowerOn); 1120 1121 // allow us to wake if children so desire 1122 patriarch->wakeSystem(); 1123 } 1124} 1125 1126 1127// ***************************************************************************** 1128// publishFeature 1129// 1130// Adds a new feature to the supported features dictionary 1131// 1132// 1133// ***************************************************************************** 1134void IOPMrootDomain::publishFeature( const char * feature ) 1135{ 1136 publishFeature(feature, kIOPMSupportedOnAC 1137 | kIOPMSupportedOnBatt 1138 | kIOPMSupportedOnUPS, 1139 NULL); 1140 return; 1141} 1142 1143 1144// ***************************************************************************** 1145// publishFeature (with supported power source specified) 1146// 1147// Adds a new feature to the supported features dictionary 1148// 1149// 1150// ***************************************************************************** 1151void IOPMrootDomain::publishFeature( 1152 const char *feature, 1153 uint32_t supportedWhere, 1154 uint32_t *uniqueFeatureID) 1155{ 1156 static uint16_t next_feature_id = 500; 1157 1158 OSNumber *new_feature_data = NULL; 1159 OSNumber *existing_feature = NULL; 1160 OSArray *existing_feature_arr = NULL; 1161 OSObject *osObj = NULL; 1162 uint32_t feature_value = 0; 1163 1164 supportedWhere &= kRD_AllPowerSources; // mask off any craziness! 1165 1166// kprintf("IOPMrootDomain::publishFeature [\"%s\":%0x01x]\n", feature, supportedWhere); 1167 1168 if(!supportedWhere) { 1169 // Feature isn't supported anywhere! 1170 return; 1171 } 1172 1173 if(next_feature_id > 5000) { 1174 // Far, far too many features! 1175 return; 1176 } 1177 1178 if(featuresDictLock) IOLockLock(featuresDictLock); 1179 1180 OSDictionary *features = 1181 (OSDictionary *) getProperty(kRootDomainSupportedFeatures); 1182 1183 // Create new features dict if necessary 1184 if ( features && OSDynamicCast(OSDictionary, features)) { 1185 features = OSDictionary::withDictionary(features); 1186 } else { 1187 features = OSDictionary::withCapacity(1); 1188 } 1189 1190 // Create OSNumber to track new feature 1191 1192 next_feature_id += 1; 1193 if( uniqueFeatureID ) { 1194 // We don't really mind if the calling kext didn't give us a place 1195 // to stash their unique id. Many kexts don't plan to unload, and thus 1196 // have no need to remove themselves later. 1197 *uniqueFeatureID = next_feature_id; 1198 } 1199 1200 feature_value = supportedWhere + (next_feature_id << 16); 1201 new_feature_data = OSNumber::withNumber( 1202 (unsigned long long)feature_value, 32); 1203 1204 // Does features object already exist? 1205 if( (osObj = features->getObject(feature)) ) 1206 { 1207 if(( existing_feature = OSDynamicCast(OSNumber, osObj) )) 1208 { 1209 // We need to create an OSArray to hold the now 2 elements. 1210 existing_feature_arr = OSArray::withObjects( 1211 (const OSObject **)&existing_feature, 1, 2); 1212 existing_feature_arr->setObject(new_feature_data); 1213 features->setObject(feature, existing_feature_arr); 1214 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) )) 1215 { 1216 // Add object to existing array 1217 existing_feature_arr->setObject(new_feature_data); 1218 } 1219 } else { 1220 // The easy case: no previously existing features listed. We simply 1221 // set the OSNumber at key 'feature' and we're on our way. 1222 features->setObject(feature, new_feature_data); 1223 } 1224 1225 new_feature_data->release(); 1226 1227 setProperty(kRootDomainSupportedFeatures, features); 1228 1229 features->release(); 1230 1231 if(featuresDictLock) IOLockUnlock(featuresDictLock); 1232 1233 // Notify EnergySaver and all those in user space so they might 1234 // re-populate their feature specific UI 1235 if(pmPowerStateQueue) { 1236 pmPowerStateQueue->featureChangeOccurred( 1237 kIOPMMessageFeatureChange, this); 1238 } 1239} 1240 1241// ***************************************************************************** 1242// removePublishedFeature 1243// 1244// Removes previously published feature 1245// 1246// 1247// ***************************************************************************** 1248IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID ) 1249{ 1250 IOReturn ret = kIOReturnError; 1251 uint32_t feature_value = 0; 1252 uint16_t feature_id = 0; 1253 bool madeAChange = false; 1254 1255 OSSymbol *dictKey = NULL; 1256 OSCollectionIterator *dictIterator = NULL; 1257 OSArray *arrayMember = NULL; 1258 OSNumber *numberMember = NULL; 1259 OSObject *osObj = NULL; 1260 OSNumber *osNum = NULL; 1261 1262 if(featuresDictLock) IOLockLock(featuresDictLock); 1263 1264 OSDictionary *features = 1265 (OSDictionary *) getProperty(kRootDomainSupportedFeatures); 1266 1267 if ( features && OSDynamicCast(OSDictionary, features) ) 1268 { 1269 // Any modifications to the dictionary are made to the copy to prevent 1270 // races & crashes with userland clients. Dictionary updated 1271 // automically later. 1272 features = OSDictionary::withDictionary(features); 1273 } else { 1274 features = NULL; 1275 ret = kIOReturnNotFound; 1276 goto exit; 1277 } 1278 1279 // We iterate 'features' dictionary looking for an entry tagged 1280 // with 'removeFeatureID'. If found, we remove it from our tracking 1281 // structures and notify the OS via a general interest message. 1282 1283 dictIterator = OSCollectionIterator::withCollection(features); 1284 if(!dictIterator) { 1285 goto exit; 1286 } 1287 1288 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) ) 1289 { 1290 osObj = features->getObject(dictKey); 1291 1292 // Each Feature is either tracked by an OSNumber 1293 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) ) 1294 { 1295 feature_value = numberMember->unsigned32BitValue(); 1296 feature_id = (uint16_t)(feature_value >> 16); 1297 1298 if( feature_id == (uint16_t)removeFeatureID ) 1299 { 1300 // Remove this node 1301 features->removeObject(dictKey); 1302 madeAChange = true; 1303 break; 1304 } 1305 1306 // Or tracked by an OSArray of OSNumbers 1307 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) ) 1308 { 1309 unsigned int arrayCount = arrayMember->getCount(); 1310 1311 for(unsigned int i=0; i<arrayCount; i++) 1312 { 1313 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i)); 1314 if(!osNum) { 1315 continue; 1316 } 1317 1318 feature_value = osNum->unsigned32BitValue(); 1319 feature_id = (uint16_t)(feature_value >> 16); 1320 1321 if( feature_id == (uint16_t)removeFeatureID ) 1322 { 1323 // Remove this node 1324 if( 1 == arrayCount ) { 1325 // If the array only contains one element, remove 1326 // the whole thing. 1327 features->removeObject(dictKey); 1328 } else { 1329 // Otherwise just remove the element in question. 1330 arrayMember->removeObject(i); 1331 } 1332 1333 madeAChange = true; 1334 break; 1335 } 1336 } 1337 } 1338 } 1339 1340 1341 dictIterator->release(); 1342 1343 if( madeAChange ) 1344 { 1345 ret = kIOReturnSuccess; 1346 1347 setProperty(kRootDomainSupportedFeatures, features); 1348 1349 // Notify EnergySaver and all those in user space so they might 1350 // re-populate their feature specific UI 1351 if(pmPowerStateQueue) { 1352 pmPowerStateQueue->featureChangeOccurred( 1353 kIOPMMessageFeatureChange, this); 1354 } 1355 } else { 1356 ret = kIOReturnNotFound; 1357 } 1358 1359exit: 1360 if(features) features->release(); 1361 if(featuresDictLock) IOLockUnlock(featuresDictLock); 1362 return ret; 1363} 1364 1365 1366// ********************************************************************************** 1367// unIdleDevice 1368// 1369// Enqueues unidle event to be performed later in a serialized context. 1370// 1371// ********************************************************************************** 1372void IOPMrootDomain::unIdleDevice( IOService *theDevice, unsigned long theState ) 1373{ 1374 if(pmPowerStateQueue) 1375 pmPowerStateQueue->unIdleOccurred(theDevice, theState); 1376} 1377 1378// ********************************************************************************** 1379// announcePowerSourceChange 1380// 1381// Notifies "interested parties" that the batteries have changed state 1382// 1383// ********************************************************************************** 1384void IOPMrootDomain::announcePowerSourceChange( void ) 1385{ 1386 IORegistryEntry *_batteryRegEntry = (IORegistryEntry *) getProperty("BatteryEntry"); 1387 1388 // (if possible) re-publish power source state under IOPMrootDomain; 1389 // only do so if the battery controller publishes an IOResource 1390 // defining battery location. Called from ApplePMU battery driver. 1391 1392 if(_batteryRegEntry) 1393 { 1394 OSArray *batt_info; 1395 batt_info = (OSArray *) _batteryRegEntry->getProperty(kIOBatteryInfoKey); 1396 if(batt_info) 1397 setProperty(kIOBatteryInfoKey, batt_info); 1398 } 1399 1400} 1401 1402 1403// ***************************************************************************** 1404// setPMSetting (private) 1405// 1406// Internal helper to relay PM settings changes from user space to individual 1407// drivers. Should be called only by IOPMrootDomain::setProperties. 1408// 1409// ***************************************************************************** 1410IOReturn IOPMrootDomain::setPMSetting( 1411 const OSSymbol *type, 1412 OSObject *obj) 1413{ 1414 OSArray *arr = NULL; 1415 PMSettingObject *p_obj = NULL; 1416 int count; 1417 int i; 1418 1419 if(NULL == type) return kIOReturnBadArgument; 1420 1421 IORecursiveLockLock(settingsCtrlLock); 1422 1423 fPMSettingsDict->setObject(type, obj); 1424 1425 arr = (OSArray *)settingsCallbacks->getObject(type); 1426 if(NULL == arr) goto exit; 1427 count = arr->getCount(); 1428 for(i=0; i<count; i++) { 1429 p_obj = (PMSettingObject *)OSDynamicCast(PMSettingObject, arr->getObject(i)); 1430 if(p_obj) p_obj->setPMSetting(type, obj); 1431 } 1432 1433exit: 1434 IORecursiveLockUnlock(settingsCtrlLock); 1435 return kIOReturnSuccess; 1436} 1437 1438// ***************************************************************************** 1439// copyPMSetting (public) 1440// 1441// Allows kexts to safely read setting values, without being subscribed to 1442// notifications. 1443// 1444// ***************************************************************************** 1445OSObject * IOPMrootDomain::copyPMSetting( 1446 OSSymbol *whichSetting) 1447{ 1448 OSObject *obj = NULL; 1449 1450 if(!whichSetting) return NULL; 1451 1452 IORecursiveLockLock(settingsCtrlLock); 1453 obj = fPMSettingsDict->getObject(whichSetting); 1454 if(obj) { 1455 obj->retain(); 1456 } 1457 IORecursiveLockUnlock(settingsCtrlLock); 1458 1459 return obj; 1460} 1461 1462// ***************************************************************************** 1463// registerPMSettingController (public) 1464// 1465// direct wrapper to registerPMSettingController with uint32_t power source arg 1466// ***************************************************************************** 1467IOReturn IOPMrootDomain::registerPMSettingController( 1468 const OSSymbol * settings[], 1469 IOPMSettingControllerCallback func, 1470 OSObject *target, 1471 uintptr_t refcon, 1472 OSObject **handle) 1473{ 1474 return registerPMSettingController( 1475 settings, 1476 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS), 1477 func, target, refcon, handle); 1478} 1479 1480// ***************************************************************************** 1481// registerPMSettingController (public) 1482// 1483// Kexts may register for notifications when a particular setting is changed. 1484// A list of settings is available in IOPM.h. 1485// Arguments: 1486// * settings - An OSArray containing OSSymbols. Caller should populate this 1487// array with a list of settings caller wants notifications from. 1488// * func - A C function callback of the type IOPMSettingControllerCallback 1489// * target - caller may provide an OSObject *, which PM will pass as an 1490// target to calls to "func" 1491// * refcon - caller may provide an void *, which PM will pass as an 1492// argument to calls to "func" 1493// * handle - This is a return argument. We will populate this pointer upon 1494// call success. Hold onto this and pass this argument to 1495// IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext 1496// Returns: 1497// kIOReturnSuccess on success 1498// ***************************************************************************** 1499IOReturn IOPMrootDomain::registerPMSettingController( 1500 const OSSymbol * settings[], 1501 uint32_t supportedPowerSources, 1502 IOPMSettingControllerCallback func, 1503 OSObject *target, 1504 uintptr_t refcon, 1505 OSObject **handle) 1506{ 1507 PMSettingObject *pmso = NULL; 1508 OSArray *list = NULL; 1509 IOReturn ret = kIOReturnSuccess; 1510 int i; 1511 1512 if( NULL == settings || 1513 NULL == func || 1514 NULL == handle) 1515 { 1516 return kIOReturnBadArgument; 1517 } 1518 1519 pmso = PMSettingObject::pmSettingObject( 1520 (IOPMrootDomain *)this, func, target, 1521 refcon, supportedPowerSources, settings); 1522 1523 if(!pmso) { 1524 ret = kIOReturnInternalError; 1525 goto bail_no_unlock; 1526 } 1527 1528 IORecursiveLockLock(settingsCtrlLock); 1529 for(i=0; settings[i]; i++) 1530 { 1531 list = (OSArray *)settingsCallbacks->getObject(settings[i]); 1532 if(!list) { 1533 // New array of callbacks for this setting 1534 list = OSArray::withCapacity(1); 1535 settingsCallbacks->setObject(settings[i], list); 1536 list->release(); 1537 } 1538 1539 // Add caller to the callback list 1540 list->setObject(pmso); 1541 } 1542 1543 IORecursiveLockUnlock(settingsCtrlLock); 1544 1545 ret = kIOReturnSuccess; 1546 1547 // Track this instance by its OSData ptr from now on 1548 *handle = pmso; 1549 1550bail_no_unlock: 1551 if(kIOReturnSuccess != ret) 1552 { 1553 // Error return case 1554 if(pmso) pmso->release(); 1555 if(handle) *handle = NULL; 1556 } 1557 return ret; 1558} 1559 1560 1561//****************************************************************************** 1562// sleepOnClamshellClosed 1563// 1564// contains the logic to determine if the system should sleep when the clamshell 1565// is closed. 1566//****************************************************************************** 1567 1568bool IOPMrootDomain::shouldSleepOnClamshellClosed ( void ) 1569{ 1570 return ( !ignoringClamshell 1571 && !ignoringClamshellDuringWakeup 1572 && !(desktopMode && acAdaptorConnect) ); 1573} 1574 1575void IOPMrootDomain::sendClientClamshellNotification ( void ) 1576{ 1577 /* Only broadcast clamshell alert if clamshell exists. */ 1578 if(!clamshellExists) 1579 return; 1580 1581 setProperty(kAppleClamshellStateKey, 1582 clamshellIsClosed ? kOSBooleanTrue : kOSBooleanFalse); 1583 1584 setProperty(kAppleClamshellCausesSleepKey, 1585 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse); 1586 1587 1588 /* Argument to message is a bitfiel of 1589 * ( kClamshellStateBit | kClamshellSleepBit ) 1590 */ 1591 messageClients(kIOPMMessageClamshellStateChange, 1592 (void *) ( (clamshellIsClosed ? kClamshellStateBit : 0) 1593 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) ); 1594} 1595 1596//****************************************************************************** 1597// informCPUStateChange 1598// 1599// Call into PM CPU code so that CPU power savings may dynamically adjust for 1600// running on battery, with the lid closed, etc. 1601// 1602// informCPUStateChange is a no-op on non x86 systems 1603// only x86 has explicit support in the IntelCPUPowerManagement kext 1604//****************************************************************************** 1605 1606void IOPMrootDomain::informCPUStateChange( 1607 uint32_t type, 1608 uint32_t value ) 1609{ 1610#ifdef __i386__ 1611 1612 pmioctlVariableInfo_t varInfoStruct; 1613 int pmCPUret = 0; 1614 const char *varNameStr = NULL; 1615 int32_t *varIndex = NULL; 1616 1617 if (kInformAC == type) { 1618 varNameStr = kIOPMRootDomainBatPowerCString; 1619 varIndex = &idxPMCPULimitedPower; 1620 } else if (kInformLid == type) { 1621 varNameStr = kIOPMRootDomainLidCloseCString; 1622 varIndex = &idxPMCPUClamshell; 1623 } else { 1624 return; 1625 } 1626 1627 // Set the new value! 1628 // pmCPUControl will assign us a new ID if one doesn't exist yet 1629 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t)); 1630 varInfoStruct.varID = *varIndex; 1631 varInfoStruct.varType = vBool; 1632 varInfoStruct.varInitValue = value; 1633 varInfoStruct.varCurValue = value; 1634 strncpy( (char *)varInfoStruct.varName, 1635 (const char *)varNameStr, 1636 strlen(varNameStr) + 1 ); 1637 1638 // Set! 1639 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct ); 1640 1641 // pmCPU only assigns numerical id's when a new varName is specified 1642 if ((0 == pmCPUret) 1643 && (*varIndex == kCPUUnknownIndex)) 1644 { 1645 // pmCPUControl has assigned us a new variable ID. 1646 // Let's re-read the structure we just SET to learn that ID. 1647 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct ); 1648 1649 if (0 == pmCPUret) 1650 { 1651 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower 1652 *varIndex = varInfoStruct.varID; 1653 } 1654 } 1655 1656 return; 1657 1658#endif __i386__ 1659} 1660 1661//****************************************************************************** 1662// systemPowerEventOccurred 1663// 1664// The power controller is notifying us of a hardware-related power management 1665// event that we must handle. 1666// 1667// systemPowerEventOccurred covers the same functionality that receivePowerNotification 1668// does; it simply provides a richer API for conveying more information. 1669//****************************************************************************** 1670IOReturn IOPMrootDomain::systemPowerEventOccurred( 1671 const OSSymbol *event, 1672 uint32_t intValue) 1673{ 1674 IOReturn attempt = kIOReturnSuccess; 1675 OSNumber *newNumber = NULL; 1676 1677 if (!event) 1678 return kIOReturnBadArgument; 1679 1680 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue)); 1681 if (!newNumber) 1682 return kIOReturnInternalError; 1683 1684 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber); 1685 1686 newNumber->release(); 1687 1688 return attempt; 1689} 1690 1691IOReturn IOPMrootDomain::systemPowerEventOccurred( 1692 const OSSymbol *event, 1693 OSObject *value) 1694{ 1695 OSDictionary *thermalsDict = NULL; 1696 bool shouldUpdate = true; 1697 1698 if (!event || !value) 1699 return kIOReturnBadArgument; 1700 1701 // LOCK 1702 // We reuse featuresDict Lock because it already exists and guards 1703 // the very infrequently used publish/remove feature mechanism; so there's zero rsk 1704 // of stepping on that lock. 1705 if (featuresDictLock) IOLockLock(featuresDictLock); 1706 1707 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey); 1708 1709 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) { 1710 thermalsDict = OSDictionary::withDictionary(thermalsDict); 1711 } else { 1712 thermalsDict = OSDictionary::withCapacity(1); 1713 } 1714 1715 if (!thermalsDict) { 1716 shouldUpdate = false; 1717 goto exit; 1718 } 1719 1720 thermalsDict->setObject (event, value); 1721 1722 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict); 1723 1724 thermalsDict->release(); 1725 1726exit: 1727 // UNLOCK 1728 if (featuresDictLock) IOLockUnlock(featuresDictLock); 1729 1730 if (shouldUpdate) 1731 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL); 1732 1733 return kIOReturnSuccess; 1734} 1735 1736 1737//****************************************************************************** 1738// receivePowerNotification 1739// 1740// The power controller is notifying us of a hardware-related power management 1741// event that we must handle. This may be a result of an 'environment' interrupt from 1742// the power mgt micro. 1743//****************************************************************************** 1744 1745IOReturn IOPMrootDomain::receivePowerNotification (UInt32 msg) 1746{ 1747 bool eval_clamshell = false; 1748 1749 /* 1750 * Local (IOPMrootDomain only) eval clamshell command 1751 */ 1752 if (msg & kLocalEvalClamshellCommand) 1753 { 1754 eval_clamshell = true; 1755 } 1756 1757 /* 1758 * Overtemp 1759 */ 1760 if (msg & kIOPMOverTemp) 1761 { 1762 IOLog("PowerManagement emergency overtemp signal. Going to sleep!"); 1763 1764 privateSleepSystem (kIOPMThermalEmergencySleepKey); 1765 } 1766 1767 /* 1768 * PMU Processor Speed Change 1769 */ 1770 if (msg & kIOPMProcessorSpeedChange) 1771 { 1772 IOService *pmu = waitForService(serviceMatching("ApplePMU")); 1773 pmu->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0); 1774 getPlatform()->sleepKernel(); 1775 pmu->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0); 1776 } 1777 1778 /* 1779 * Sleep Now! 1780 */ 1781 if (msg & kIOPMSleepNow) 1782 { 1783 privateSleepSystem (kIOPMSoftwareSleepKey); 1784 } 1785 1786 /* 1787 * Power Emergency 1788 */ 1789 if (msg & kIOPMPowerEmergency) 1790 { 1791 privateSleepSystem (kIOPMLowPowerSleepKey); 1792 } 1793 1794 1795 /* 1796 * Clamshell OPEN 1797 */ 1798 if (msg & kIOPMClamshellOpened) 1799 { 1800 // Received clamshel open message from clamshell controlling driver 1801 // Update our internal state and tell general interest clients 1802 clamshellIsClosed = false; 1803 clamshellExists = true; 1804 1805 // Tell PMCPU 1806 informCPUStateChange(kInformLid, 0); 1807 1808 // Tell general interest clients 1809 sendClientClamshellNotification(); 1810 } 1811 1812 /* 1813 * Clamshell CLOSED 1814 * Send the clamshell interest notification since the lid is closing. 1815 */ 1816 if (msg & kIOPMClamshellClosed) 1817 { 1818 // Received clamshel open message from clamshell controlling driver 1819 // Update our internal state and tell general interest clients 1820 clamshellIsClosed = true; 1821 clamshellExists = true; 1822 1823 // Tell PMCPU 1824 informCPUStateChange(kInformLid, 1); 1825 1826 // Tell general interest clients 1827 sendClientClamshellNotification(); 1828 1829 // And set eval_clamshell = so we can attempt 1830 eval_clamshell = true; 1831 } 1832 1833 /* 1834 * Set Desktop mode (sent from graphics) 1835 * 1836 * -> reevaluate lid state 1837 */ 1838 if (msg & kIOPMSetDesktopMode) 1839 { 1840 desktopMode = (0 != (msg & kIOPMSetValue)); 1841 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue); 1842 1843 sendClientClamshellNotification(); 1844 1845 // Re-evaluate the lid state 1846 if( clamshellIsClosed ) 1847 { 1848 eval_clamshell = true; 1849 } 1850 } 1851 1852 /* 1853 * AC Adaptor connected 1854 * 1855 * -> reevaluate lid state 1856 */ 1857 if (msg & kIOPMSetACAdaptorConnected) 1858 { 1859 acAdaptorConnect = (0 != (msg & kIOPMSetValue)); 1860 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue); 1861 1862 // Tell PMCPU 1863 informCPUStateChange(kInformAC, !acAdaptorConnect); 1864 1865 sendClientClamshellNotification(); 1866 1867 // Re-evaluate the lid state 1868 if( clamshellIsClosed ) 1869 { 1870 eval_clamshell = true; 1871 } 1872 1873 } 1874 1875 /* 1876 * Enable Clamshell (external display disappear) 1877 * 1878 * -> reevaluate lid state 1879 */ 1880 if (msg & kIOPMEnableClamshell) 1881 { 1882 // Re-evaluate the lid state 1883 // System should sleep on external display disappearance 1884 // in lid closed operation. 1885 if( clamshellIsClosed && (true == ignoringClamshell) ) 1886 { 1887 eval_clamshell = true; 1888 } 1889 1890 ignoringClamshell = false; 1891 1892 sendClientClamshellNotification(); 1893 } 1894 1895 /* 1896 * Disable Clamshell (external display appeared) 1897 * We don't bother re-evaluating clamshell state. If the system is awake, 1898 * the lid is probably open. 1899 */ 1900 if (msg & kIOPMDisableClamshell) 1901 { 1902 ignoringClamshell = true; 1903 1904 sendClientClamshellNotification(); 1905 } 1906 1907 /* 1908 * Evaluate clamshell and SLEEP if appropiate 1909 */ 1910 if ( eval_clamshell && shouldSleepOnClamshellClosed() ) 1911 { 1912 1913 1914 // SLEEP! 1915 privateSleepSystem (kIOPMClamshellSleepKey); 1916 } 1917 1918 /* 1919 * Power Button 1920 */ 1921 if (msg & kIOPMPowerButton) 1922 { 1923 // toggle state of sleep/wake 1924 // are we dozing? 1925 if ( getPowerState() == DOZE_STATE ) 1926 { 1927 // yes, tell the tree we're waking 1928 systemWake(); 1929 // wake the Display Wrangler 1930 reportUserInput(); 1931 } 1932 else { 1933 OSString *pbs = OSString::withCString("DisablePowerButtonSleep"); 1934 // Check that power button sleep is enabled 1935 if( pbs ) { 1936 if( kOSBooleanTrue != getProperty(pbs)) 1937 privateSleepSystem (kIOPMPowerButtonSleepKey); 1938 } 1939 } 1940 } 1941 1942 /* 1943 * Allow Sleep 1944 * 1945 */ 1946 if ( (msg & kIOPMAllowSleep) && !allowSleep ) 1947 { 1948 allowSleep = true; 1949 adjustPowerState(); 1950 } 1951 1952 /* 1953 * Prevent Sleep 1954 * 1955 */ 1956 if (msg & kIOPMPreventSleep) { 1957 allowSleep = false; 1958 // are we dozing? 1959 if ( getPowerState() == DOZE_STATE ) { 1960 // yes, tell the tree we're waking 1961 systemWake(); 1962 adjustPowerState(); 1963 // wake the Display Wrangler 1964 reportUserInput(); 1965 } else { 1966 adjustPowerState(); 1967 // make sure we have power to clamp 1968 patriarch->wakeSystem(); 1969 } 1970 } 1971 1972 return 0; 1973} 1974 1975 1976//********************************************************************************* 1977// sleepSupported 1978// 1979//********************************************************************************* 1980 1981void IOPMrootDomain::setSleepSupported( IOOptionBits flags ) 1982{ 1983 if ( flags & kPCICantSleep ) 1984 { 1985 canSleep = false; 1986 } else { 1987 canSleep = true; 1988 platformSleepSupport = flags; 1989 } 1990 1991 setProperty(kIOSleepSupportedKey, canSleep); 1992 1993} 1994 1995//********************************************************************************* 1996// requestPowerDomainState 1997// 1998// The root domain intercepts this call to the superclass. 1999// Called on the PM work loop thread. 2000// 2001// If the clamp bit is not set in the desire, then the child doesn't need the power 2002// state it's requesting; it just wants it. The root ignores desires but not needs. 2003// If the clamp bit is not set, the root takes it that the child can tolerate no 2004// power and interprets the request accordingly. If all children can thus tolerate 2005// no power, we are on our way to idle sleep. 2006//********************************************************************************* 2007 2008IOReturn IOPMrootDomain::requestPowerDomainState ( 2009 IOPMPowerFlags desiredState, 2010 IOPowerConnection * whichChild, 2011 unsigned long specification ) 2012{ 2013 OSIterator *iter; 2014 OSObject *next; 2015 IOPowerConnection *connection; 2016 unsigned long powerRequestFlag = 0; 2017 IOPMPowerFlags editedDesire; 2018 2019#if DEBUG 2020 IOService *powerChild; 2021 powerChild = (IOService *) whichChild->getChildEntry(gIOPowerPlane); 2022#endif 2023 2024 DEBUG_LOG("RequestPowerDomainState: flags %lx, child %p [%s], spec %lx\n", 2025 desiredState, powerChild, powerChild ? powerChild->getName() : "?", 2026 specification); 2027 2028 // Force the child's input power requirements to 0 unless the prevent 2029 // idle-sleep flag is set. No input power flags map to our state 0. 2030 // Our power clamp (deviceDesire) keeps the minimum power state at 2. 2031 2032 if (desiredState & kIOPMPreventIdleSleep) 2033 editedDesire = desiredState; 2034 else 2035 editedDesire = 0; 2036 2037 // Recompute sleep supported flag (doze if not supported) 2038 sleepIsSupported = true; 2039 2040 iter = getChildIterator(gIOPowerPlane); 2041 if ( iter ) 2042 { 2043 while ( (next = iter->getNextObject()) ) 2044 { 2045 if ( (connection = OSDynamicCast(IOPowerConnection, next)) ) 2046 { 2047 // Ignore child that are in the process of joining. 2048 if (connection->getReadyFlag() == false) 2049 continue; 2050 2051 // Is this connection attached to the child that called 2052 // requestPowerDomainState()? 2053 2054 if ( connection == whichChild ) 2055 { 2056 // Yes, OR in the child's input power requirements. 2057 powerRequestFlag |= editedDesire; 2058 2059 if ( desiredState & kIOPMPreventSystemSleep ) 2060 sleepIsSupported = false; 2061 } 2062 else 2063 { 2064#if DEBUG 2065 powerChild = (IOService *) connection->getChildEntry(gIOPowerPlane); 2066#endif 2067 DEBUG_LOG(" child %p, PState %ld, noIdle %d, noSleep %d, valid %d %s\n", 2068 powerChild, 2069 connection->getDesiredDomainState(), 2070 connection->getPreventIdleSleepFlag(), 2071 connection->getPreventSystemSleepFlag(), 2072 connection->getReadyFlag(), 2073 powerChild ? powerChild->getName() : "?"); 2074 2075 // No, OR in the child's desired power domain state. 2076 // Which is our power state desired by this child. 2077 powerRequestFlag |= connection->getDesiredDomainState(); 2078 2079 if ( connection->getPreventSystemSleepFlag() ) 2080 sleepIsSupported = false; 2081 } 2082 } 2083 } 2084 iter->release(); 2085 } 2086 2087 if ( !powerRequestFlag && !systemBooting ) 2088 { 2089 if (!wrangler) 2090 { 2091 sleepASAP = false; 2092 changePowerStateToPriv(ON_STATE); 2093 if (idleSeconds) 2094 { 2095 AbsoluteTime deadline; 2096 // stay awake for at least idleSeconds 2097 clock_interval_to_deadline(idleSeconds, kSecondScale, &deadline); 2098 thread_call_enter_delayed(extraSleepTimer, deadline); 2099 // this gets turned off when we sleep again 2100 idleSleepPending = true; 2101 } 2102 } 2103 else if (extraSleepDelay == 0) 2104 { 2105 sleepASAP = true; 2106 } 2107 } 2108 2109 DEBUG_LOG(" sleepDelay %lx, mergedFlags %lx, sleepASAP %x, booting %x\n", 2110 extraSleepDelay, powerRequestFlag, sleepASAP, systemBooting); 2111 2112 // Drop our power clamp to SLEEP_STATE when all devices become idle. 2113 // Needed when the system sleep and display sleep timeouts are the same. 2114 // Otherwise, the extra sleep timer will also drop our power clamp. 2115 2116 adjustPowerState(); 2117 2118 editedDesire |= (desiredState & kIOPMPreventSystemSleep); 2119 2120 // If our power clamp has already dropped to SLEEP_STATE, and no child 2121 // is keeping us at max power, then this will trigger idle sleep. 2122 2123 return super::requestPowerDomainState(editedDesire, whichChild, specification); 2124} 2125 2126 2127//********************************************************************************* 2128// getSleepSupported 2129// 2130//********************************************************************************* 2131 2132IOOptionBits IOPMrootDomain::getSleepSupported( void ) 2133{ 2134 return( platformSleepSupport ); 2135} 2136 2137 2138//********************************************************************************* 2139// handlePlatformHaltRestart 2140// 2141//********************************************************************************* 2142 2143struct HaltRestartApplierContext { 2144 IOPMrootDomain * RootDomain; 2145 unsigned long PowerState; 2146 IOPMPowerFlags PowerFlags; 2147 UInt32 MessageType; 2148 UInt32 Counter; 2149}; 2150 2151static void 2152platformHaltRestartApplier( OSObject * object, void * context ) 2153{ 2154 IOPowerStateChangeNotification notify; 2155 HaltRestartApplierContext * ctx; 2156 AbsoluteTime startTime; 2157 UInt32 deltaTime; 2158 2159 ctx = (HaltRestartApplierContext *) context; 2160 2161 memset(¬ify, 0, sizeof(notify)); 2162 notify.powerRef = (void *)ctx->Counter; 2163 notify.returnValue = 0; 2164 notify.stateNumber = ctx->PowerState; 2165 notify.stateFlags = ctx->PowerFlags; 2166 2167 clock_get_uptime(&startTime); 2168 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)¬ify ); 2169 deltaTime = computeDeltaTimeMS(&startTime); 2170 2171 if ((deltaTime > kPMHaltTimeoutMS) || (gIOKitDebug & kIOLogDebugPower)) 2172 { 2173 _IOServiceInterestNotifier * notifier; 2174 notifier = OSDynamicCast(_IOServiceInterestNotifier, object); 2175 2176 // IOService children of IOPMrootDomain are not instrumented. 2177 // Only IORootParent currently falls under that group. 2178 2179 if (notifier) 2180 { 2181 HaltRestartLog("%s handler %p took %lu ms\n", 2182 (ctx->MessageType == kIOMessageSystemWillPowerOff) ? 2183 "PowerOff" : "Restart", 2184 notifier->handler, deltaTime ); 2185 } 2186 } 2187 2188 ctx->Counter++; 2189} 2190 2191void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type ) 2192{ 2193 HaltRestartApplierContext ctx; 2194 AbsoluteTime startTime; 2195 UInt32 deltaTime; 2196 2197 memset(&ctx, 0, sizeof(ctx)); 2198 ctx.RootDomain = this; 2199 2200 clock_get_uptime(&startTime); 2201 switch (pe_type) 2202 { 2203 case kPEHaltCPU: 2204 ctx.PowerState = OFF_STATE; 2205 ctx.MessageType = kIOMessageSystemWillPowerOff; 2206 break; 2207 2208 case kPERestartCPU: 2209 ctx.PowerState = RESTART_STATE; 2210 ctx.MessageType = kIOMessageSystemWillRestart; 2211 break; 2212 2213 default: 2214 return; 2215 } 2216 2217 // Notify legacy clients 2218 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx); 2219 2220 // Notify in power tree order 2221 notifySystemShutdown(this, ctx.MessageType); 2222 2223 deltaTime = computeDeltaTimeMS(&startTime); 2224 HaltRestartLog("%s all drivers took %lu ms\n", 2225 (ctx.MessageType == kIOMessageSystemWillPowerOff) ? 2226 "PowerOff" : "Restart", 2227 deltaTime ); 2228} 2229 2230 2231//********************************************************************************* 2232// tellChangeDown 2233// 2234// We override the superclass implementation so we can send a different message 2235// type to the client or application being notified. 2236//********************************************************************************* 2237 2238bool IOPMrootDomain::tellChangeDown ( unsigned long stateNum ) 2239{ 2240 switch ( stateNum ) { 2241 case DOZE_STATE: 2242 case SLEEP_STATE: 2243 2244 // Direct callout into OSMetaClass so it can disable kmod unloads 2245 // during sleep/wake to prevent deadlocks. 2246 OSMetaClassSystemSleepOrWake( kIOMessageSystemWillSleep ); 2247 2248 return super::tellClientsWithResponse(kIOMessageSystemWillSleep); 2249 } 2250 return super::tellChangeDown(stateNum); 2251} 2252 2253 2254//********************************************************************************* 2255// askChangeDown 2256// 2257// We override the superclass implementation so we can send a different message 2258// type to the client or application being notified. 2259// 2260// This must be idle sleep since we don't ask apps during any other power change. 2261//********************************************************************************* 2262 2263bool IOPMrootDomain::askChangeDown ( unsigned long ) 2264{ 2265 return super::tellClientsWithResponse(kIOMessageCanSystemSleep); 2266} 2267 2268 2269//********************************************************************************* 2270// tellNoChangeDown 2271// 2272// Notify registered applications and kernel clients that we are not 2273// dropping power. 2274// 2275// We override the superclass implementation so we can send a different message 2276// type to the client or application being notified. 2277// 2278// This must be a vetoed idle sleep, since no other power change can be vetoed. 2279//********************************************************************************* 2280 2281void IOPMrootDomain::tellNoChangeDown ( unsigned long ) 2282{ 2283 if (idleSeconds && !wrangler) 2284 { 2285 AbsoluteTime deadline; 2286 sleepASAP = false; 2287 // stay awake for at least idleSeconds 2288 clock_interval_to_deadline(idleSeconds, kSecondScale, &deadline); 2289 thread_call_enter_delayed(extraSleepTimer, deadline); 2290 // this gets turned off when we sleep again 2291 idleSleepPending = true; 2292 } 2293 return tellClients(kIOMessageSystemWillNotSleep); 2294} 2295 2296 2297//********************************************************************************* 2298// tellChangeUp 2299// 2300// Notify registered applications and kernel clients that we are raising power. 2301// 2302// We override the superclass implementation so we can send a different message 2303// type to the client or application being notified. 2304//********************************************************************************* 2305 2306void IOPMrootDomain::tellChangeUp ( unsigned long stateNum) 2307{ 2308 if ( stateNum == ON_STATE ) 2309 { 2310 // Direct callout into OSMetaClass so it can disable kmod unloads 2311 // during sleep/wake to prevent deadlocks. 2312 OSMetaClassSystemSleepOrWake( kIOMessageSystemHasPoweredOn ); 2313 2314 if (getPowerState() == ON_STATE) 2315 { 2316 // this is a quick wake from aborted sleep 2317 if (idleSeconds && !wrangler) 2318 { 2319 AbsoluteTime deadline; 2320 sleepASAP = false; 2321 // stay awake for at least idleSeconds 2322 clock_interval_to_deadline(idleSeconds, kSecondScale, &deadline); 2323 thread_call_enter_delayed(extraSleepTimer, deadline); 2324 // this gets turned off when we sleep again 2325 idleSleepPending = true; 2326 } 2327 tellClients(kIOMessageSystemWillPowerOn); 2328 } 2329#if HIBERNATION 2330 else 2331 { 2332 IOHibernateSystemPostWake(); 2333 } 2334#endif 2335 return tellClients(kIOMessageSystemHasPoweredOn); 2336 } 2337} 2338 2339//********************************************************************************* 2340// reportUserInput 2341// 2342//********************************************************************************* 2343 2344void IOPMrootDomain::reportUserInput ( void ) 2345{ 2346#if !NO_KERNEL_HID 2347 OSIterator * iter; 2348 2349 if(!wrangler) 2350 { 2351 iter = getMatchingServices(serviceMatching("IODisplayWrangler")); 2352 if(iter) 2353 { 2354 wrangler = (IOService *) iter->getNextObject(); 2355 iter->release(); 2356 } 2357 } 2358 2359 if(wrangler) 2360 wrangler->activityTickle(0,0); 2361#endif 2362} 2363 2364//********************************************************************************* 2365// setQuickSpinDownTimeout 2366// 2367//********************************************************************************* 2368 2369void IOPMrootDomain::setQuickSpinDownTimeout ( void ) 2370{ 2371 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)1); 2372} 2373 2374//********************************************************************************* 2375// restoreUserSpinDownTimeout 2376// 2377//********************************************************************************* 2378 2379void IOPMrootDomain::restoreUserSpinDownTimeout ( void ) 2380{ 2381 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)user_spindown); 2382} 2383 2384//********************************************************************************* 2385// changePowerStateTo & changePowerStateToPriv 2386// 2387// Override of these methods for logging purposes. 2388//********************************************************************************* 2389 2390IOReturn IOPMrootDomain::changePowerStateTo ( unsigned long ordinal ) 2391{ 2392 return super::changePowerStateTo(ordinal); 2393} 2394 2395IOReturn IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal ) 2396{ 2397 IOReturn ret; 2398 2399 DEBUG_LOG("ChangePowerStateToPriv: power state %ld\n", ordinal); 2400 2401 if ( (getPowerState() == DOZE_STATE) && (ordinal != ON_STATE) ) 2402 { 2403 return kIOReturnSuccess; 2404 } 2405 2406 if( (userDisabledAllSleep || systemBooting || systemShutdown) 2407 && (ordinal == SLEEP_STATE) ) 2408 { 2409 DEBUG_LOG(" sleep denied: disableAllSleep %d, booting %d, shutdown %d\n", 2410 userDisabledAllSleep, systemBooting, systemShutdown); 2411 super::changePowerStateToPriv(ON_STATE); 2412 } 2413 2414 if( (SLEEP_STATE == ordinal) && sleepSupportedPEFunction ) 2415 { 2416 2417 // Determine if the machine supports sleep, or must doze. 2418 ret = getPlatform()->callPlatformFunction( 2419 sleepSupportedPEFunction, false, 2420 NULL, NULL, NULL, NULL); 2421 2422 // If the machine only supports doze, the callPlatformFunction call 2423 // boils down to IOPMrootDomain::setSleepSupported(kPCICantSleep), 2424 // otherwise nothing. 2425 } 2426 2427 return super::changePowerStateToPriv(ordinal); 2428} 2429 2430 2431//********************************************************************************* 2432// sysPowerDownHandler 2433// 2434// Receives a notification when the RootDomain changes state. 2435// 2436// Allows us to take action on system sleep, power down, and restart after 2437// applications have received their power change notifications and replied, 2438// but before drivers have powered down. We perform a vfs sync on power down. 2439//********************************************************************************* 2440 2441IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon, 2442 UInt32 messageType, IOService * service, 2443 void * messageArgument, vm_size_t argSize ) 2444{ 2445 IOReturn ret; 2446 IOPowerStateChangeNotification *params = (IOPowerStateChangeNotification *) messageArgument; 2447 IOPMrootDomain *rootDomain = OSDynamicCast(IOPMrootDomain, service); 2448 2449 if(!rootDomain) 2450 return kIOReturnUnsupported; 2451 2452 switch (messageType) { 2453 case kIOMessageSystemWillSleep: 2454 DEBUG_LOG("SystemWillSleep\n"); 2455 2456 // Interested applications have been notified of an impending power 2457 // change and have acked (when applicable). 2458 // This is our chance to save whatever state we can before powering 2459 // down. 2460 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c, 2461 // via callout 2462 2463 // We will ack within 20 seconds 2464 params->returnValue = 20 * 1000 * 1000; 2465#if HIBERNATION 2466 if (gIOHibernateState) 2467 params->returnValue += gIOHibernateFreeTime * 1000; //add in time we could spend freeing pages 2468#endif 2469 2470 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) ) 2471 { 2472 // Purposely delay the ack and hope that shutdown occurs quickly. 2473 // Another option is not to schedule the thread and wait for 2474 // ack timeout... 2475 AbsoluteTime deadline; 2476 clock_interval_to_deadline( 30, kSecondScale, &deadline ); 2477 thread_call_enter1_delayed( rootDomain->diskSyncCalloutEntry, 2478 (thread_call_param_t)params->powerRef, 2479 deadline ); 2480 } 2481 else 2482 thread_call_enter1(rootDomain->diskSyncCalloutEntry, (thread_call_param_t)params->powerRef); 2483 ret = kIOReturnSuccess; 2484 break; 2485 2486 case kIOMessageSystemWillPowerOff: 2487 case kIOMessageSystemWillRestart: 2488 ret = kIOReturnUnsupported; 2489 break; 2490 2491 default: 2492 ret = kIOReturnUnsupported; 2493 break; 2494 } 2495 return ret; 2496} 2497 2498//********************************************************************************* 2499// displayWranglerNotification 2500// 2501// Receives a notification when the IODisplayWrangler changes state. 2502// 2503// Allows us to take action on display dim/undim. 2504// 2505// When the display sleeps we: 2506// - Start the idle sleep timer 2507// - set the quick spin down timeout 2508// 2509// On wake from display sleep: 2510// - Cancel the idle sleep timer 2511// - restore the user's chosen spindown timer from the "quick" spin down value 2512//********************************************************************************* 2513 2514IOReturn IOPMrootDomain::displayWranglerNotification( 2515 void * target, void * refCon, 2516 UInt32 messageType, IOService * service, 2517 void * messageArgument, vm_size_t argSize ) 2518{ 2519#if !NO_KERNEL_HID 2520 IOPMrootDomain * rootDomain = OSDynamicCast(IOPMrootDomain, (IOService *)target); 2521 AbsoluteTime deadline; 2522 static int displayPowerState = 4; 2523 2524 if (!rootDomain) 2525 return kIOReturnUnsupported; 2526 2527 switch (messageType) { 2528 case kIOMessageDeviceWillPowerOff: 2529 DEBUG_LOG("DisplayWranglerWillPowerOff: new p-state %d\n", 2530 displayPowerState - 1); 2531 2532 // The display wrangler has dropped power because of idle display sleep 2533 // or force system sleep. We will receive 4 messages before the display 2534 // wrangler reaches its lowest state. Act only when going to state 2. 2535 // 2536 // 4->3 Display Dim 2537 // 3->2 Display Sleep 2538 // 2->1 Not visible to user 2539 // 1->0 Not visible to user 2540 2541 displayPowerState--; 2542 if ( 2 != displayPowerState ) 2543 return kIOReturnUnsupported; 2544 2545 // We start a timer here if the System Sleep timer is greater than the 2546 // Display Sleep timer. We kick off this timer when the display sleeps. 2547 // 2548 // Note that, although Display Dim timings may change adaptively accordingly 2549 // to the user's activity patterns, Display Sleep _always_ occurs at the 2550 // specified interval since last user activity. 2551 2552 if ( rootDomain->extraSleepDelay ) 2553 { 2554 clock_interval_to_deadline(rootDomain->extraSleepDelay*60, kSecondScale, &deadline); 2555 thread_call_enter_delayed(rootDomain->extraSleepTimer, deadline); 2556 rootDomain->idleSleepPending = true; 2557 DEBUG_LOG(" sleep timer set to expire in %ld min\n", 2558 rootDomain->extraSleepDelay); 2559 } else { 2560 // Accelerate disk spindown if system sleep and display sleep 2561 // sliders are set to the same value (e.g. both set to 5 min), 2562 // and display is about to go dark. Check that spin down timer 2563 // is non-zero (zero = never spin down) and system sleep is 2564 // not set to never sleep. 2565 2566 if ( (0 != rootDomain->user_spindown) && (0 != rootDomain->sleepSlider) ) 2567 { 2568 DEBUG_LOG(" accelerate quick disk spindown, was %d min\n", 2569 rootDomain->user_spindown); 2570 rootDomain->setQuickSpinDownTimeout(); 2571 } 2572 } 2573 2574 break; 2575 2576 case kIOMessageDeviceHasPoweredOn: 2577 DEBUG_LOG("DisplayWranglerHasPoweredOn: previous p-state %d\n", 2578 displayPowerState); 2579 2580 // The display wrangler has powered on either because of user activity 2581 // or wake from sleep/doze. 2582 2583 displayPowerState = 4; 2584 rootDomain->adjustPowerState(); 2585 2586 // cancel any pending idle sleep timers 2587 if (rootDomain->idleSleepPending) 2588 { 2589 DEBUG_LOG(" extra-sleep timer stopped\n"); 2590 thread_call_cancel(rootDomain->extraSleepTimer); 2591 rootDomain->idleSleepPending = false; 2592 } 2593 2594 // Change the spindown value back to the user's selection from our 2595 // accelerated setting. 2596 if (0 != rootDomain->user_spindown) 2597 { 2598 DEBUG_LOG(" restoring disk spindown to %d min\n", 2599 rootDomain->user_spindown); 2600 rootDomain->restoreUserSpinDownTimeout(); 2601 } 2602 2603 break; 2604 2605 default: 2606 break; 2607 } 2608#endif 2609 return kIOReturnUnsupported; 2610 } 2611 2612//********************************************************************************* 2613// displayWranglerPublished 2614// 2615// Receives a notification when the IODisplayWrangler is published. 2616// When it's published we install a power state change handler. 2617// 2618//********************************************************************************* 2619 2620bool IOPMrootDomain::displayWranglerPublished( 2621 void * target, 2622 void * refCon, 2623 IOService * newService) 2624{ 2625#if !NO_KERNEL_HID 2626 IOPMrootDomain *rootDomain = 2627 OSDynamicCast(IOPMrootDomain, (IOService *)target); 2628 2629 if(!rootDomain) 2630 return false; 2631 2632 rootDomain->wrangler = newService; 2633 2634 // we found the display wrangler, now install a handler 2635 if( !rootDomain->wrangler->registerInterest( gIOGeneralInterest, 2636 &displayWranglerNotification, target, 0) ) 2637 { 2638 return false; 2639 } 2640#endif 2641 return true; 2642} 2643 2644//********************************************************************************* 2645// batteryPublished 2646// 2647// Notification on battery class IOPowerSource appearance 2648// 2649//****************************************************************************** 2650 2651bool IOPMrootDomain::batteryPublished( 2652 void * target, 2653 void * root_domain, 2654 IOService * resourceService ) 2655{ 2656 // rdar://2936060&4435589 2657 // All laptops have dimmable LCD displays 2658 // All laptops have batteries 2659 // So if this machine has a battery, publish the fact that the backlight 2660 // supports dimming. 2661 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims"); 2662 2663 return (true); 2664} 2665 2666//********************************************************************************* 2667// adjustPowerState 2668// 2669// Some condition that affects our wake/sleep/doze decision has changed. 2670// 2671// If the sleep slider is in the off position, we cannot sleep or doze. 2672// If the enclosure is open, we cannot sleep or doze. 2673// If the system is still booting, we cannot sleep or doze. 2674// 2675// In those circumstances, we prevent sleep and doze by holding power on with 2676// changePowerStateToPriv(ON). 2677// 2678// If the above conditions do not exist, and also the sleep timer has expired, we 2679// allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or 2680// changePowerStateToPriv(DOZE) depending on whether or not we already know the 2681// platform cannot sleep. 2682// 2683// In this case, sleep or doze will either occur immediately or at the next time 2684// that no children are holding the system out of idle sleep via the 2685// kIOPMPreventIdleSleep flag in their power state arrays. 2686//********************************************************************************* 2687 2688void IOPMrootDomain::adjustPowerState( void ) 2689{ 2690 if ( (sleepSlider == 0) 2691 || !allowSleep 2692 || systemBooting 2693 || systemShutdown 2694 || userDisabledAllSleep ) 2695 { 2696 DEBUG_LOG("AdjustPowerState %ld -> ON: slider %ld, allowSleep %d, " 2697 "booting %d, shutdown %d, userDisabled %d\n", 2698 getPowerState(), sleepSlider, allowSleep, systemBooting, 2699 systemShutdown, userDisabledAllSleep); 2700 2701 changePowerStateToPriv(ON_STATE); 2702 } else { 2703 if ( sleepASAP ) 2704 { 2705 DEBUG_LOG("AdjustPowerState SLEEP\n"); 2706 2707 /* Convenient place to run any code at idle sleep time 2708 * IOPMrootDomain initiates an idle sleep here 2709 * 2710 * Set last sleep cause accordingly. 2711 */ 2712 setProperty(kRootDomainSleepReasonKey, kIOPMIdleSleepKey); 2713 2714 sleepASAP = false; 2715 if ( !sleepIsSupported ) 2716 { 2717 setSleepSupported( kPCICantSleep ); 2718 kprintf("Sleep prevented by kIOPMPreventSystemSleep flag\n"); 2719 } 2720 changePowerStateToPriv(SLEEP_STATE); 2721 } 2722 } 2723} 2724 2725//********************************************************************************* 2726// PMHaltWorker Class 2727// 2728//********************************************************************************* 2729 2730static unsigned int gPMHaltBusyCount; 2731static unsigned int gPMHaltIdleCount; 2732static int gPMHaltDepth; 2733static unsigned long gPMHaltEvent; 2734static IOLock * gPMHaltLock = 0; 2735static OSArray * gPMHaltArray = 0; 2736static const OSSymbol * gPMHaltClientAcknowledgeKey = 0; 2737 2738PMHaltWorker * PMHaltWorker::worker( void ) 2739{ 2740 PMHaltWorker * me; 2741 IOThread thread; 2742 2743 do { 2744 me = OSTypeAlloc( PMHaltWorker ); 2745 if (!me || !me->init()) 2746 break; 2747 2748 me->lock = IOLockAlloc(); 2749 if (!me->lock) 2750 break; 2751 2752 DEBUG_LOG("PMHaltWorker %p\n", me); 2753 me->retain(); // thread holds extra retain 2754 thread = IOCreateThread( &PMHaltWorker::main, me ); 2755 if (!thread) 2756 { 2757 me->release(); 2758 break; 2759 } 2760 return me; 2761 2762 } while (false); 2763 2764 if (me) me->release(); 2765 return 0; 2766} 2767 2768void PMHaltWorker::free( void ) 2769{ 2770 DEBUG_LOG("PMHaltWorker free %p\n", this); 2771 if (lock) 2772 { 2773 IOLockFree(lock); 2774 lock = 0; 2775 } 2776 return OSObject::free(); 2777} 2778 2779void PMHaltWorker::main( void * arg ) 2780{ 2781 PMHaltWorker * me = (PMHaltWorker *) arg; 2782 2783 IOLockLock( gPMHaltLock ); 2784 gPMHaltBusyCount++; 2785 me->depth = gPMHaltDepth; 2786 IOLockUnlock( gPMHaltLock ); 2787 2788 while (me->depth >= 0) 2789 { 2790 PMHaltWorker::work( me ); 2791 2792 IOLockLock( gPMHaltLock ); 2793 if (++gPMHaltIdleCount >= gPMHaltBusyCount) 2794 { 2795 // This is the last thread to finish work on this level, 2796 // inform everyone to start working on next lower level. 2797 gPMHaltDepth--; 2798 me->depth = gPMHaltDepth; 2799 gPMHaltIdleCount = 0; 2800 thread_wakeup((event_t) &gPMHaltIdleCount); 2801 } 2802 else 2803 { 2804 // One or more threads are still working on this level, 2805 // this thread must wait. 2806 me->depth = gPMHaltDepth - 1; 2807 do { 2808 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT); 2809 } while (me->depth != gPMHaltDepth); 2810 } 2811 IOLockUnlock( gPMHaltLock ); 2812 } 2813 2814 // No more work to do, terminate thread 2815 DEBUG_LOG("All done for worker: %p (visits = %u)\n", me, me->visits); 2816 thread_wakeup( &gPMHaltDepth ); 2817 me->release(); 2818} 2819 2820void PMHaltWorker::work( PMHaltWorker * me ) 2821{ 2822 IOService * service; 2823 OSSet * inner; 2824 AbsoluteTime startTime; 2825 UInt32 deltaTime; 2826 bool timeout; 2827 2828 while (true) 2829 { 2830 service = 0; 2831 timeout = false; 2832 2833 // Claim an unit of work from the shared pool 2834 IOLockLock( gPMHaltLock ); 2835 inner = (OSSet *)gPMHaltArray->getObject(me->depth); 2836 if (inner) 2837 { 2838 service = (IOService *)inner->getAnyObject(); 2839 if (service) 2840 { 2841 service->retain(); 2842 inner->removeObject(service); 2843 } 2844 } 2845 IOLockUnlock( gPMHaltLock ); 2846 if (!service) 2847 break; // no more work at this depth 2848 2849 clock_get_uptime(&startTime); 2850 2851 if (!service->isInactive() && 2852 service->setProperty(gPMHaltClientAcknowledgeKey, me)) 2853 { 2854 IOLockLock(me->lock); 2855 me->startTime = startTime; 2856 me->service = service; 2857 me->timeout = false; 2858 IOLockUnlock(me->lock); 2859 2860 service->systemWillShutdown( gPMHaltEvent ); 2861 2862 // Wait for driver acknowledgement 2863 IOLockLock(me->lock); 2864 while (service->getProperty(gPMHaltClientAcknowledgeKey)) 2865 { 2866 IOLockSleep(me->lock, me, THREAD_UNINT); 2867 } 2868 me->service = 0; 2869 timeout = me->timeout; 2870 IOLockUnlock(me->lock); 2871 } 2872 2873 deltaTime = computeDeltaTimeMS(&startTime); 2874 if ((deltaTime > kPMHaltTimeoutMS) || timeout || 2875 (gIOKitDebug & kIOLogDebugPower)) 2876 { 2877 HaltRestartLog("%s driver %s (%p) took %lu ms\n", 2878 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ? 2879 "PowerOff" : "Restart", 2880 service->getName(), service, 2881 deltaTime ); 2882 } 2883 2884 service->release(); 2885 me->visits++; 2886 } 2887} 2888 2889void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now ) 2890{ 2891 UInt64 nano; 2892 AbsoluteTime startTime; 2893 AbsoluteTime endTime; 2894 2895 endTime = *now; 2896 2897 IOLockLock(me->lock); 2898 if (me->service && !me->timeout) 2899 { 2900 startTime = me->startTime; 2901 nano = 0; 2902 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) 2903 { 2904 SUB_ABSOLUTETIME(&endTime, &startTime); 2905 absolutetime_to_nanoseconds(endTime, &nano); 2906 } 2907 if (nano > 3000000000ULL) 2908 { 2909 me->timeout = true; 2910 HaltRestartLog("%s still waiting on %s\n", 2911 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ? 2912 "PowerOff" : "Restart", 2913 me->service->getName()); 2914 } 2915 } 2916 IOLockUnlock(me->lock); 2917} 2918 2919//********************************************************************************* 2920// acknowledgeSystemWillShutdown 2921// 2922// Acknowledgement from drivers that they have prepared for shutdown/restart. 2923//********************************************************************************* 2924 2925void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from ) 2926{ 2927 PMHaltWorker * worker; 2928 OSObject * prop; 2929 2930 if (!from) 2931 return; 2932 2933 //DEBUG_LOG("%s acknowledged\n", from->getName()); 2934 prop = from->copyProperty( gPMHaltClientAcknowledgeKey ); 2935 if (prop) 2936 { 2937 worker = (PMHaltWorker *) prop; 2938 IOLockLock(worker->lock); 2939 from->removeProperty( gPMHaltClientAcknowledgeKey ); 2940 thread_wakeup((event_t) worker); 2941 IOLockUnlock(worker->lock); 2942 worker->release(); 2943 } 2944 else 2945 { 2946 DEBUG_LOG("%s acknowledged without worker property\n", 2947 from->getName()); 2948 } 2949} 2950 2951//********************************************************************************* 2952// notifySystemShutdown 2953// 2954// Notify all objects in PM tree that system will shutdown or restart 2955//********************************************************************************* 2956 2957static void 2958notifySystemShutdown( IOService * root, unsigned long event ) 2959{ 2960#define PLACEHOLDER ((OSSet *)gPMHaltArray) 2961 IORegistryIterator * iter; 2962 IORegistryEntry * entry; 2963 IOService * node; 2964 OSSet * inner; 2965 PMHaltWorker * workers[kPMHaltMaxWorkers]; 2966 AbsoluteTime deadline; 2967 unsigned int totalNodes = 0; 2968 unsigned int depth; 2969 unsigned int rootDepth; 2970 unsigned int numWorkers; 2971 unsigned int count; 2972 int waitResult; 2973 void * baseFunc; 2974 bool ok; 2975 2976 DEBUG_LOG("%s event = %lx\n", __FUNCTION__, event); 2977 2978 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown); 2979 2980 // Iterate the entire PM tree starting from root 2981 2982 rootDepth = root->getDepth( gIOPowerPlane ); 2983 if (!rootDepth) goto done; 2984 2985 // debug - for repeated test runs 2986 while (PMHaltWorker::metaClass->getInstanceCount()) 2987 IOSleep(1); 2988 2989 if (!gPMHaltArray) 2990 { 2991 gPMHaltArray = OSArray::withCapacity(40); 2992 if (!gPMHaltArray) goto done; 2993 } 2994 else // debug 2995 gPMHaltArray->flushCollection(); 2996 2997 if (!gPMHaltLock) 2998 { 2999 gPMHaltLock = IOLockAlloc(); 3000 if (!gPMHaltLock) goto done; 3001 } 3002 3003 if (!gPMHaltClientAcknowledgeKey) 3004 { 3005 gPMHaltClientAcknowledgeKey = 3006 OSSymbol::withCStringNoCopy("PMShutdown"); 3007 if (!gPMHaltClientAcknowledgeKey) goto done; 3008 } 3009 3010 gPMHaltEvent = event; 3011 3012 // Depth-first walk of PM plane 3013 3014 iter = IORegistryIterator::iterateOver( 3015 root, gIOPowerPlane, kIORegistryIterateRecursively); 3016 3017 if (iter) 3018 { 3019 while ((entry = iter->getNextObject())) 3020 { 3021 node = OSDynamicCast(IOService, entry); 3022 if (!node) 3023 continue; 3024 3025 if (baseFunc == 3026 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown)) 3027 continue; 3028 3029 depth = node->getDepth( gIOPowerPlane ); 3030 if (depth <= rootDepth) 3031 continue; 3032 3033 ok = false; 3034 3035 // adjust to zero based depth 3036 depth -= (rootDepth + 1); 3037 3038 // gPMHaltArray is an array of containers, each container 3039 // refers to nodes with the same depth. 3040 3041 count = gPMHaltArray->getCount(); 3042 while (depth >= count) 3043 { 3044 // expand array and insert placeholders 3045 gPMHaltArray->setObject(PLACEHOLDER); 3046 count++; 3047 } 3048 count = gPMHaltArray->getCount(); 3049 if (depth < count) 3050 { 3051 inner = (OSSet *)gPMHaltArray->getObject(depth); 3052 if (inner == PLACEHOLDER) 3053 { 3054 inner = OSSet::withCapacity(40); 3055 if (inner) 3056 { 3057 gPMHaltArray->replaceObject(depth, inner); 3058 inner->release(); 3059 } 3060 } 3061 3062 // PM nodes that appear more than once in the tree will have 3063 // the same depth, OSSet will refuse to add the node twice. 3064 if (inner) 3065 ok = inner->setObject(node); 3066 } 3067 if (!ok) 3068 DEBUG_LOG("Skipped PM node %s\n", node->getName()); 3069 } 3070 iter->release(); 3071 } 3072 3073 // debug only 3074 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++) 3075 { 3076 count = 0; 3077 if (inner != PLACEHOLDER) 3078 count = inner->getCount(); 3079 DEBUG_LOG("Nodes at depth %u = %u\n", i, count); 3080 } 3081 3082 // strip placeholders (not all depths are populated) 3083 numWorkers = 0; 3084 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); ) 3085 { 3086 if (inner == PLACEHOLDER) 3087 { 3088 gPMHaltArray->removeObject(i); 3089 continue; 3090 } 3091 count = inner->getCount(); 3092 if (count > numWorkers) 3093 numWorkers = count; 3094 totalNodes += count; 3095 i++; 3096 } 3097 3098 if (gPMHaltArray->getCount() == 0 || !numWorkers) 3099 goto done; 3100 3101 gPMHaltBusyCount = 0; 3102 gPMHaltIdleCount = 0; 3103 gPMHaltDepth = gPMHaltArray->getCount() - 1; 3104 3105 // Create multiple workers (and threads) 3106 3107 if (numWorkers > kPMHaltMaxWorkers) 3108 numWorkers = kPMHaltMaxWorkers; 3109 3110 DEBUG_LOG("PM nodes = %u, maxDepth = %u, workers = %u\n", 3111 totalNodes, gPMHaltArray->getCount(), numWorkers); 3112 3113 for (unsigned int i = 0; i < numWorkers; i++) 3114 workers[i] = PMHaltWorker::worker(); 3115 3116 // Wait for workers to exhaust all available work 3117 3118 IOLockLock(gPMHaltLock); 3119 while (gPMHaltDepth >= 0) 3120 { 3121 clock_interval_to_deadline(1000, kMillisecondScale, &deadline); 3122 3123 waitResult = IOLockSleepDeadline( 3124 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT); 3125 if (THREAD_TIMED_OUT == waitResult) 3126 { 3127 AbsoluteTime now; 3128 clock_get_uptime(&now); 3129 3130 IOLockUnlock(gPMHaltLock); 3131 for (unsigned int i = 0 ; i < numWorkers; i++) 3132 { 3133 if (workers[i]) 3134 PMHaltWorker::checkTimeout(workers[i], &now); 3135 } 3136 IOLockLock(gPMHaltLock); 3137 } 3138 } 3139 IOLockUnlock(gPMHaltLock); 3140 3141 // Release all workers 3142 3143 for (unsigned int i = 0; i < numWorkers; i++) 3144 { 3145 if (workers[i]) 3146 workers[i]->release(); 3147 // worker also retained by it's own thread 3148 } 3149 3150done: 3151 DEBUG_LOG("%s done\n", __FUNCTION__); 3152 return; 3153} 3154 3155#if DEBUG_TEST 3156// debug - exercise notifySystemShutdown() 3157bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const 3158{ 3159 IOPMrootDomain * root = (IOPMrootDomain *) this; 3160 notifySystemShutdown( root, kIOMessageSystemWillPowerOff ); 3161 return( super::serializeProperties(s) ); 3162} 3163#endif 3164 3165/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 3166 3167 3168 3169#undef super 3170#define super OSObject 3171OSDefineMetaClassAndStructors(PMSettingObject, OSObject) 3172 3173void PMSettingObject::setPMSetting(const OSSymbol *type, OSObject *obj) 3174{ 3175 (*func)(target, type, obj, refcon); 3176} 3177 3178/* 3179 * Static constructor/initializer for PMSettingObject 3180 */ 3181PMSettingObject *PMSettingObject::pmSettingObject( 3182 IOPMrootDomain *parent_arg, 3183 IOPMSettingControllerCallback handler_arg, 3184 OSObject *target_arg, 3185 uintptr_t refcon_arg, 3186 uint32_t supportedPowerSources, 3187 const OSSymbol * settings[]) 3188{ 3189 uint32_t objCount = 0; 3190 PMSettingObject *pmso; 3191 3192 if( !parent_arg || !handler_arg || !settings ) return NULL; 3193 3194 // count OSSymbol entries in NULL terminated settings array 3195 while( settings[objCount] ) { 3196 objCount++; 3197 } 3198 if(0 == objCount) return NULL; 3199 3200 pmso = new PMSettingObject; 3201 if(!pmso || !pmso->init()) return NULL; 3202 3203 pmso->parent = parent_arg; 3204 pmso->func = handler_arg; 3205 pmso->target = target_arg; 3206 pmso->refcon = refcon_arg; 3207 pmso->releaseAtCount = objCount + 1; // release when it has count+1 retains 3208 3209 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount); 3210 if(pmso->publishedFeatureID) { 3211 for(unsigned int i=0; i<objCount; i++) { 3212 // Since there is now at least one listener to this setting, publish 3213 // PM root domain support for it. 3214 parent_arg->publishFeature( settings[i]->getCStringNoCopy(), 3215 supportedPowerSources, &pmso->publishedFeatureID[i] ); 3216 } 3217 } 3218 3219 return pmso; 3220} 3221 3222void PMSettingObject::free(void) 3223{ 3224 OSCollectionIterator *settings_iter; 3225 OSSymbol *sym; 3226 OSArray *arr; 3227 int arr_idx; 3228 int i; 3229 int objCount = releaseAtCount - 1; 3230 3231 if(publishedFeatureID) { 3232 for(i=0; i<objCount; i++) { 3233 if(0 != publishedFeatureID[i]) { 3234 parent->removePublishedFeature( publishedFeatureID[i] ); 3235 } 3236 } 3237 3238 IOFree(publishedFeatureID, sizeof(uint32_t) * objCount); 3239 } 3240 3241 IORecursiveLockLock(parent->settingsCtrlLock); 3242 3243 // Search each PM settings array in the kernel. 3244 settings_iter = OSCollectionIterator::withCollection(parent->settingsCallbacks); 3245 if(settings_iter) 3246 { 3247 while(( sym = OSDynamicCast(OSSymbol, settings_iter->getNextObject()) )) 3248 { 3249 arr = (OSArray *)parent->settingsCallbacks->getObject(sym); 3250 arr_idx = arr->getNextIndexOfObject(this, 0); 3251 if(-1 != arr_idx) { 3252 // 'this' was found in the array; remove it 3253 arr->removeObject(arr_idx); 3254 } 3255 } 3256 3257 settings_iter->release(); 3258 } 3259 3260 IORecursiveLockUnlock(parent->settingsCtrlLock); 3261 3262 super::free(); 3263} 3264 3265void PMSettingObject::taggedRelease(const void *tag, const int when) const 3266{ 3267 // We have n+1 retains - 1 per array that this PMSettingObject is a member 3268 // of, and 1 retain to ourself. When we get a release with n+1 retains 3269 // remaining, we go ahead and free ourselves, cleaning up array pointers 3270 // in free(); 3271 3272 super::taggedRelease(tag, releaseAtCount); 3273} 3274 3275 3276 3277/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 3278 3279#undef super 3280#define super IOService 3281 3282OSDefineMetaClassAndStructors(IORootParent, IOService) 3283 3284// This array exactly parallels the state array for the root domain. 3285// Power state changes initiated by a device can be vetoed by a client of the device, and 3286// power state changes initiated by the parent of a device cannot be vetoed by a client of the device, 3287// so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks 3288// its parent to make the change. That is the reason for this complexity. 3289 3290static IOPMPowerState patriarchPowerStates[number_of_power_states] = { 3291 {1,0,0,0,0,0,0,0,0,0,0,0}, // off 3292 {1,0,RESTART_POWER,0,0,0,0,0,0,0,0,0}, // reset 3293 {1,0,SLEEP_POWER,0,0,0,0,0,0,0,0,0}, // sleep 3294 {1,0,DOZE_POWER,0,0,0,0,0,0,0,0,0}, // doze 3295 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0} // running 3296}; 3297 3298bool IORootParent::start ( IOService * nub ) 3299{ 3300 mostRecentChange = ON_STATE; 3301 super::start(nub); 3302 PMinit(); 3303 youAreRoot(); 3304 registerPowerDriver(this,patriarchPowerStates,number_of_power_states); 3305 wakeSystem(); 3306 powerOverrideOnPriv(); 3307 return true; 3308} 3309 3310 3311void IORootParent::shutDownSystem ( void ) 3312{ 3313 mostRecentChange = OFF_STATE; 3314 changePowerStateToPriv(OFF_STATE); 3315} 3316 3317 3318void IORootParent::restartSystem ( void ) 3319{ 3320 mostRecentChange = RESTART_STATE; 3321 changePowerStateToPriv(RESTART_STATE); 3322} 3323 3324 3325void IORootParent::sleepSystem ( void ) 3326{ 3327 mostRecentChange = SLEEP_STATE; 3328 changePowerStateToPriv(SLEEP_STATE); 3329} 3330 3331 3332void IORootParent::dozeSystem ( void ) 3333{ 3334 mostRecentChange = DOZE_STATE; 3335 changePowerStateToPriv(DOZE_STATE); 3336} 3337 3338// Called in demand sleep when sleep discovered to be impossible after actually attaining that state. 3339// This brings the parent to doze, which allows the root to step up from sleep to doze. 3340 3341// In idle sleep, do nothing because the parent is still on and the root can freely change state. 3342 3343void IORootParent::sleepToDoze ( void ) 3344{ 3345 if ( mostRecentChange == SLEEP_STATE ) { 3346 changePowerStateToPriv(DOZE_STATE); 3347 } 3348} 3349 3350 3351void IORootParent::wakeSystem ( void ) 3352{ 3353 mostRecentChange = ON_STATE; 3354 changePowerStateToPriv(ON_STATE); 3355} 3356 3357IOReturn IORootParent::changePowerStateToPriv ( unsigned long ordinal ) 3358{ 3359 IOReturn ret; 3360 3361 if( (SLEEP_STATE == ordinal) && sleepSupportedPEFunction ) 3362 { 3363 3364 // Determine if the machine supports sleep, or must doze. 3365 ret = getPlatform()->callPlatformFunction( 3366 sleepSupportedPEFunction, false, 3367 NULL, NULL, NULL, NULL); 3368 3369 // If the machine only supports doze, the callPlatformFunction call 3370 // boils down toIOPMrootDomain::setSleepSupported(kPCICantSleep), 3371 // otherwise nothing. 3372 } 3373 3374 return super::changePowerStateToPriv(ordinal); 3375} 3376 3377