2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
44 #include <IOKit/IOHibernatePrivate.h>
46 #include <sys/syslog.h>
47 #include <sys/sysctl.h>
49 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
54 #include "IOPMrootDomainInternal.h"
61 #define DEBUG_LOG(x...) do { kprintf(x); } while (0)
63 #define DEBUG_LOG(x...)
65 #define HaltRestartLog(x...) do { kprintf(x); } while (0)
68 IOReturn
OSMetaClassSystemSleepOrWake( UInt32
);
71 extern const IORegistryPlane
* gIOPowerPlane
;
73 IOReturn
broadcast_aggressiveness ( OSObject
*, void *, void *, void *, void * );
74 static void sleepTimerExpired(thread_call_param_t
);
75 static void wakeupClamshellTimerExpired ( thread_call_param_t us
);
76 static void notifySystemShutdown( IOService
* root
, unsigned long event
);
78 // "IOPMSetSleepSupported" callPlatformFunction name
79 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
81 #define kIOSleepSupportedKey "IOSleepSupported"
83 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
84 | kIOPMSupportedOnBatt \
85 | kIOPMSupportedOnUPS)
87 #define number_of_power_states 5
89 #define RESTART_STATE 1
94 #define ON_POWER kIOPMPowerOn
95 #define RESTART_POWER kIOPMRestart
96 #define SLEEP_POWER kIOPMAuxPowerOn
97 #define DOZE_POWER kIOPMDoze
101 // not idle around autowake time, secs
102 kAutoWakePreWindow
= 45,
103 kAutoWakePostWindow
= 15
107 #define kLocalEvalClamshellCommand (1 << 15)
109 static IOPMPowerState ourPowerStates
[number_of_power_states
] = {
111 {1,0, 0, 0,0,0,0,0,0,0,0,0},
113 {1,kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
,0,0,0,0,0,0,0,0},
115 {1,kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
,0,0,0,0,0,0,0,0},
117 {1,kIOPMDoze
, kIOPMDoze
, DOZE_POWER
,0,0,0,0,0,0,0,0},
119 {1,kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
,0,0,0,0,0,0,0,0},
122 static IOPMrootDomain
* gRootDomain
;
123 static UInt32 gSleepOrShutdownPending
= 0;
125 struct timeval gIOLastSleepTime
;
126 struct timeval gIOLastWakeTime
;
128 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
129 #define kCPUUnknownIndex 9999999
136 class PMSettingObject
: public OSObject
138 OSDeclareDefaultStructors(PMSettingObject
)
140 IOPMrootDomain
*parent
;
141 IOPMSettingControllerCallback func
;
144 uint32_t *publishedFeatureID
;
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
[]);
155 void setPMSetting(const OSSymbol
*type
, OSObject
*obj
);
157 void taggedRelease(const void *tag
, const int when
) const;
162 * Internal helper object for Shutdown/Restart notifications.
164 #define kPMHaltMaxWorkers 8
165 #define kPMHaltTimeoutMS 100
167 class PMHaltWorker
: public OSObject
169 OSDeclareDefaultStructors( PMHaltWorker
)
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)
177 bool timeout
; // service took too long
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 );
186 OSDefineMetaClassAndStructors( PMHaltWorker
, OSObject
)
189 #define super IOService
190 OSDefineMetaClassAndStructors(IOPMrootDomain
,IOService
)
194 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
196 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
199 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
201 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
204 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
206 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
209 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
211 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
214 IOReturn
rootDomainRestart ( void )
216 return gRootDomain
->restartSystem();
219 IOReturn
rootDomainShutdown ( void )
221 return gRootDomain
->shutdownSystem();
224 void IOSystemShutdownNotification ( void )
226 IOCatalogue::disableExternalLinker();
227 for ( int i
= 0; i
< 100; i
++ )
229 if ( OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) ) break;
234 int sync_internal(void);
238 A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain
239 children it has, but within the constraint of the power state provided by its parent. The driver expresses its desire by
240 calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children
241 express their desires by calling requestPowerDomainState().
243 The Root Power Domain owns the policy for idle and demand sleep and doze for the system. It is a power-managed IOService just
244 like the others in the system. It implements several power states which correspond to what we see as Sleep, Doze, etc.
246 The sleep/doze policy is as follows:
247 Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards.
248 Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero.
249 The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep.
251 These three conditions are enforced using the "driver clamp" by calling changePowerStateTo(). For example, if the case is
252 opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or
253 the state of the other clamp.
255 Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item.
256 In this case the root's parent actually initiates the power state change so that the root has no choice and does not give
257 applications the opportunity to veto the change.
259 Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep. When this is true, the root's
260 children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE)
261 to hold itself on until the sleep timer expires. This timer is set for the difference between the sleep timeout slider and
262 the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel. For example, if
263 the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes,
264 when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root
265 sets its timer for 25 minutes (30 - 5). When the timer expires, it releases its clamp and now nothing is holding it awake,
268 Demand sleep is prevented when the system is booting. When preferences are transmitted by the loginwindow at the end of
269 boot, a flag is cleared, and this allows subsequent Demand Sleep.
271 The 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
272 a clamp, but sets a flag which is noticed before actually sleeping the kernel. If the flag is set, the root steps up
273 one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and
274 ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler
278 // **********************************************************************************
280 IOPMrootDomain
* IOPMrootDomain::construct( void )
282 IOPMrootDomain
*root
;
284 root
= new IOPMrootDomain
;
291 // **********************************************************************************
293 static void disk_sync_callout(thread_call_param_t p0
, thread_call_param_t p1
)
295 IOService
*rootDomain
= (IOService
*) p0
;
296 unsigned long pmRef
= (unsigned long) p1
;
298 DEBUG_LOG("disk_sync_callout: start\n");
301 IOHibernateSystemSleep();
304 rootDomain
->allowPowerChange(pmRef
);
305 DEBUG_LOG("disk_sync_callout: finish\n");
308 // **********************************************************************************
310 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
312 AbsoluteTime endTime
;
315 clock_get_uptime(&endTime
);
316 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
318 SUB_ABSOLUTETIME(&endTime
, startTime
);
319 absolutetime_to_nanoseconds(endTime
, &nano
);
322 return (UInt32
)(nano
/ 1000000ULL);
325 // **********************************************************************************
328 // We don't do much here. The real initialization occurs when the platform
329 // expert informs us we are the root.
330 // **********************************************************************************
332 #define kRootDomainSettingsCount 14
334 static SYSCTL_STRUCT(_kern
, OID_AUTO
, sleeptime
,
335 CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
336 &gIOLastSleepTime
, timeval
, "");
338 static SYSCTL_STRUCT(_kern
, OID_AUTO
, waketime
,
339 CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
340 &gIOLastWakeTime
, timeval
, "");
342 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
344 bool IOPMrootDomain::start ( IOService
* nub
)
346 OSIterator
*psIterator
;
347 OSDictionary
*tmpDict
;
349 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
351 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
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
)
370 pmPowerStateQueue
= 0;
372 _reserved
= (ExpansionData
*)IOMalloc(sizeof(ExpansionData
));
373 if(!_reserved
) return false;
381 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
383 setProperty(kIOSleepSupportedKey
,true);
385 userDisabledAllSleep
= false;
387 sleepIsSupported
= true;
388 systemBooting
= true;
390 idleSleepPending
= false;
393 clamshellIsClosed
= false;
394 clamshellExists
= false;
395 ignoringClamshell
= true;
396 ignoringClamshellDuringWakeup
= false;
397 acAdaptorConnect
= true;
399 idxPMCPUClamshell
= kCPUUnknownIndex
;
400 idxPMCPULimitedPower
= kCPUUnknownIndex
;
402 tmpDict
= OSDictionary::withCapacity(1);
403 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
406 settingsCallbacks
= OSDictionary::withCapacity(1);
408 // Create a list of the valid PM settings that we'll relay to
409 // interested clients in setProperties() => setPMSetting()
410 allowedPMSettings
= OSArray::withObjects(
411 (const OSObject
**)settingsArr
,
412 kRootDomainSettingsCount
,
415 fPMSettingsDict
= OSDictionary::withCapacity(5);
417 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(this);
418 getPMworkloop()->addEventSource(pmPowerStateQueue
);
420 featuresDictLock
= IOLockAlloc();
421 settingsCtrlLock
= IORecursiveLockAlloc();
423 extraSleepTimer
= thread_call_allocate(
424 (thread_call_func_t
)sleepTimerExpired
,
425 (thread_call_param_t
) this);
426 clamshellWakeupIgnore
= thread_call_allocate(
427 (thread_call_func_t
)wakeupClamshellTimerExpired
,
428 (thread_call_param_t
) this);
429 diskSyncCalloutEntry
= thread_call_allocate(
431 (thread_call_param_t
) this);
434 patriarch
= new IORootParent
;
436 patriarch
->attach(this);
437 patriarch
->start(this);
438 patriarch
->addPowerChild(this);
440 registerPowerDriver(this,ourPowerStates
,number_of_power_states
);
442 setPMRootDomain(this);
443 // set a clamp until we sleep
444 changePowerStateToPriv(ON_STATE
);
446 // install power change handler
447 registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
450 // Register for a notification when IODisplayWrangler is published
451 _displayWranglerNotifier
= addNotification(
452 gIOPublishNotification
, serviceMatching("IODisplayWrangler"),
453 &displayWranglerPublished
, this, 0);
456 // Battery location published - ApplePMU support only
457 _batteryPublishNotifier
= addNotification(
458 gIOPublishNotification
, serviceMatching("IOPMPowerSource"),
459 &batteryPublished
, this, this);
462 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
463 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
464 ucClassName
->release();
466 // IOBacklightDisplay can take a long time to load at boot, or it may
467 // not load at all if you're booting with clamshell closed. We publish
468 // 'DisplayDims' here redundantly to get it published early and at all.
469 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
470 if( psIterator
&& psIterator
->getNextObject() )
472 // There's at least one battery on the system, so we publish
473 // 'DisplayDims' support for the LCD.
474 publishFeature("DisplayDims");
477 psIterator
->release();
481 sysctl_register_oid(&sysctl__kern_sleeptime
);
482 sysctl_register_oid(&sysctl__kern_waketime
);
485 IOHibernateSystemInit(this);
488 registerService(); // let clients find us
493 // **********************************************************************************
496 // Receive a setProperty call
497 // The "System Boot" property means the system is completely booted.
498 // **********************************************************************************
499 IOReturn
IOPMrootDomain::setProperties ( OSObject
*props_obj
)
501 IOReturn return_value
= kIOReturnSuccess
;
502 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
510 const OSSymbol
*boot_complete_string
=
511 OSSymbol::withCString("System Boot Complete");
512 const OSSymbol
*sys_shutdown_string
=
513 OSSymbol::withCString("System Shutdown");
514 const OSSymbol
*stall_halt_string
=
515 OSSymbol::withCString("StallSystemAtHalt");
516 const OSSymbol
*battery_warning_disabled_string
=
517 OSSymbol::withCString("BatteryWarningsDisabled");
518 const OSSymbol
*idle_seconds_string
=
519 OSSymbol::withCString("System Idle Seconds");
521 const OSSymbol
*hibernatemode_string
=
522 OSSymbol::withCString(kIOHibernateModeKey
);
523 const OSSymbol
*hibernatefile_string
=
524 OSSymbol::withCString(kIOHibernateFileKey
);
525 const OSSymbol
*hibernatefreeratio_string
=
526 OSSymbol::withCString(kIOHibernateFreeRatioKey
);
527 const OSSymbol
*hibernatefreetime_string
=
528 OSSymbol::withCString(kIOHibernateFreeTimeKey
);
530 const OSSymbol
*sleepdisabled_string
=
531 OSSymbol::withCString("SleepDisabled");
535 return_value
= kIOReturnBadArgument
;
539 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(idle_seconds_string
))))
541 setProperty(idle_seconds_string
, n
);
542 idleSeconds
= n
->unsigned32BitValue();
546 && boot_complete_string
547 && dict
->getObject(boot_complete_string
))
549 systemBooting
= false;
552 // If lid is closed, re-send lid closed notification
553 // now that booting is complete.
554 if( clamshellIsClosed
)
556 this->receivePowerNotification(kLocalEvalClamshellCommand
);
560 if( battery_warning_disabled_string
561 && dict
->getObject(battery_warning_disabled_string
))
563 setProperty( battery_warning_disabled_string
,
564 dict
->getObject(battery_warning_disabled_string
));
567 if( sys_shutdown_string
568 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sys_shutdown_string
))))
571 if(kOSBooleanTrue
== b
)
573 /* We set systemShutdown = true during shutdown
574 to prevent sleep at unexpected times while loginwindow is trying
575 to shutdown apps and while the OS is trying to transition to
578 Set to true during shutdown, as soon as loginwindow shows
579 the "shutdown countdown dialog", through individual app
580 termination, and through black screen kernel shutdown.
582 kprintf("systemShutdown true\n");
583 systemShutdown
= true;
586 A shutdown was initiated, but then the shutdown
587 was cancelled, clearing systemShutdown to false here.
589 kprintf("systemShutdown false\n");
590 systemShutdown
= false;
594 if( stall_halt_string
595 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(stall_halt_string
))) )
597 setProperty(stall_halt_string
, b
);
601 if ( hibernatemode_string
602 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatemode_string
))))
604 setProperty(hibernatemode_string
, n
);
606 if ( hibernatefreeratio_string
607 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreeratio_string
))))
609 setProperty(hibernatefreeratio_string
, n
);
611 if ( hibernatefreetime_string
612 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreetime_string
))))
614 setProperty(hibernatefreetime_string
, n
);
616 if ( hibernatefile_string
617 && (str
= OSDynamicCast(OSString
, dict
->getObject(hibernatefile_string
))))
619 setProperty(hibernatefile_string
, str
);
623 if( sleepdisabled_string
624 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sleepdisabled_string
))) )
626 setProperty(sleepdisabled_string
, b
);
628 userDisabledAllSleep
= (kOSBooleanTrue
== b
);
631 // Relay our allowed PM settings onto our registered PM clients
632 for(i
= 0; i
< allowedPMSettings
->getCount(); i
++) {
634 type
= (OSSymbol
*)allowedPMSettings
->getObject(i
);
637 obj
= dict
->getObject(type
);
640 if ((gIOPMSettingAutoWakeSecondsKey
== type
) && ((n
= OSDynamicCast(OSNumber
, obj
))))
642 UInt32 rsecs
= n
->unsigned32BitValue();
644 autoWakeStart
= autoWakeEnd
= 0;
647 AbsoluteTime deadline
;
648 clock_interval_to_deadline(rsecs
+ kAutoWakePostWindow
, kSecondScale
, &deadline
);
649 autoWakeEnd
= AbsoluteTime_to_scalar(&deadline
);
650 if (rsecs
> kAutoWakePreWindow
)
651 rsecs
-= kAutoWakePreWindow
;
654 clock_interval_to_deadline(rsecs
, kSecondScale
, &deadline
);
655 autoWakeStart
= AbsoluteTime_to_scalar(&deadline
);
659 return_value
= setPMSetting(type
, obj
);
661 if(kIOReturnSuccess
!= return_value
) goto exit
;
665 if(sleepdisabled_string
) sleepdisabled_string
->release();
666 if(boot_complete_string
) boot_complete_string
->release();
667 if(stall_halt_string
) stall_halt_string
->release();
668 if(idle_seconds_string
) idle_seconds_string
->release();
673 //*********************************************************************************
676 // Power Managment is informing us that we are the root power domain.
677 // We know we are not the root however, since we have just instantiated a parent
678 // for ourselves and made it the root. We override this method so it will have
680 //*********************************************************************************
681 IOReturn
IOPMrootDomain::youAreRoot ( void )
686 // **********************************************************************************
690 // **********************************************************************************
691 void IOPMrootDomain::command_received ( void * w
, void * x
, void * y
, void * z
)
693 super::command_received(w
,x
,y
,z
);
697 // **********************************************************************************
698 // broadcast_aggressiveness
700 // **********************************************************************************
701 IOReturn
broadcast_aggressiveness ( OSObject
* root
, void * x
, void * y
, void *, void * )
703 ((IOPMrootDomain
*)root
)->broadcast_it((unsigned long)x
,(unsigned long)y
);
708 // **********************************************************************************
711 // We are behind the command gate to broadcast an aggressiveness factor. We let the
712 // superclass do it, but we need to snoop on factors that affect idle sleep.
713 // **********************************************************************************
714 void IOPMrootDomain::broadcast_it (unsigned long type
, unsigned long value
)
716 super::setAggressiveness(type
,value
);
718 // Save user's spin down timer to restore after we replace it for idle sleep
719 if( type
== kPMMinutesToSpinDown
) user_spindown
= value
;
721 // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer
722 if (getAggressiveness(kPMMinutesToDim
, (unsigned long *)&longestNonSleepSlider
)
724 longestNonSleepSlider
= 0;
726 if ( type
== kPMMinutesToSleep
) {
727 DEBUG_LOG("PM idle time -> %ld secs (ena %d)\n", idleSeconds
, (value
!= 0));
728 if (0x7fffffff == value
)
731 if ( (sleepSlider
== 0) && (value
!= 0) ) {
735 changePowerStateToPriv(ON_STATE
);
738 AbsoluteTime deadline
;
739 // stay awake for at least idleSeconds
740 clock_interval_to_deadline(idleSeconds
, kSecondScale
, &deadline
);
741 thread_call_enter_delayed(extraSleepTimer
, deadline
);
742 // this gets turned off when we sleep again
743 idleSleepPending
= true;
748 // If sleepASAP is already set, then calling adjustPowerState() here
749 // will put the system to sleep immediately which is bad. Note that
750 // this aggressiveness change can occur without waking up the display
751 // by (dis)connecting the AC adapter. To get around this, the power
752 // clamp is restore to ON state then dropped after waiting for the
753 // sleep timer to expire.
757 AbsoluteTime deadline
;
758 // stay awake for at least sleepSlider minutes
759 clock_interval_to_deadline(value
* 60, kSecondScale
, &deadline
);
760 thread_call_enter_delayed(extraSleepTimer
, deadline
);
761 // this gets turned off when we sleep again
762 idleSleepPending
= true;
768 if ( sleepSlider
== 0 ) {
769 // idle sleep is now disabled
771 // make sure we're powered
772 patriarch
->wakeSystem();
775 if ( sleepSlider
> longestNonSleepSlider
) {
776 extraSleepDelay
= sleepSlider
- longestNonSleepSlider
;
784 // **********************************************************************************
787 // **********************************************************************************
788 static void sleepTimerExpired ( thread_call_param_t us
)
790 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
794 static void wakeupClamshellTimerExpired ( thread_call_param_t us
)
796 ((IOPMrootDomain
*)us
)->stopIgnoringClamshellEventsDuringWakeup();
800 // **********************************************************************************
801 // handleSleepTimerExpiration
803 // The time between the sleep idle timeout and the next longest one has elapsed.
804 // It's time to sleep. Start that by removing the clamp that's holding us awake.
805 // **********************************************************************************
806 void IOPMrootDomain::handleSleepTimerExpiration ( void )
808 DEBUG_LOG("SleepTimerExpired\n");
812 clock_get_uptime(&time
);
813 if ((AbsoluteTime_to_scalar(&time
) > autoWakeStart
) && (AbsoluteTime_to_scalar(&time
) < autoWakeEnd
))
815 thread_call_enter_delayed(extraSleepTimer
, *((AbsoluteTime
*) &autoWakeEnd
));
819 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
820 if(0 != user_spindown
)
821 setQuickSpinDownTimeout();
828 void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void)
830 // Allow clamshell-induced sleep now
831 ignoringClamshellDuringWakeup
= false;
833 // Re-send clamshell event, in case it causes a sleep
834 if(clamshellIsClosed
)
835 this->receivePowerNotification( kLocalEvalClamshellCommand
);
838 //*********************************************************************************
841 // Some aggressiveness factor has changed. We broadcast it to the hierarchy while on
842 // the Power Mangement workloop thread. This enables objects in the
843 // hierarchy to successfully alter their idle timers, which are all on the
845 //*********************************************************************************
847 IOReturn
IOPMrootDomain::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
849 IOWorkLoop
* pmWorkLoop
= getPMworkloop();
851 pmWorkLoop
->runAction(broadcast_aggressiveness
,this,(void *)type
,(void *)newLevel
);
853 return kIOReturnSuccess
;
857 // **********************************************************************************
860 // **********************************************************************************
862 IOReturn
IOPMrootDomain::sleepSystem ( void )
864 return sleepSystemOptions (NULL
);
868 IOReturn
IOPMrootDomain::sleepSystemOptions ( OSDictionary
*options
)
870 /* sleepSystem is a public function, and may be called by any kernel driver.
871 * And that's bad - drivers should sleep the system by calling
872 * receivePowerNotification() instead. Drivers should not use sleepSystem.
874 * Note that user space app calls to IOPMSleepSystem() will also travel
875 * this code path and thus be correctly identified as software sleeps.
878 if (options
&& options
->getObject("OSSwitch"))
881 // Log specific sleep cause for OS Switch hibernation
882 return privateSleepSystem( kIOPMOSSwitchHibernationKey
) ;
886 return privateSleepSystem( kIOPMSoftwareSleepKey
);
892 IOReturn
IOPMrootDomain::privateSleepSystem ( const char *sleepReason
)
894 // Record sleep cause in IORegistry
896 setProperty(kRootDomainSleepReasonKey
, sleepReason
);
900 kprintf("Preventing system sleep on grounds of systemShutdown.\n");
903 if( userDisabledAllSleep
)
905 /* Prevent sleep of all kinds if directed to by user space */
906 return kIOReturnNotPermitted
;
913 if ( !sleepIsSupported
) {
914 setSleepSupported( kPCICantSleep
);
915 kprintf("Sleep prevented by kIOPMPreventSystemSleep flag\n");
917 patriarch
->sleepSystem();
918 return kIOReturnSuccess
;
920 // Unable to sleep because system is in the process of booting or shutting down,
921 // or sleep has otherwise been disallowed.
922 return kIOReturnError
;
927 // **********************************************************************************
930 // **********************************************************************************
931 IOReturn
IOPMrootDomain::shutdownSystem ( void )
933 //patriarch->shutDownSystem();
934 return kIOReturnUnsupported
;
938 // **********************************************************************************
941 // **********************************************************************************
942 IOReturn
IOPMrootDomain::restartSystem ( void )
944 //patriarch->restartSystem();
945 return kIOReturnUnsupported
;
949 // **********************************************************************************
952 // This overrides powerChangeDone in IOService.
954 // Finder sleep and idle sleep move us from the ON state to the SLEEP_STATE.
956 // If we just finished going to the SLEEP_STATE, and the platform is capable of true sleep,
957 // sleep the kernel. Otherwise switch up to the DOZE_STATE which will keep almost
958 // everything as off as it can get.
960 // **********************************************************************************
961 void IOPMrootDomain::powerChangeDone ( unsigned long previousState
)
963 OSNumber
* propertyPtr
;
964 unsigned short theProperty
;
965 AbsoluteTime deadline
;
967 DEBUG_LOG("PowerChangeDone: %ld -> %ld\n", previousState
, getPowerState());
969 switch ( getPowerState() ) {
971 if ( previousState
!= ON_STATE
)
974 if ( canSleep
&& sleepIsSupported
)
976 // re-enable this timer for next sleep
977 idleSleepPending
= false;
979 uint32_t secs
, microsecs
;
980 clock_get_calendar_microtime(&secs
, µsecs
);
982 gIOLastSleepTime
.tv_sec
= secs
;
983 gIOLastSleepTime
.tv_usec
= microsecs
;
986 IOLog("System %sSleep\n", gIOHibernateState
? "Safe" : "");
988 IOHibernateSystemHasSlept();
990 IOLog("System Sleep\n");
993 getPlatform()->sleepKernel();
995 // The CPU(s) are off at this point. When they're awakened by CPU interrupt,
996 // code will resume execution here.
998 // Now we're waking...
1000 IOHibernateSystemWake();
1003 // stay awake for at least 30 seconds
1004 clock_interval_to_deadline(30, kSecondScale
, &deadline
);
1005 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1006 // this gets turned off when we sleep again
1007 idleSleepPending
= true;
1009 // Ignore closed clamshell during wakeup and for a few seconds
1010 // after wakeup is complete
1011 ignoringClamshellDuringWakeup
= true;
1013 // sleep transition complete
1014 gSleepOrShutdownPending
= 0;
1016 // trip the reset of the calendar clock
1017 clock_wakeup_calendar();
1019 // get us some power
1020 patriarch
->wakeSystem();
1022 // early stage wake notification
1023 tellClients(kIOMessageSystemWillPowerOn
);
1025 // tell the tree we're waking
1027 IOLog("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
1031 // Allow drivers to request extra processing time before clamshell
1032 // sleep if kIOREMSleepEnabledKey is present.
1033 // Ignore clamshell events for at least 5 seconds
1034 if(getProperty(kIOREMSleepEnabledKey
)) {
1035 // clamshellWakeupIgnore callout clears ignoreClamshellDuringWakeup bit
1036 clock_interval_to_deadline(5, kSecondScale
, &deadline
);
1037 if(clamshellWakeupIgnore
) {
1038 thread_call_enter_delayed(clamshellWakeupIgnore
, deadline
);
1040 } else ignoringClamshellDuringWakeup
= false;
1042 // Find out what woke us
1043 propertyPtr
= OSDynamicCast(OSNumber
,getProperty("WakeEvent"));
1044 if ( propertyPtr
) {
1045 theProperty
= propertyPtr
->unsigned16BitValue();
1046 IOLog("Wake event %04x\n",theProperty
);
1047 if ( (theProperty
& 0x0008) || //lid
1048 (theProperty
& 0x0800) || // front panel button
1049 (theProperty
& 0x0020) || // external keyboard
1050 (theProperty
& 0x0001) ) { // internal keyboard
1051 // We've identified the wakeup event as UI driven
1055 // Since we can't identify the wakeup event, treat it as UI activity
1059 // Wake for thirty seconds
1060 changePowerStateToPriv(ON_STATE
);
1062 // allow us to step up a power state
1063 patriarch
->sleepToDoze();
1065 // ignore children's request for higher power during doze.
1066 powerOverrideOnPriv();
1067 changePowerStateToPriv(DOZE_STATE
);
1072 if ( previousState
!= DOZE_STATE
)
1074 IOLog("System Doze\n");
1076 // re-enable this timer for next sleep
1077 idleSleepPending
= false;
1078 gSleepOrShutdownPending
= 0;
1082 IOLog("System Restart\n");
1083 PEHaltRestart(kPERestartCPU
);
1087 IOLog("System Halt\n");
1088 PEHaltRestart(kPEHaltCPU
);
1094 // **********************************************************************************
1097 // The Display Wrangler calls here when it switches to its highest state. If the
1098 // system is currently dozing, allow it to wake by making sure the parent is
1100 // **********************************************************************************
1101 void IOPMrootDomain::wakeFromDoze( void )
1103 if ( getPowerState() == DOZE_STATE
)
1105 // Reset sleep support till next sleep attempt.
1106 // A machine's support of sleep vs. doze can change over the course of
1107 // a running system, so we recalculate it before every sleep.
1108 setSleepSupported(0);
1110 changePowerStateToPriv(ON_STATE
);
1111 powerOverrideOffPriv();
1113 // early wake notification
1114 tellClients(kIOMessageSystemWillPowerOn
);
1116 // allow us to wake if children so desire
1117 patriarch
->wakeSystem();
1122 // *****************************************************************************
1125 // Adds a new feature to the supported features dictionary
1128 // *****************************************************************************
1129 void IOPMrootDomain::publishFeature( const char * feature
)
1131 publishFeature(feature
, kIOPMSupportedOnAC
1132 | kIOPMSupportedOnBatt
1133 | kIOPMSupportedOnUPS
,
1139 // *****************************************************************************
1140 // publishFeature (with supported power source specified)
1142 // Adds a new feature to the supported features dictionary
1145 // *****************************************************************************
1146 void IOPMrootDomain::publishFeature(
1147 const char *feature
,
1148 uint32_t supportedWhere
,
1149 uint32_t *uniqueFeatureID
)
1151 static uint16_t next_feature_id
= 500;
1153 OSNumber
*new_feature_data
= NULL
;
1154 OSNumber
*existing_feature
= NULL
;
1155 OSArray
*existing_feature_arr
= NULL
;
1156 OSObject
*osObj
= NULL
;
1157 uint32_t feature_value
= 0;
1159 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
1161 // kprintf("IOPMrootDomain::publishFeature [\"%s\":%0x01x]\n", feature, supportedWhere);
1163 if(!supportedWhere
) {
1164 // Feature isn't supported anywhere!
1168 if(next_feature_id
> 5000) {
1169 // Far, far too many features!
1173 if(featuresDictLock
) IOLockLock(featuresDictLock
);
1175 OSDictionary
*features
=
1176 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
1178 // Create new features dict if necessary
1179 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
1180 features
= OSDictionary::withDictionary(features
);
1182 features
= OSDictionary::withCapacity(1);
1185 // Create OSNumber to track new feature
1187 next_feature_id
+= 1;
1188 if( uniqueFeatureID
) {
1189 // We don't really mind if the calling kext didn't give us a place
1190 // to stash their unique id. Many kexts don't plan to unload, and thus
1191 // have no need to remove themselves later.
1192 *uniqueFeatureID
= next_feature_id
;
1195 feature_value
= supportedWhere
+ (next_feature_id
<< 16);
1196 new_feature_data
= OSNumber::withNumber(
1197 (unsigned long long)feature_value
, 32);
1199 // Does features object already exist?
1200 if( (osObj
= features
->getObject(feature
)) )
1202 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
1204 // We need to create an OSArray to hold the now 2 elements.
1205 existing_feature_arr
= OSArray::withObjects(
1206 (const OSObject
**)&existing_feature
, 1, 2);
1207 existing_feature_arr
->setObject(new_feature_data
);
1208 features
->setObject(feature
, existing_feature_arr
);
1209 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
1211 // Add object to existing array
1212 existing_feature_arr
->setObject(new_feature_data
);
1215 // The easy case: no previously existing features listed. We simply
1216 // set the OSNumber at key 'feature' and we're on our way.
1217 features
->setObject(feature
, new_feature_data
);
1220 new_feature_data
->release();
1222 setProperty(kRootDomainSupportedFeatures
, features
);
1224 features
->release();
1226 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
1228 // Notify EnergySaver and all those in user space so they might
1229 // re-populate their feature specific UI
1230 if(pmPowerStateQueue
) {
1231 pmPowerStateQueue
->featureChangeOccurred(
1232 kIOPMMessageFeatureChange
, this);
1236 // *****************************************************************************
1237 // removePublishedFeature
1239 // Removes previously published feature
1242 // *****************************************************************************
1243 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
1245 IOReturn ret
= kIOReturnError
;
1246 uint32_t feature_value
= 0;
1247 uint16_t feature_id
= 0;
1248 bool madeAChange
= false;
1250 OSSymbol
*dictKey
= NULL
;
1251 OSCollectionIterator
*dictIterator
= NULL
;
1252 OSArray
*arrayMember
= NULL
;
1253 OSNumber
*numberMember
= NULL
;
1254 OSObject
*osObj
= NULL
;
1255 OSNumber
*osNum
= NULL
;
1257 if(featuresDictLock
) IOLockLock(featuresDictLock
);
1259 OSDictionary
*features
=
1260 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
1262 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
1264 // Any modifications to the dictionary are made to the copy to prevent
1265 // races & crashes with userland clients. Dictionary updated
1266 // automically later.
1267 features
= OSDictionary::withDictionary(features
);
1270 ret
= kIOReturnNotFound
;
1274 // We iterate 'features' dictionary looking for an entry tagged
1275 // with 'removeFeatureID'. If found, we remove it from our tracking
1276 // structures and notify the OS via a general interest message.
1278 dictIterator
= OSCollectionIterator::withCollection(features
);
1283 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
1285 osObj
= features
->getObject(dictKey
);
1287 // Each Feature is either tracked by an OSNumber
1288 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
1290 feature_value
= numberMember
->unsigned32BitValue();
1291 feature_id
= (uint16_t)(feature_value
>> 16);
1293 if( feature_id
== (uint16_t)removeFeatureID
)
1296 features
->removeObject(dictKey
);
1301 // Or tracked by an OSArray of OSNumbers
1302 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
1304 unsigned int arrayCount
= arrayMember
->getCount();
1306 for(unsigned int i
=0; i
<arrayCount
; i
++)
1308 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
1313 feature_value
= osNum
->unsigned32BitValue();
1314 feature_id
= (uint16_t)(feature_value
>> 16);
1316 if( feature_id
== (uint16_t)removeFeatureID
)
1319 if( 1 == arrayCount
) {
1320 // If the array only contains one element, remove
1322 features
->removeObject(dictKey
);
1324 // Otherwise just remove the element in question.
1325 arrayMember
->removeObject(i
);
1336 dictIterator
->release();
1340 ret
= kIOReturnSuccess
;
1342 setProperty(kRootDomainSupportedFeatures
, features
);
1344 // Notify EnergySaver and all those in user space so they might
1345 // re-populate their feature specific UI
1346 if(pmPowerStateQueue
) {
1347 pmPowerStateQueue
->featureChangeOccurred(
1348 kIOPMMessageFeatureChange
, this);
1351 ret
= kIOReturnNotFound
;
1355 if(features
) features
->release();
1356 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
1361 // **********************************************************************************
1364 // Enqueues unidle event to be performed later in a serialized context.
1366 // **********************************************************************************
1367 void IOPMrootDomain::unIdleDevice( IOService
*theDevice
, unsigned long theState
)
1369 if(pmPowerStateQueue
)
1370 pmPowerStateQueue
->unIdleOccurred(theDevice
, theState
);
1373 // **********************************************************************************
1374 // announcePowerSourceChange
1376 // Notifies "interested parties" that the batteries have changed state
1378 // **********************************************************************************
1379 void IOPMrootDomain::announcePowerSourceChange( void )
1381 IORegistryEntry
*_batteryRegEntry
= (IORegistryEntry
*) getProperty("BatteryEntry");
1383 // (if possible) re-publish power source state under IOPMrootDomain;
1384 // only do so if the battery controller publishes an IOResource
1385 // defining battery location. Called from ApplePMU battery driver.
1387 if(_batteryRegEntry
)
1390 batt_info
= (OSArray
*) _batteryRegEntry
->getProperty(kIOBatteryInfoKey
);
1392 setProperty(kIOBatteryInfoKey
, batt_info
);
1398 // *****************************************************************************
1399 // setPMSetting (private)
1401 // Internal helper to relay PM settings changes from user space to individual
1402 // drivers. Should be called only by IOPMrootDomain::setProperties.
1404 // *****************************************************************************
1405 IOReturn
IOPMrootDomain::setPMSetting(
1406 const OSSymbol
*type
,
1409 OSArray
*arr
= NULL
;
1410 PMSettingObject
*p_obj
= NULL
;
1414 if(NULL
== type
) return kIOReturnBadArgument
;
1416 IORecursiveLockLock(settingsCtrlLock
);
1418 fPMSettingsDict
->setObject(type
, obj
);
1420 arr
= (OSArray
*)settingsCallbacks
->getObject(type
);
1421 if(NULL
== arr
) goto exit
;
1422 count
= arr
->getCount();
1423 for(i
=0; i
<count
; i
++) {
1424 p_obj
= (PMSettingObject
*)OSDynamicCast(PMSettingObject
, arr
->getObject(i
));
1425 if(p_obj
) p_obj
->setPMSetting(type
, obj
);
1429 IORecursiveLockUnlock(settingsCtrlLock
);
1430 return kIOReturnSuccess
;
1433 // *****************************************************************************
1434 // copyPMSetting (public)
1436 // Allows kexts to safely read setting values, without being subscribed to
1439 // *****************************************************************************
1440 OSObject
* IOPMrootDomain::copyPMSetting(
1441 OSSymbol
*whichSetting
)
1443 OSObject
*obj
= NULL
;
1445 if(!whichSetting
) return NULL
;
1447 IORecursiveLockLock(settingsCtrlLock
);
1448 obj
= fPMSettingsDict
->getObject(whichSetting
);
1452 IORecursiveLockUnlock(settingsCtrlLock
);
1457 // *****************************************************************************
1458 // registerPMSettingController (public)
1460 // direct wrapper to registerPMSettingController with uint32_t power source arg
1461 // *****************************************************************************
1462 IOReturn
IOPMrootDomain::registerPMSettingController(
1463 const OSSymbol
* settings
[],
1464 IOPMSettingControllerCallback func
,
1469 return registerPMSettingController(
1471 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
1472 func
, target
, refcon
, handle
);
1475 // *****************************************************************************
1476 // registerPMSettingController (public)
1478 // Kexts may register for notifications when a particular setting is changed.
1479 // A list of settings is available in IOPM.h.
1481 // * settings - An OSArray containing OSSymbols. Caller should populate this
1482 // array with a list of settings caller wants notifications from.
1483 // * func - A C function callback of the type IOPMSettingControllerCallback
1484 // * target - caller may provide an OSObject *, which PM will pass as an
1485 // target to calls to "func"
1486 // * refcon - caller may provide an void *, which PM will pass as an
1487 // argument to calls to "func"
1488 // * handle - This is a return argument. We will populate this pointer upon
1489 // call success. Hold onto this and pass this argument to
1490 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
1492 // kIOReturnSuccess on success
1493 // *****************************************************************************
1494 IOReturn
IOPMrootDomain::registerPMSettingController(
1495 const OSSymbol
* settings
[],
1496 uint32_t supportedPowerSources
,
1497 IOPMSettingControllerCallback func
,
1502 PMSettingObject
*pmso
= NULL
;
1503 OSArray
*list
= NULL
;
1504 IOReturn ret
= kIOReturnSuccess
;
1507 if( NULL
== settings
||
1511 return kIOReturnBadArgument
;
1514 pmso
= PMSettingObject::pmSettingObject(
1515 (IOPMrootDomain
*)this, func
, target
,
1516 refcon
, supportedPowerSources
, settings
);
1519 ret
= kIOReturnInternalError
;
1520 goto bail_no_unlock
;
1523 IORecursiveLockLock(settingsCtrlLock
);
1524 for(i
=0; settings
[i
]; i
++)
1526 list
= (OSArray
*)settingsCallbacks
->getObject(settings
[i
]);
1528 // New array of callbacks for this setting
1529 list
= OSArray::withCapacity(1);
1530 settingsCallbacks
->setObject(settings
[i
], list
);
1534 // Add caller to the callback list
1535 list
->setObject(pmso
);
1538 IORecursiveLockUnlock(settingsCtrlLock
);
1540 ret
= kIOReturnSuccess
;
1542 // Track this instance by its OSData ptr from now on
1546 if(kIOReturnSuccess
!= ret
)
1548 // Error return case
1549 if(pmso
) pmso
->release();
1550 if(handle
) *handle
= NULL
;
1556 //******************************************************************************
1557 // sleepOnClamshellClosed
1559 // contains the logic to determine if the system should sleep when the clamshell
1561 //******************************************************************************
1563 bool IOPMrootDomain::shouldSleepOnClamshellClosed ( void )
1565 return ( !ignoringClamshell
1566 && !ignoringClamshellDuringWakeup
1567 && !(desktopMode
&& acAdaptorConnect
) );
1570 void IOPMrootDomain::sendClientClamshellNotification ( void )
1572 /* Only broadcast clamshell alert if clamshell exists. */
1573 if(!clamshellExists
)
1576 setProperty(kAppleClamshellStateKey
,
1577 clamshellIsClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
1579 setProperty(kAppleClamshellCausesSleepKey
,
1580 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
1583 /* Argument to message is a bitfiel of
1584 * ( kClamshellStateBit | kClamshellSleepBit )
1586 messageClients(kIOPMMessageClamshellStateChange
,
1587 (void *) ( (clamshellIsClosed
? kClamshellStateBit
: 0)
1588 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
1591 //******************************************************************************
1592 // informCPUStateChange
1594 // Call into PM CPU code so that CPU power savings may dynamically adjust for
1595 // running on battery, with the lid closed, etc.
1597 // informCPUStateChange is a no-op on non x86 systems
1598 // only x86 has explicit support in the IntelCPUPowerManagement kext
1599 //******************************************************************************
1601 void IOPMrootDomain::informCPUStateChange(
1607 pmioctlVariableInfo_t varInfoStruct
;
1609 const char *varNameStr
= NULL
;
1610 int32_t *varIndex
= NULL
;
1612 if (kInformAC
== type
) {
1613 varNameStr
= kIOPMRootDomainBatPowerCString
;
1614 varIndex
= &idxPMCPULimitedPower
;
1615 } else if (kInformLid
== type
) {
1616 varNameStr
= kIOPMRootDomainLidCloseCString
;
1617 varIndex
= &idxPMCPUClamshell
;
1622 // Set the new value!
1623 // pmCPUControl will assign us a new ID if one doesn't exist yet
1624 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
1625 varInfoStruct
.varID
= *varIndex
;
1626 varInfoStruct
.varType
= vBool
;
1627 varInfoStruct
.varInitValue
= value
;
1628 varInfoStruct
.varCurValue
= value
;
1629 strncpy( (char *)varInfoStruct
.varName
,
1630 (const char *)varNameStr
,
1631 strlen(varNameStr
) + 1 );
1634 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
1636 // pmCPU only assigns numerical id's when a new varName is specified
1638 && (*varIndex
== kCPUUnknownIndex
))
1640 // pmCPUControl has assigned us a new variable ID.
1641 // Let's re-read the structure we just SET to learn that ID.
1642 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
1646 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
1647 *varIndex
= varInfoStruct
.varID
;
1657 //******************************************************************************
1658 // receivePowerNotification
1660 // The power controller is notifying us of a hardware-related power management
1661 // event that we must handle. This is a result of an 'environment' interrupt from
1662 // the power mgt micro.
1663 //******************************************************************************
1665 IOReturn
IOPMrootDomain::receivePowerNotification (UInt32 msg
)
1667 bool eval_clamshell
= false;
1670 * Local (IOPMrootDomain only) eval clamshell command
1672 if (msg
& kLocalEvalClamshellCommand
)
1674 eval_clamshell
= true;
1680 if (msg
& kIOPMOverTemp
)
1682 IOLog("PowerManagement emergency overtemp signal. Going to sleep!");
1684 privateSleepSystem (kIOPMThermalEmergencySleepKey
);
1688 * PMU Processor Speed Change
1690 if (msg
& kIOPMProcessorSpeedChange
)
1692 IOService
*pmu
= waitForService(serviceMatching("ApplePMU"));
1693 pmu
->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
1694 getPlatform()->sleepKernel();
1695 pmu
->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
1701 if (msg
& kIOPMSleepNow
)
1703 privateSleepSystem (kIOPMSoftwareSleepKey
);
1709 if (msg
& kIOPMPowerEmergency
)
1711 privateSleepSystem (kIOPMLowPowerSleepKey
);
1718 if (msg
& kIOPMClamshellOpened
)
1720 // Received clamshel open message from clamshell controlling driver
1721 // Update our internal state and tell general interest clients
1722 clamshellIsClosed
= false;
1723 clamshellExists
= true;
1726 informCPUStateChange(kInformLid
, 0);
1728 // Tell general interest clients
1729 sendClientClamshellNotification();
1734 * Send the clamshell interest notification since the lid is closing.
1736 if (msg
& kIOPMClamshellClosed
)
1738 // Received clamshel open message from clamshell controlling driver
1739 // Update our internal state and tell general interest clients
1740 clamshellIsClosed
= true;
1741 clamshellExists
= true;
1744 informCPUStateChange(kInformLid
, 1);
1746 // Tell general interest clients
1747 sendClientClamshellNotification();
1749 // And set eval_clamshell = so we can attempt
1750 eval_clamshell
= true;
1754 * Set Desktop mode (sent from graphics)
1756 * -> reevaluate lid state
1758 if (msg
& kIOPMSetDesktopMode
)
1760 desktopMode
= (0 != (msg
& kIOPMSetValue
));
1761 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
1763 sendClientClamshellNotification();
1765 // Re-evaluate the lid state
1766 if( clamshellIsClosed
)
1768 eval_clamshell
= true;
1773 * AC Adaptor connected
1775 * -> reevaluate lid state
1777 if (msg
& kIOPMSetACAdaptorConnected
)
1779 acAdaptorConnect
= (0 != (msg
& kIOPMSetValue
));
1780 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
1783 informCPUStateChange(kInformAC
, !acAdaptorConnect
);
1785 sendClientClamshellNotification();
1787 // Re-evaluate the lid state
1788 if( clamshellIsClosed
)
1790 eval_clamshell
= true;
1796 * Enable Clamshell (external display disappear)
1798 * -> reevaluate lid state
1800 if (msg
& kIOPMEnableClamshell
)
1802 // Re-evaluate the lid state
1803 // System should sleep on external display disappearance
1804 // in lid closed operation.
1805 if( clamshellIsClosed
&& (true == ignoringClamshell
) )
1807 eval_clamshell
= true;
1810 ignoringClamshell
= false;
1812 sendClientClamshellNotification();
1816 * Disable Clamshell (external display appeared)
1817 * We don't bother re-evaluating clamshell state. If the system is awake,
1818 * the lid is probably open.
1820 if (msg
& kIOPMDisableClamshell
)
1822 ignoringClamshell
= true;
1824 sendClientClamshellNotification();
1828 * Evaluate clamshell and SLEEP if appropiate
1830 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
1835 privateSleepSystem (kIOPMClamshellSleepKey
);
1841 if (msg
& kIOPMPowerButton
)
1843 // toggle state of sleep/wake
1845 if ( getPowerState() == DOZE_STATE
)
1847 // yes, tell the tree we're waking
1849 // wake the Display Wrangler
1853 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
1854 // Check that power button sleep is enabled
1856 if( kOSBooleanTrue
!= getProperty(pbs
))
1857 privateSleepSystem (kIOPMPowerButtonSleepKey
);
1866 if ( (msg
& kIOPMAllowSleep
) && !allowSleep
)
1876 if (msg
& kIOPMPreventSleep
) {
1879 if ( getPowerState() == DOZE_STATE
) {
1880 // yes, tell the tree we're waking
1883 // wake the Display Wrangler
1887 // make sure we have power to clamp
1888 patriarch
->wakeSystem();
1896 //*********************************************************************************
1899 //*********************************************************************************
1901 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
1903 if ( flags
& kPCICantSleep
)
1908 platformSleepSupport
= flags
;
1911 setProperty(kIOSleepSupportedKey
, canSleep
);
1915 //*********************************************************************************
1916 // requestPowerDomainState
1918 // The root domain intercepts this call to the superclass.
1919 // Called on the PM work loop thread.
1921 // If the clamp bit is not set in the desire, then the child doesn't need the power
1922 // state it's requesting; it just wants it. The root ignores desires but not needs.
1923 // If the clamp bit is not set, the root takes it that the child can tolerate no
1924 // power and interprets the request accordingly. If all children can thus tolerate
1925 // no power, we are on our way to idle sleep.
1926 //*********************************************************************************
1928 IOReturn
IOPMrootDomain::requestPowerDomainState (
1929 IOPMPowerFlags desiredState
,
1930 IOPowerConnection
* whichChild
,
1931 unsigned long specification
)
1935 IOPowerConnection
*connection
;
1936 unsigned long powerRequestFlag
= 0;
1937 IOPMPowerFlags editedDesire
;
1940 IOService
*powerChild
;
1941 powerChild
= (IOService
*) whichChild
->getChildEntry(gIOPowerPlane
);
1944 DEBUG_LOG("RequestPowerDomainState: flags %lx, child %p [%s], spec %lx\n",
1945 desiredState
, powerChild
, powerChild
? powerChild
->getName() : "?",
1948 // Force the child's input power requirements to 0 unless the prevent
1949 // idle-sleep flag is set. No input power flags map to our state 0.
1950 // Our power clamp (deviceDesire) keeps the minimum power state at 2.
1952 if (desiredState
& kIOPMPreventIdleSleep
)
1953 editedDesire
= desiredState
;
1957 // Recompute sleep supported flag (doze if not supported)
1958 sleepIsSupported
= true;
1960 iter
= getChildIterator(gIOPowerPlane
);
1963 while ( (next
= iter
->getNextObject()) )
1965 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
1967 // Ignore child that are in the process of joining.
1968 if (connection
->getReadyFlag() == false)
1971 // Is this connection attached to the child that called
1972 // requestPowerDomainState()?
1974 if ( connection
== whichChild
)
1976 // Yes, OR in the child's input power requirements.
1977 powerRequestFlag
|= editedDesire
;
1979 if ( desiredState
& kIOPMPreventSystemSleep
)
1980 sleepIsSupported
= false;
1985 powerChild
= (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
1987 DEBUG_LOG(" child %p, PState %ld, noIdle %d, noSleep %d, valid %d %s\n",
1989 connection
->getDesiredDomainState(),
1990 connection
->getPreventIdleSleepFlag(),
1991 connection
->getPreventSystemSleepFlag(),
1992 connection
->getReadyFlag(),
1993 powerChild
? powerChild
->getName() : "?");
1995 // No, OR in the child's desired power domain state.
1996 // Which is our power state desired by this child.
1997 powerRequestFlag
|= connection
->getDesiredDomainState();
1999 if ( connection
->getPreventSystemSleepFlag() )
2000 sleepIsSupported
= false;
2007 if ( !powerRequestFlag
&& !systemBooting
)
2012 changePowerStateToPriv(ON_STATE
);
2015 AbsoluteTime deadline
;
2016 // stay awake for at least idleSeconds
2017 clock_interval_to_deadline(idleSeconds
, kSecondScale
, &deadline
);
2018 thread_call_enter_delayed(extraSleepTimer
, deadline
);
2019 // this gets turned off when we sleep again
2020 idleSleepPending
= true;
2023 else if (extraSleepDelay
== 0)
2029 DEBUG_LOG(" sleepDelay %lx, mergedFlags %lx, sleepASAP %x, booting %x\n",
2030 extraSleepDelay
, powerRequestFlag
, sleepASAP
, systemBooting
);
2032 // Drop our power clamp to SLEEP_STATE when all devices become idle.
2033 // Needed when the system sleep and display sleep timeouts are the same.
2034 // Otherwise, the extra sleep timer will also drop our power clamp.
2038 editedDesire
|= (desiredState
& kIOPMPreventSystemSleep
);
2040 // If our power clamp has already dropped to SLEEP_STATE, and no child
2041 // is keeping us at max power, then this will trigger idle sleep.
2043 return super::requestPowerDomainState(editedDesire
, whichChild
, specification
);
2047 //*********************************************************************************
2048 // getSleepSupported
2050 //*********************************************************************************
2052 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
2054 return( platformSleepSupport
);
2058 //*********************************************************************************
2059 // handlePlatformHaltRestart
2061 //*********************************************************************************
2063 struct HaltRestartApplierContext
{
2064 IOPMrootDomain
* RootDomain
;
2065 unsigned long PowerState
;
2066 IOPMPowerFlags PowerFlags
;
2072 platformHaltRestartApplier( OSObject
* object
, void * context
)
2074 IOPowerStateChangeNotification notify
;
2075 HaltRestartApplierContext
* ctx
;
2076 AbsoluteTime startTime
;
2079 ctx
= (HaltRestartApplierContext
*) context
;
2081 memset(¬ify
, 0, sizeof(notify
));
2082 notify
.powerRef
= (void *)ctx
->Counter
;
2083 notify
.returnValue
= 0;
2084 notify
.stateNumber
= ctx
->PowerState
;
2085 notify
.stateFlags
= ctx
->PowerFlags
;
2087 clock_get_uptime(&startTime
);
2088 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
2089 deltaTime
= computeDeltaTimeMS(&startTime
);
2091 if ((deltaTime
> kPMHaltTimeoutMS
) || (gIOKitDebug
& kIOLogDebugPower
))
2093 _IOServiceInterestNotifier
* notifier
;
2094 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
2096 // IOService children of IOPMrootDomain are not instrumented.
2097 // Only IORootParent currently falls under that group.
2101 HaltRestartLog("%s handler %p took %lu ms\n",
2102 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ?
2103 "PowerOff" : "Restart",
2104 notifier
->handler
, deltaTime
);
2111 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
2113 HaltRestartApplierContext ctx
;
2114 AbsoluteTime startTime
;
2117 memset(&ctx
, 0, sizeof(ctx
));
2118 ctx
.RootDomain
= this;
2120 clock_get_uptime(&startTime
);
2124 ctx
.PowerState
= OFF_STATE
;
2125 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
2129 ctx
.PowerState
= RESTART_STATE
;
2130 ctx
.MessageType
= kIOMessageSystemWillRestart
;
2137 // Notify legacy clients
2138 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
2140 // Notify in power tree order
2141 notifySystemShutdown(this, ctx
.MessageType
);
2143 deltaTime
= computeDeltaTimeMS(&startTime
);
2144 HaltRestartLog("%s all drivers took %lu ms\n",
2145 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ?
2146 "PowerOff" : "Restart",
2151 //*********************************************************************************
2154 // We override the superclass implementation so we can send a different message
2155 // type to the client or application being notified.
2156 //*********************************************************************************
2158 bool IOPMrootDomain::tellChangeDown ( unsigned long stateNum
)
2160 switch ( stateNum
) {
2164 // Direct callout into OSMetaClass so it can disable kmod unloads
2165 // during sleep/wake to prevent deadlocks.
2166 OSMetaClassSystemSleepOrWake( kIOMessageSystemWillSleep
);
2168 return super::tellClientsWithResponse(kIOMessageSystemWillSleep
);
2170 return super::tellChangeDown(stateNum
);
2174 //*********************************************************************************
2177 // We override the superclass implementation so we can send a different message
2178 // type to the client or application being notified.
2180 // This must be idle sleep since we don't ask apps during any other power change.
2181 //*********************************************************************************
2183 bool IOPMrootDomain::askChangeDown ( unsigned long )
2185 return super::tellClientsWithResponse(kIOMessageCanSystemSleep
);
2189 //*********************************************************************************
2192 // Notify registered applications and kernel clients that we are not
2195 // We override the superclass implementation so we can send a different message
2196 // type to the client or application being notified.
2198 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2199 //*********************************************************************************
2201 void IOPMrootDomain::tellNoChangeDown ( unsigned long )
2203 if (idleSeconds
&& !wrangler
)
2205 AbsoluteTime deadline
;
2207 // stay awake for at least idleSeconds
2208 clock_interval_to_deadline(idleSeconds
, kSecondScale
, &deadline
);
2209 thread_call_enter_delayed(extraSleepTimer
, deadline
);
2210 // this gets turned off when we sleep again
2211 idleSleepPending
= true;
2213 return tellClients(kIOMessageSystemWillNotSleep
);
2217 //*********************************************************************************
2220 // Notify registered applications and kernel clients that we are raising power.
2222 // We override the superclass implementation so we can send a different message
2223 // type to the client or application being notified.
2224 //*********************************************************************************
2226 void IOPMrootDomain::tellChangeUp ( unsigned long stateNum
)
2228 if ( stateNum
== ON_STATE
)
2231 // Direct callout into OSMetaClass so it can disable kmod unloads
2232 // during sleep/wake to prevent deadlocks.
2233 OSMetaClassSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2235 IOHibernateSystemPostWake();
2237 return tellClients(kIOMessageSystemHasPoweredOn
);
2241 //*********************************************************************************
2244 //*********************************************************************************
2246 void IOPMrootDomain::reportUserInput ( void )
2253 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
2256 wrangler
= (IOService
*) iter
->getNextObject();
2262 wrangler
->activityTickle(0,0);
2266 //*********************************************************************************
2267 // setQuickSpinDownTimeout
2269 //*********************************************************************************
2271 void IOPMrootDomain::setQuickSpinDownTimeout ( void )
2273 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown
,(unsigned long)1);
2276 //*********************************************************************************
2277 // restoreUserSpinDownTimeout
2279 //*********************************************************************************
2281 void IOPMrootDomain::restoreUserSpinDownTimeout ( void )
2283 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown
,(unsigned long)user_spindown
);
2286 //*********************************************************************************
2287 // changePowerStateTo & changePowerStateToPriv
2289 // Override of these methods for logging purposes.
2290 //*********************************************************************************
2292 IOReturn
IOPMrootDomain::changePowerStateTo ( unsigned long ordinal
)
2294 return super::changePowerStateTo(ordinal
);
2297 IOReturn
IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal
)
2301 DEBUG_LOG("ChangePowerStateToPriv: power state %ld\n", ordinal
);
2303 if ( (getPowerState() == DOZE_STATE
) && (ordinal
!= ON_STATE
) )
2305 return kIOReturnSuccess
;
2308 if( (userDisabledAllSleep
|| systemBooting
|| systemShutdown
)
2309 && (ordinal
== SLEEP_STATE
) )
2311 DEBUG_LOG(" sleep denied: disableAllSleep %d, booting %d, shutdown %d\n",
2312 userDisabledAllSleep
, systemBooting
, systemShutdown
);
2313 super::changePowerStateToPriv(ON_STATE
);
2316 if( (SLEEP_STATE
== ordinal
) && sleepSupportedPEFunction
)
2319 // Determine if the machine supports sleep, or must doze.
2320 ret
= getPlatform()->callPlatformFunction(
2321 sleepSupportedPEFunction
, false,
2322 NULL
, NULL
, NULL
, NULL
);
2324 // If the machine only supports doze, the callPlatformFunction call
2325 // boils down to IOPMrootDomain::setSleepSupported(kPCICantSleep),
2326 // otherwise nothing.
2329 return super::changePowerStateToPriv(ordinal
);
2333 //*********************************************************************************
2334 // sysPowerDownHandler
2336 // Receives a notification when the RootDomain changes state.
2338 // Allows us to take action on system sleep, power down, and restart after
2339 // applications have received their power change notifications and replied,
2340 // but before drivers have powered down. We perform a vfs sync on power down.
2341 //*********************************************************************************
2343 IOReturn
IOPMrootDomain::sysPowerDownHandler( void * target
, void * refCon
,
2344 UInt32 messageType
, IOService
* service
,
2345 void * messageArgument
, vm_size_t argSize
)
2348 IOPowerStateChangeNotification
*params
= (IOPowerStateChangeNotification
*) messageArgument
;
2349 IOPMrootDomain
*rootDomain
= OSDynamicCast(IOPMrootDomain
, service
);
2352 return kIOReturnUnsupported
;
2354 switch (messageType
) {
2355 case kIOMessageSystemWillSleep
:
2356 DEBUG_LOG("SystemWillSleep\n");
2358 // Interested applications have been notified of an impending power
2359 // change and have acked (when applicable).
2360 // This is our chance to save whatever state we can before powering
2362 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2365 // We will ack within 20 seconds
2366 params
->returnValue
= 20 * 1000 * 1000;
2368 if (gIOHibernateState
)
2369 params
->returnValue
+= gIOHibernateFreeTime
* 1000; //add in time we could spend freeing pages
2372 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2374 // Purposely delay the ack and hope that shutdown occurs quickly.
2375 // Another option is not to schedule the thread and wait for
2377 AbsoluteTime deadline
;
2378 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2379 thread_call_enter1_delayed( rootDomain
->diskSyncCalloutEntry
,
2380 (thread_call_param_t
)params
->powerRef
,
2384 thread_call_enter1(rootDomain
->diskSyncCalloutEntry
, (thread_call_param_t
)params
->powerRef
);
2385 ret
= kIOReturnSuccess
;
2388 case kIOMessageSystemWillPowerOff
:
2389 case kIOMessageSystemWillRestart
:
2390 ret
= kIOReturnUnsupported
;
2394 ret
= kIOReturnUnsupported
;
2400 //*********************************************************************************
2401 // displayWranglerNotification
2403 // Receives a notification when the IODisplayWrangler changes state.
2405 // Allows us to take action on display dim/undim.
2407 // When the display sleeps we:
2408 // - Start the idle sleep timer
2409 // - set the quick spin down timeout
2411 // On wake from display sleep:
2412 // - Cancel the idle sleep timer
2413 // - restore the user's chosen spindown timer from the "quick" spin down value
2414 //*********************************************************************************
2416 IOReturn
IOPMrootDomain::displayWranglerNotification(
2417 void * target
, void * refCon
,
2418 UInt32 messageType
, IOService
* service
,
2419 void * messageArgument
, vm_size_t argSize
)
2422 IOPMrootDomain
* rootDomain
= OSDynamicCast(IOPMrootDomain
, (IOService
*)target
);
2423 AbsoluteTime deadline
;
2424 static int displayPowerState
= 4;
2427 return kIOReturnUnsupported
;
2429 switch (messageType
) {
2430 case kIOMessageDeviceWillPowerOff
:
2431 DEBUG_LOG("DisplayWranglerWillPowerOff: new p-state %d\n",
2432 displayPowerState
- 1);
2434 // The display wrangler has dropped power because of idle display sleep
2435 // or force system sleep. We will receive 4 messages before the display
2436 // wrangler reaches its lowest state. Act only when going to state 2.
2439 // 3->2 Display Sleep
2440 // 2->1 Not visible to user
2441 // 1->0 Not visible to user
2443 displayPowerState
--;
2444 if ( 2 != displayPowerState
)
2445 return kIOReturnUnsupported
;
2447 // We start a timer here if the System Sleep timer is greater than the
2448 // Display Sleep timer. We kick off this timer when the display sleeps.
2450 // Note that, although Display Dim timings may change adaptively accordingly
2451 // to the user's activity patterns, Display Sleep _always_ occurs at the
2452 // specified interval since last user activity.
2454 if ( rootDomain
->extraSleepDelay
)
2456 clock_interval_to_deadline(rootDomain
->extraSleepDelay
*60, kSecondScale
, &deadline
);
2457 thread_call_enter_delayed(rootDomain
->extraSleepTimer
, deadline
);
2458 rootDomain
->idleSleepPending
= true;
2459 DEBUG_LOG(" sleep timer set to expire in %ld min\n",
2460 rootDomain
->extraSleepDelay
);
2462 // Accelerate disk spindown if system sleep and display sleep
2463 // sliders are set to the same value (e.g. both set to 5 min),
2464 // and display is about to go dark. Check that spin down timer
2465 // is non-zero (zero = never spin down) and system sleep is
2466 // not set to never sleep.
2468 if ( (0 != rootDomain
->user_spindown
) && (0 != rootDomain
->sleepSlider
) )
2470 DEBUG_LOG(" accelerate quick disk spindown, was %d min\n",
2471 rootDomain
->user_spindown
);
2472 rootDomain
->setQuickSpinDownTimeout();
2478 case kIOMessageDeviceHasPoweredOn
:
2479 DEBUG_LOG("DisplayWranglerHasPoweredOn: previous p-state %d\n",
2482 // The display wrangler has powered on either because of user activity
2483 // or wake from sleep/doze.
2485 displayPowerState
= 4;
2486 rootDomain
->adjustPowerState();
2488 // cancel any pending idle sleep timers
2489 if (rootDomain
->idleSleepPending
)
2491 DEBUG_LOG(" extra-sleep timer stopped\n");
2492 thread_call_cancel(rootDomain
->extraSleepTimer
);
2493 rootDomain
->idleSleepPending
= false;
2496 // Change the spindown value back to the user's selection from our
2497 // accelerated setting.
2498 if (0 != rootDomain
->user_spindown
)
2500 DEBUG_LOG(" restoring disk spindown to %d min\n",
2501 rootDomain
->user_spindown
);
2502 rootDomain
->restoreUserSpinDownTimeout();
2511 return kIOReturnUnsupported
;
2514 //*********************************************************************************
2515 // displayWranglerPublished
2517 // Receives a notification when the IODisplayWrangler is published.
2518 // When it's published we install a power state change handler.
2520 //*********************************************************************************
2522 bool IOPMrootDomain::displayWranglerPublished(
2525 IOService
* newService
)
2528 IOPMrootDomain
*rootDomain
=
2529 OSDynamicCast(IOPMrootDomain
, (IOService
*)target
);
2534 rootDomain
->wrangler
= newService
;
2536 // we found the display wrangler, now install a handler
2537 if( !rootDomain
->wrangler
->registerInterest( gIOGeneralInterest
,
2538 &displayWranglerNotification
, target
, 0) )
2546 //*********************************************************************************
2549 // Notification on battery class IOPowerSource appearance
2551 //******************************************************************************
2553 bool IOPMrootDomain::batteryPublished(
2556 IOService
* resourceService
)
2558 // rdar://2936060&4435589
2559 // All laptops have dimmable LCD displays
2560 // All laptops have batteries
2561 // So if this machine has a battery, publish the fact that the backlight
2562 // supports dimming.
2563 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
2568 //*********************************************************************************
2571 // Some condition that affects our wake/sleep/doze decision has changed.
2573 // If the sleep slider is in the off position, we cannot sleep or doze.
2574 // If the enclosure is open, we cannot sleep or doze.
2575 // If the system is still booting, we cannot sleep or doze.
2577 // In those circumstances, we prevent sleep and doze by holding power on with
2578 // changePowerStateToPriv(ON).
2580 // If the above conditions do not exist, and also the sleep timer has expired, we
2581 // allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
2582 // changePowerStateToPriv(DOZE) depending on whether or not we already know the
2583 // platform cannot sleep.
2585 // In this case, sleep or doze will either occur immediately or at the next time
2586 // that no children are holding the system out of idle sleep via the
2587 // kIOPMPreventIdleSleep flag in their power state arrays.
2588 //*********************************************************************************
2590 void IOPMrootDomain::adjustPowerState( void )
2592 if ( (sleepSlider
== 0)
2596 || userDisabledAllSleep
)
2598 DEBUG_LOG("AdjustPowerState %ld -> ON: slider %ld, allowSleep %d, "
2599 "booting %d, shutdown %d, userDisabled %d\n",
2600 getPowerState(), sleepSlider
, allowSleep
, systemBooting
,
2601 systemShutdown
, userDisabledAllSleep
);
2603 changePowerStateToPriv(ON_STATE
);
2607 DEBUG_LOG("AdjustPowerState SLEEP\n");
2609 /* Convenient place to run any code at idle sleep time
2610 * IOPMrootDomain initiates an idle sleep here
2612 * Set last sleep cause accordingly.
2614 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
2617 if ( !sleepIsSupported
)
2619 setSleepSupported( kPCICantSleep
);
2620 kprintf("Sleep prevented by kIOPMPreventSystemSleep flag\n");
2622 changePowerStateToPriv(SLEEP_STATE
);
2627 //*********************************************************************************
2628 // PMHaltWorker Class
2630 //*********************************************************************************
2632 static unsigned int gPMHaltBusyCount
;
2633 static unsigned int gPMHaltIdleCount
;
2634 static int gPMHaltDepth
;
2635 static unsigned long gPMHaltEvent
;
2636 static IOLock
* gPMHaltLock
= 0;
2637 static OSArray
* gPMHaltArray
= 0;
2638 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
2640 PMHaltWorker
* PMHaltWorker::worker( void )
2646 me
= OSTypeAlloc( PMHaltWorker
);
2647 if (!me
|| !me
->init())
2650 me
->lock
= IOLockAlloc();
2654 DEBUG_LOG("PMHaltWorker %p\n", me
);
2655 me
->retain(); // thread holds extra retain
2656 thread
= IOCreateThread( &PMHaltWorker::main
, me
);
2666 if (me
) me
->release();
2670 void PMHaltWorker::free( void )
2672 DEBUG_LOG("PMHaltWorker free %p\n", this);
2678 return OSObject::free();
2681 void PMHaltWorker::main( void * arg
)
2683 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
2685 IOLockLock( gPMHaltLock
);
2687 me
->depth
= gPMHaltDepth
;
2688 IOLockUnlock( gPMHaltLock
);
2690 while (me
->depth
>= 0)
2692 PMHaltWorker::work( me
);
2694 IOLockLock( gPMHaltLock
);
2695 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
2697 // This is the last thread to finish work on this level,
2698 // inform everyone to start working on next lower level.
2700 me
->depth
= gPMHaltDepth
;
2701 gPMHaltIdleCount
= 0;
2702 thread_wakeup((event_t
) &gPMHaltIdleCount
);
2706 // One or more threads are still working on this level,
2707 // this thread must wait.
2708 me
->depth
= gPMHaltDepth
- 1;
2710 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
2711 } while (me
->depth
!= gPMHaltDepth
);
2713 IOLockUnlock( gPMHaltLock
);
2716 // No more work to do, terminate thread
2717 DEBUG_LOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
2718 thread_wakeup( &gPMHaltDepth
);
2722 void PMHaltWorker::work( PMHaltWorker
* me
)
2724 IOService
* service
;
2726 AbsoluteTime startTime
;
2735 // Claim an unit of work from the shared pool
2736 IOLockLock( gPMHaltLock
);
2737 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
2740 service
= (IOService
*)inner
->getAnyObject();
2744 inner
->removeObject(service
);
2747 IOLockUnlock( gPMHaltLock
);
2749 break; // no more work at this depth
2751 clock_get_uptime(&startTime
);
2753 if (!service
->isInactive() &&
2754 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
2756 IOLockLock(me
->lock
);
2757 me
->startTime
= startTime
;
2758 me
->service
= service
;
2759 me
->timeout
= false;
2760 IOLockUnlock(me
->lock
);
2762 service
->systemWillShutdown( gPMHaltEvent
);
2764 // Wait for driver acknowledgement
2765 IOLockLock(me
->lock
);
2766 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
2768 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
2771 timeout
= me
->timeout
;
2772 IOLockUnlock(me
->lock
);
2775 deltaTime
= computeDeltaTimeMS(&startTime
);
2776 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
2777 (gIOKitDebug
& kIOLogDebugPower
))
2779 HaltRestartLog("%s driver %s (%p) took %lu ms\n",
2780 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
2781 "PowerOff" : "Restart",
2782 service
->getName(), service
,
2791 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
2794 AbsoluteTime startTime
;
2795 AbsoluteTime endTime
;
2799 IOLockLock(me
->lock
);
2800 if (me
->service
&& !me
->timeout
)
2802 startTime
= me
->startTime
;
2804 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
2806 SUB_ABSOLUTETIME(&endTime
, &startTime
);
2807 absolutetime_to_nanoseconds(endTime
, &nano
);
2809 if (nano
> 3000000000ULL)
2812 HaltRestartLog("%s still waiting on %s\n",
2813 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
2814 "PowerOff" : "Restart",
2815 me
->service
->getName());
2818 IOLockUnlock(me
->lock
);
2821 //*********************************************************************************
2822 // acknowledgeSystemWillShutdown
2824 // Acknowledgement from drivers that they have prepared for shutdown/restart.
2825 //*********************************************************************************
2827 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
2829 PMHaltWorker
* worker
;
2835 //DEBUG_LOG("%s acknowledged\n", from->getName());
2836 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
2839 worker
= (PMHaltWorker
*) prop
;
2840 IOLockLock(worker
->lock
);
2841 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
2842 thread_wakeup((event_t
) worker
);
2843 IOLockUnlock(worker
->lock
);
2848 DEBUG_LOG("%s acknowledged without worker property\n",
2853 //*********************************************************************************
2854 // notifySystemShutdown
2856 // Notify all objects in PM tree that system will shutdown or restart
2857 //*********************************************************************************
2860 notifySystemShutdown( IOService
* root
, unsigned long event
)
2862 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
2863 IORegistryIterator
* iter
;
2864 IORegistryEntry
* entry
;
2867 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
2868 AbsoluteTime deadline
;
2869 unsigned int totalNodes
= 0;
2871 unsigned int rootDepth
;
2872 unsigned int numWorkers
;
2878 DEBUG_LOG("%s event = %lx\n", __FUNCTION__
, event
);
2880 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
2882 // Iterate the entire PM tree starting from root
2884 rootDepth
= root
->getDepth( gIOPowerPlane
);
2885 if (!rootDepth
) goto done
;
2887 // debug - for repeated test runs
2888 while (PMHaltWorker::metaClass
->getInstanceCount())
2893 gPMHaltArray
= OSArray::withCapacity(40);
2894 if (!gPMHaltArray
) goto done
;
2897 gPMHaltArray
->flushCollection();
2901 gPMHaltLock
= IOLockAlloc();
2902 if (!gPMHaltLock
) goto done
;
2905 if (!gPMHaltClientAcknowledgeKey
)
2907 gPMHaltClientAcknowledgeKey
=
2908 OSSymbol::withCStringNoCopy("PMShutdown");
2909 if (!gPMHaltClientAcknowledgeKey
) goto done
;
2912 gPMHaltEvent
= event
;
2914 // Depth-first walk of PM plane
2916 iter
= IORegistryIterator::iterateOver(
2917 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
2921 while ((entry
= iter
->getNextObject()))
2923 node
= OSDynamicCast(IOService
, entry
);
2928 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
2931 depth
= node
->getDepth( gIOPowerPlane
);
2932 if (depth
<= rootDepth
)
2937 // adjust to zero based depth
2938 depth
-= (rootDepth
+ 1);
2940 // gPMHaltArray is an array of containers, each container
2941 // refers to nodes with the same depth.
2943 count
= gPMHaltArray
->getCount();
2944 while (depth
>= count
)
2946 // expand array and insert placeholders
2947 gPMHaltArray
->setObject(PLACEHOLDER
);
2950 count
= gPMHaltArray
->getCount();
2953 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
2954 if (inner
== PLACEHOLDER
)
2956 inner
= OSSet::withCapacity(40);
2959 gPMHaltArray
->replaceObject(depth
, inner
);
2964 // PM nodes that appear more than once in the tree will have
2965 // the same depth, OSSet will refuse to add the node twice.
2967 ok
= inner
->setObject(node
);
2970 DEBUG_LOG("Skipped PM node %s\n", node
->getName());
2976 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
2979 if (inner
!= PLACEHOLDER
)
2980 count
= inner
->getCount();
2981 DEBUG_LOG("Nodes at depth %u = %u\n", i
, count
);
2984 // strip placeholders (not all depths are populated)
2986 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
2988 if (inner
== PLACEHOLDER
)
2990 gPMHaltArray
->removeObject(i
);
2993 count
= inner
->getCount();
2994 if (count
> numWorkers
)
2996 totalNodes
+= count
;
3000 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
3003 gPMHaltBusyCount
= 0;
3004 gPMHaltIdleCount
= 0;
3005 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
3007 // Create multiple workers (and threads)
3009 if (numWorkers
> kPMHaltMaxWorkers
)
3010 numWorkers
= kPMHaltMaxWorkers
;
3012 DEBUG_LOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
3013 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
3015 for (unsigned int i
= 0; i
< numWorkers
; i
++)
3016 workers
[i
] = PMHaltWorker::worker();
3018 // Wait for workers to exhaust all available work
3020 IOLockLock(gPMHaltLock
);
3021 while (gPMHaltDepth
>= 0)
3023 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
3025 waitResult
= IOLockSleepDeadline(
3026 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
3027 if (THREAD_TIMED_OUT
== waitResult
)
3030 clock_get_uptime(&now
);
3032 IOLockUnlock(gPMHaltLock
);
3033 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
3036 PMHaltWorker::checkTimeout(workers
[i
], &now
);
3038 IOLockLock(gPMHaltLock
);
3041 IOLockUnlock(gPMHaltLock
);
3043 // Release all workers
3045 for (unsigned int i
= 0; i
< numWorkers
; i
++)
3048 workers
[i
]->release();
3049 // worker also retained by it's own thread
3053 DEBUG_LOG("%s done\n", __FUNCTION__
);
3058 // debug - exercise notifySystemShutdown()
3059 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
3061 IOPMrootDomain
* root
= (IOPMrootDomain
*) this;
3062 notifySystemShutdown( root
, kIOMessageSystemWillPowerOff
);
3063 return( super::serializeProperties(s
) );
3067 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3072 #define super OSObject
3073 OSDefineMetaClassAndStructors(PMSettingObject
, OSObject
)
3075 void PMSettingObject::setPMSetting(const OSSymbol
*type
, OSObject
*obj
)
3077 (*func
)(target
, type
, obj
, refcon
);
3081 * Static constructor/initializer for PMSettingObject
3083 PMSettingObject
*PMSettingObject::pmSettingObject(
3084 IOPMrootDomain
*parent_arg
,
3085 IOPMSettingControllerCallback handler_arg
,
3086 OSObject
*target_arg
,
3087 uintptr_t refcon_arg
,
3088 uint32_t supportedPowerSources
,
3089 const OSSymbol
* settings
[])
3091 uint32_t objCount
= 0;
3092 PMSettingObject
*pmso
;
3094 if( !parent_arg
|| !handler_arg
|| !settings
) return NULL
;
3096 // count OSSymbol entries in NULL terminated settings array
3097 while( settings
[objCount
] ) {
3100 if(0 == objCount
) return NULL
;
3102 pmso
= new PMSettingObject
;
3103 if(!pmso
|| !pmso
->init()) return NULL
;
3105 pmso
->parent
= parent_arg
;
3106 pmso
->func
= handler_arg
;
3107 pmso
->target
= target_arg
;
3108 pmso
->refcon
= refcon_arg
;
3109 pmso
->releaseAtCount
= objCount
+ 1; // release when it has count+1 retains
3111 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount
);
3112 if(pmso
->publishedFeatureID
) {
3113 for(unsigned int i
=0; i
<objCount
; i
++) {
3114 // Since there is now at least one listener to this setting, publish
3115 // PM root domain support for it.
3116 parent_arg
->publishFeature( settings
[i
]->getCStringNoCopy(),
3117 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
3124 void PMSettingObject::free(void)
3126 OSCollectionIterator
*settings_iter
;
3131 int objCount
= releaseAtCount
- 1;
3133 if(publishedFeatureID
) {
3134 for(i
=0; i
<objCount
; i
++) {
3135 if(0 != publishedFeatureID
[i
]) {
3136 parent
->removePublishedFeature( publishedFeatureID
[i
] );
3140 IOFree(publishedFeatureID
, sizeof(uint32_t) * objCount
);
3143 IORecursiveLockLock(parent
->settingsCtrlLock
);
3145 // Search each PM settings array in the kernel.
3146 settings_iter
= OSCollectionIterator::withCollection(parent
->settingsCallbacks
);
3149 while(( sym
= OSDynamicCast(OSSymbol
, settings_iter
->getNextObject()) ))
3151 arr
= (OSArray
*)parent
->settingsCallbacks
->getObject(sym
);
3152 arr_idx
= arr
->getNextIndexOfObject(this, 0);
3154 // 'this' was found in the array; remove it
3155 arr
->removeObject(arr_idx
);
3159 settings_iter
->release();
3162 IORecursiveLockUnlock(parent
->settingsCtrlLock
);
3167 void PMSettingObject::taggedRelease(const void *tag
, const int when
) const
3169 // We have n+1 retains - 1 per array that this PMSettingObject is a member
3170 // of, and 1 retain to ourself. When we get a release with n+1 retains
3171 // remaining, we go ahead and free ourselves, cleaning up array pointers
3174 super::taggedRelease(tag
, releaseAtCount
);
3179 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3182 #define super IOService
3184 OSDefineMetaClassAndStructors(IORootParent
, IOService
)
3186 // This array exactly parallels the state array for the root domain.
3187 // Power state changes initiated by a device can be vetoed by a client of the device, and
3188 // power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
3189 // so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
3190 // its parent to make the change. That is the reason for this complexity.
3192 static IOPMPowerState patriarchPowerStates
[number_of_power_states
] = {
3193 {1,0,0,0,0,0,0,0,0,0,0,0}, // off
3194 {1,0,RESTART_POWER
,0,0,0,0,0,0,0,0,0}, // reset
3195 {1,0,SLEEP_POWER
,0,0,0,0,0,0,0,0,0}, // sleep
3196 {1,0,DOZE_POWER
,0,0,0,0,0,0,0,0,0}, // doze
3197 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0} // running
3200 bool IORootParent::start ( IOService
* nub
)
3202 mostRecentChange
= ON_STATE
;
3206 registerPowerDriver(this,patriarchPowerStates
,number_of_power_states
);
3208 powerOverrideOnPriv();
3213 void IORootParent::shutDownSystem ( void )
3215 mostRecentChange
= OFF_STATE
;
3216 changePowerStateToPriv(OFF_STATE
);
3220 void IORootParent::restartSystem ( void )
3222 mostRecentChange
= RESTART_STATE
;
3223 changePowerStateToPriv(RESTART_STATE
);
3227 void IORootParent::sleepSystem ( void )
3229 mostRecentChange
= SLEEP_STATE
;
3230 changePowerStateToPriv(SLEEP_STATE
);
3234 void IORootParent::dozeSystem ( void )
3236 mostRecentChange
= DOZE_STATE
;
3237 changePowerStateToPriv(DOZE_STATE
);
3240 // Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
3241 // This brings the parent to doze, which allows the root to step up from sleep to doze.
3243 // In idle sleep, do nothing because the parent is still on and the root can freely change state.
3245 void IORootParent::sleepToDoze ( void )
3247 if ( mostRecentChange
== SLEEP_STATE
) {
3248 changePowerStateToPriv(DOZE_STATE
);
3253 void IORootParent::wakeSystem ( void )
3255 mostRecentChange
= ON_STATE
;
3256 changePowerStateToPriv(ON_STATE
);
3259 IOReturn
IORootParent::changePowerStateToPriv ( unsigned long ordinal
)
3263 if( (SLEEP_STATE
== ordinal
) && sleepSupportedPEFunction
)
3266 // Determine if the machine supports sleep, or must doze.
3267 ret
= getPlatform()->callPlatformFunction(
3268 sleepSupportedPEFunction
, false,
3269 NULL
, NULL
, NULL
, NULL
);
3271 // If the machine only supports doze, the callPlatformFunction call
3272 // boils down toIOPMrootDomain::setSleepSupported(kPCICantSleep),
3273 // otherwise nothing.
3276 return super::changePowerStateToPriv(ordinal
);