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;
1080 // Invalidate prior activity tickles to allow wake from doze.
1081 if (wrangler
) wrangler
->changePowerStateTo(0);
1085 IOLog("System Restart\n");
1086 PEHaltRestart(kPERestartCPU
);
1090 IOLog("System Halt\n");
1091 PEHaltRestart(kPEHaltCPU
);
1097 // **********************************************************************************
1100 // The Display Wrangler calls here when it switches to its highest state. If the
1101 // system is currently dozing, allow it to wake by making sure the parent is
1103 // **********************************************************************************
1104 void IOPMrootDomain::wakeFromDoze( void )
1106 if ( getPowerState() == DOZE_STATE
)
1108 // Reset sleep support till next sleep attempt.
1109 // A machine's support of sleep vs. doze can change over the course of
1110 // a running system, so we recalculate it before every sleep.
1111 setSleepSupported(0);
1113 changePowerStateToPriv(ON_STATE
);
1114 powerOverrideOffPriv();
1116 // early wake notification
1117 tellClients(kIOMessageSystemWillPowerOn
);
1119 // allow us to wake if children so desire
1120 patriarch
->wakeSystem();
1125 // *****************************************************************************
1128 // Adds a new feature to the supported features dictionary
1131 // *****************************************************************************
1132 void IOPMrootDomain::publishFeature( const char * feature
)
1134 publishFeature(feature
, kIOPMSupportedOnAC
1135 | kIOPMSupportedOnBatt
1136 | kIOPMSupportedOnUPS
,
1142 // *****************************************************************************
1143 // publishFeature (with supported power source specified)
1145 // Adds a new feature to the supported features dictionary
1148 // *****************************************************************************
1149 void IOPMrootDomain::publishFeature(
1150 const char *feature
,
1151 uint32_t supportedWhere
,
1152 uint32_t *uniqueFeatureID
)
1154 static uint16_t next_feature_id
= 500;
1156 OSNumber
*new_feature_data
= NULL
;
1157 OSNumber
*existing_feature
= NULL
;
1158 OSArray
*existing_feature_arr
= NULL
;
1159 OSObject
*osObj
= NULL
;
1160 uint32_t feature_value
= 0;
1162 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
1164 // kprintf("IOPMrootDomain::publishFeature [\"%s\":%0x01x]\n", feature, supportedWhere);
1166 if(!supportedWhere
) {
1167 // Feature isn't supported anywhere!
1171 if(next_feature_id
> 5000) {
1172 // Far, far too many features!
1176 if(featuresDictLock
) IOLockLock(featuresDictLock
);
1178 OSDictionary
*features
=
1179 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
1181 // Create new features dict if necessary
1182 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
1183 features
= OSDictionary::withDictionary(features
);
1185 features
= OSDictionary::withCapacity(1);
1188 // Create OSNumber to track new feature
1190 next_feature_id
+= 1;
1191 if( uniqueFeatureID
) {
1192 // We don't really mind if the calling kext didn't give us a place
1193 // to stash their unique id. Many kexts don't plan to unload, and thus
1194 // have no need to remove themselves later.
1195 *uniqueFeatureID
= next_feature_id
;
1198 feature_value
= supportedWhere
+ (next_feature_id
<< 16);
1199 new_feature_data
= OSNumber::withNumber(
1200 (unsigned long long)feature_value
, 32);
1202 // Does features object already exist?
1203 if( (osObj
= features
->getObject(feature
)) )
1205 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
1207 // We need to create an OSArray to hold the now 2 elements.
1208 existing_feature_arr
= OSArray::withObjects(
1209 (const OSObject
**)&existing_feature
, 1, 2);
1210 existing_feature_arr
->setObject(new_feature_data
);
1211 features
->setObject(feature
, existing_feature_arr
);
1212 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
1214 // Add object to existing array
1215 existing_feature_arr
->setObject(new_feature_data
);
1218 // The easy case: no previously existing features listed. We simply
1219 // set the OSNumber at key 'feature' and we're on our way.
1220 features
->setObject(feature
, new_feature_data
);
1223 new_feature_data
->release();
1225 setProperty(kRootDomainSupportedFeatures
, features
);
1227 features
->release();
1229 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
1231 // Notify EnergySaver and all those in user space so they might
1232 // re-populate their feature specific UI
1233 if(pmPowerStateQueue
) {
1234 pmPowerStateQueue
->featureChangeOccurred(
1235 kIOPMMessageFeatureChange
, this);
1239 // *****************************************************************************
1240 // removePublishedFeature
1242 // Removes previously published feature
1245 // *****************************************************************************
1246 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
1248 IOReturn ret
= kIOReturnError
;
1249 uint32_t feature_value
= 0;
1250 uint16_t feature_id
= 0;
1251 bool madeAChange
= false;
1253 OSSymbol
*dictKey
= NULL
;
1254 OSCollectionIterator
*dictIterator
= NULL
;
1255 OSArray
*arrayMember
= NULL
;
1256 OSNumber
*numberMember
= NULL
;
1257 OSObject
*osObj
= NULL
;
1258 OSNumber
*osNum
= NULL
;
1260 if(featuresDictLock
) IOLockLock(featuresDictLock
);
1262 OSDictionary
*features
=
1263 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
1265 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
1267 // Any modifications to the dictionary are made to the copy to prevent
1268 // races & crashes with userland clients. Dictionary updated
1269 // automically later.
1270 features
= OSDictionary::withDictionary(features
);
1273 ret
= kIOReturnNotFound
;
1277 // We iterate 'features' dictionary looking for an entry tagged
1278 // with 'removeFeatureID'. If found, we remove it from our tracking
1279 // structures and notify the OS via a general interest message.
1281 dictIterator
= OSCollectionIterator::withCollection(features
);
1286 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
1288 osObj
= features
->getObject(dictKey
);
1290 // Each Feature is either tracked by an OSNumber
1291 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
1293 feature_value
= numberMember
->unsigned32BitValue();
1294 feature_id
= (uint16_t)(feature_value
>> 16);
1296 if( feature_id
== (uint16_t)removeFeatureID
)
1299 features
->removeObject(dictKey
);
1304 // Or tracked by an OSArray of OSNumbers
1305 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
1307 unsigned int arrayCount
= arrayMember
->getCount();
1309 for(unsigned int i
=0; i
<arrayCount
; i
++)
1311 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
1316 feature_value
= osNum
->unsigned32BitValue();
1317 feature_id
= (uint16_t)(feature_value
>> 16);
1319 if( feature_id
== (uint16_t)removeFeatureID
)
1322 if( 1 == arrayCount
) {
1323 // If the array only contains one element, remove
1325 features
->removeObject(dictKey
);
1327 // Otherwise just remove the element in question.
1328 arrayMember
->removeObject(i
);
1339 dictIterator
->release();
1343 ret
= kIOReturnSuccess
;
1345 setProperty(kRootDomainSupportedFeatures
, features
);
1347 // Notify EnergySaver and all those in user space so they might
1348 // re-populate their feature specific UI
1349 if(pmPowerStateQueue
) {
1350 pmPowerStateQueue
->featureChangeOccurred(
1351 kIOPMMessageFeatureChange
, this);
1354 ret
= kIOReturnNotFound
;
1358 if(features
) features
->release();
1359 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
1364 // **********************************************************************************
1367 // Enqueues unidle event to be performed later in a serialized context.
1369 // **********************************************************************************
1370 void IOPMrootDomain::unIdleDevice( IOService
*theDevice
, unsigned long theState
)
1372 if(pmPowerStateQueue
)
1373 pmPowerStateQueue
->unIdleOccurred(theDevice
, theState
);
1376 // **********************************************************************************
1377 // announcePowerSourceChange
1379 // Notifies "interested parties" that the batteries have changed state
1381 // **********************************************************************************
1382 void IOPMrootDomain::announcePowerSourceChange( void )
1384 IORegistryEntry
*_batteryRegEntry
= (IORegistryEntry
*) getProperty("BatteryEntry");
1386 // (if possible) re-publish power source state under IOPMrootDomain;
1387 // only do so if the battery controller publishes an IOResource
1388 // defining battery location. Called from ApplePMU battery driver.
1390 if(_batteryRegEntry
)
1393 batt_info
= (OSArray
*) _batteryRegEntry
->getProperty(kIOBatteryInfoKey
);
1395 setProperty(kIOBatteryInfoKey
, batt_info
);
1401 // *****************************************************************************
1402 // setPMSetting (private)
1404 // Internal helper to relay PM settings changes from user space to individual
1405 // drivers. Should be called only by IOPMrootDomain::setProperties.
1407 // *****************************************************************************
1408 IOReturn
IOPMrootDomain::setPMSetting(
1409 const OSSymbol
*type
,
1412 OSArray
*arr
= NULL
;
1413 PMSettingObject
*p_obj
= NULL
;
1417 if(NULL
== type
) return kIOReturnBadArgument
;
1419 IORecursiveLockLock(settingsCtrlLock
);
1421 fPMSettingsDict
->setObject(type
, obj
);
1423 arr
= (OSArray
*)settingsCallbacks
->getObject(type
);
1424 if(NULL
== arr
) goto exit
;
1425 count
= arr
->getCount();
1426 for(i
=0; i
<count
; i
++) {
1427 p_obj
= (PMSettingObject
*)OSDynamicCast(PMSettingObject
, arr
->getObject(i
));
1428 if(p_obj
) p_obj
->setPMSetting(type
, obj
);
1432 IORecursiveLockUnlock(settingsCtrlLock
);
1433 return kIOReturnSuccess
;
1436 // *****************************************************************************
1437 // copyPMSetting (public)
1439 // Allows kexts to safely read setting values, without being subscribed to
1442 // *****************************************************************************
1443 OSObject
* IOPMrootDomain::copyPMSetting(
1444 OSSymbol
*whichSetting
)
1446 OSObject
*obj
= NULL
;
1448 if(!whichSetting
) return NULL
;
1450 IORecursiveLockLock(settingsCtrlLock
);
1451 obj
= fPMSettingsDict
->getObject(whichSetting
);
1455 IORecursiveLockUnlock(settingsCtrlLock
);
1460 // *****************************************************************************
1461 // registerPMSettingController (public)
1463 // direct wrapper to registerPMSettingController with uint32_t power source arg
1464 // *****************************************************************************
1465 IOReturn
IOPMrootDomain::registerPMSettingController(
1466 const OSSymbol
* settings
[],
1467 IOPMSettingControllerCallback func
,
1472 return registerPMSettingController(
1474 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
1475 func
, target
, refcon
, handle
);
1478 // *****************************************************************************
1479 // registerPMSettingController (public)
1481 // Kexts may register for notifications when a particular setting is changed.
1482 // A list of settings is available in IOPM.h.
1484 // * settings - An OSArray containing OSSymbols. Caller should populate this
1485 // array with a list of settings caller wants notifications from.
1486 // * func - A C function callback of the type IOPMSettingControllerCallback
1487 // * target - caller may provide an OSObject *, which PM will pass as an
1488 // target to calls to "func"
1489 // * refcon - caller may provide an void *, which PM will pass as an
1490 // argument to calls to "func"
1491 // * handle - This is a return argument. We will populate this pointer upon
1492 // call success. Hold onto this and pass this argument to
1493 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
1495 // kIOReturnSuccess on success
1496 // *****************************************************************************
1497 IOReturn
IOPMrootDomain::registerPMSettingController(
1498 const OSSymbol
* settings
[],
1499 uint32_t supportedPowerSources
,
1500 IOPMSettingControllerCallback func
,
1505 PMSettingObject
*pmso
= NULL
;
1506 OSArray
*list
= NULL
;
1507 IOReturn ret
= kIOReturnSuccess
;
1510 if( NULL
== settings
||
1514 return kIOReturnBadArgument
;
1517 pmso
= PMSettingObject::pmSettingObject(
1518 (IOPMrootDomain
*)this, func
, target
,
1519 refcon
, supportedPowerSources
, settings
);
1522 ret
= kIOReturnInternalError
;
1523 goto bail_no_unlock
;
1526 IORecursiveLockLock(settingsCtrlLock
);
1527 for(i
=0; settings
[i
]; i
++)
1529 list
= (OSArray
*)settingsCallbacks
->getObject(settings
[i
]);
1531 // New array of callbacks for this setting
1532 list
= OSArray::withCapacity(1);
1533 settingsCallbacks
->setObject(settings
[i
], list
);
1537 // Add caller to the callback list
1538 list
->setObject(pmso
);
1541 IORecursiveLockUnlock(settingsCtrlLock
);
1543 ret
= kIOReturnSuccess
;
1545 // Track this instance by its OSData ptr from now on
1549 if(kIOReturnSuccess
!= ret
)
1551 // Error return case
1552 if(pmso
) pmso
->release();
1553 if(handle
) *handle
= NULL
;
1559 //******************************************************************************
1560 // sleepOnClamshellClosed
1562 // contains the logic to determine if the system should sleep when the clamshell
1564 //******************************************************************************
1566 bool IOPMrootDomain::shouldSleepOnClamshellClosed ( void )
1568 return ( !ignoringClamshell
1569 && !ignoringClamshellDuringWakeup
1570 && !(desktopMode
&& acAdaptorConnect
) );
1573 void IOPMrootDomain::sendClientClamshellNotification ( void )
1575 /* Only broadcast clamshell alert if clamshell exists. */
1576 if(!clamshellExists
)
1579 setProperty(kAppleClamshellStateKey
,
1580 clamshellIsClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
1582 setProperty(kAppleClamshellCausesSleepKey
,
1583 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
1586 /* Argument to message is a bitfiel of
1587 * ( kClamshellStateBit | kClamshellSleepBit )
1589 messageClients(kIOPMMessageClamshellStateChange
,
1590 (void *) ( (clamshellIsClosed
? kClamshellStateBit
: 0)
1591 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
1594 //******************************************************************************
1595 // informCPUStateChange
1597 // Call into PM CPU code so that CPU power savings may dynamically adjust for
1598 // running on battery, with the lid closed, etc.
1600 // informCPUStateChange is a no-op on non x86 systems
1601 // only x86 has explicit support in the IntelCPUPowerManagement kext
1602 //******************************************************************************
1604 void IOPMrootDomain::informCPUStateChange(
1610 pmioctlVariableInfo_t varInfoStruct
;
1612 const char *varNameStr
= NULL
;
1613 int32_t *varIndex
= NULL
;
1615 if (kInformAC
== type
) {
1616 varNameStr
= kIOPMRootDomainBatPowerCString
;
1617 varIndex
= &idxPMCPULimitedPower
;
1618 } else if (kInformLid
== type
) {
1619 varNameStr
= kIOPMRootDomainLidCloseCString
;
1620 varIndex
= &idxPMCPUClamshell
;
1625 // Set the new value!
1626 // pmCPUControl will assign us a new ID if one doesn't exist yet
1627 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
1628 varInfoStruct
.varID
= *varIndex
;
1629 varInfoStruct
.varType
= vBool
;
1630 varInfoStruct
.varInitValue
= value
;
1631 varInfoStruct
.varCurValue
= value
;
1632 strncpy( (char *)varInfoStruct
.varName
,
1633 (const char *)varNameStr
,
1634 strlen(varNameStr
) + 1 );
1637 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
1639 // pmCPU only assigns numerical id's when a new varName is specified
1641 && (*varIndex
== kCPUUnknownIndex
))
1643 // pmCPUControl has assigned us a new variable ID.
1644 // Let's re-read the structure we just SET to learn that ID.
1645 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
1649 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
1650 *varIndex
= varInfoStruct
.varID
;
1659 //******************************************************************************
1660 // systemPowerEventOccurred
1662 // The power controller is notifying us of a hardware-related power management
1663 // event that we must handle.
1665 // systemPowerEventOccurred covers the same functionality that receivePowerNotification
1666 // does; it simply provides a richer API for conveying more information.
1667 //******************************************************************************
1668 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
1669 const OSSymbol
*event
,
1672 IOReturn attempt
= kIOReturnSuccess
;
1673 OSNumber
*newNumber
= NULL
;
1676 return kIOReturnBadArgument
;
1678 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
1680 return kIOReturnInternalError
;
1682 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
1684 newNumber
->release();
1689 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
1690 const OSSymbol
*event
,
1693 OSDictionary
*thermalsDict
= NULL
;
1694 bool shouldUpdate
= true;
1696 if (!event
|| !value
)
1697 return kIOReturnBadArgument
;
1700 // We reuse featuresDict Lock because it already exists and guards
1701 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
1702 // of stepping on that lock.
1703 if (featuresDictLock
) IOLockLock(featuresDictLock
);
1705 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
1707 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
1708 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
1710 thermalsDict
= OSDictionary::withCapacity(1);
1713 if (!thermalsDict
) {
1714 shouldUpdate
= false;
1718 thermalsDict
->setObject (event
, value
);
1720 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
1722 thermalsDict
->release();
1726 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
1729 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
1731 return kIOReturnSuccess
;
1735 //******************************************************************************
1736 // receivePowerNotification
1738 // The power controller is notifying us of a hardware-related power management
1739 // event that we must handle. This may be a result of an 'environment' interrupt from
1740 // the power mgt micro.
1741 //******************************************************************************
1743 IOReturn
IOPMrootDomain::receivePowerNotification (UInt32 msg
)
1745 bool eval_clamshell
= false;
1748 * Local (IOPMrootDomain only) eval clamshell command
1750 if (msg
& kLocalEvalClamshellCommand
)
1752 eval_clamshell
= true;
1758 if (msg
& kIOPMOverTemp
)
1760 IOLog("PowerManagement emergency overtemp signal. Going to sleep!");
1762 privateSleepSystem (kIOPMThermalEmergencySleepKey
);
1766 * PMU Processor Speed Change
1768 if (msg
& kIOPMProcessorSpeedChange
)
1770 IOService
*pmu
= waitForService(serviceMatching("ApplePMU"));
1771 pmu
->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
1772 getPlatform()->sleepKernel();
1773 pmu
->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
1779 if (msg
& kIOPMSleepNow
)
1781 privateSleepSystem (kIOPMSoftwareSleepKey
);
1787 if (msg
& kIOPMPowerEmergency
)
1789 privateSleepSystem (kIOPMLowPowerSleepKey
);
1796 if (msg
& kIOPMClamshellOpened
)
1798 // Received clamshel open message from clamshell controlling driver
1799 // Update our internal state and tell general interest clients
1800 clamshellIsClosed
= false;
1801 clamshellExists
= true;
1804 informCPUStateChange(kInformLid
, 0);
1806 // Tell general interest clients
1807 sendClientClamshellNotification();
1812 * Send the clamshell interest notification since the lid is closing.
1814 if (msg
& kIOPMClamshellClosed
)
1816 // Received clamshel open message from clamshell controlling driver
1817 // Update our internal state and tell general interest clients
1818 clamshellIsClosed
= true;
1819 clamshellExists
= true;
1822 informCPUStateChange(kInformLid
, 1);
1824 // Tell general interest clients
1825 sendClientClamshellNotification();
1827 // And set eval_clamshell = so we can attempt
1828 eval_clamshell
= true;
1832 * Set Desktop mode (sent from graphics)
1834 * -> reevaluate lid state
1836 if (msg
& kIOPMSetDesktopMode
)
1838 desktopMode
= (0 != (msg
& kIOPMSetValue
));
1839 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
1841 sendClientClamshellNotification();
1843 // Re-evaluate the lid state
1844 if( clamshellIsClosed
)
1846 eval_clamshell
= true;
1851 * AC Adaptor connected
1853 * -> reevaluate lid state
1855 if (msg
& kIOPMSetACAdaptorConnected
)
1857 acAdaptorConnect
= (0 != (msg
& kIOPMSetValue
));
1858 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
1861 informCPUStateChange(kInformAC
, !acAdaptorConnect
);
1863 sendClientClamshellNotification();
1865 // Re-evaluate the lid state
1866 if( clamshellIsClosed
)
1868 eval_clamshell
= true;
1874 * Enable Clamshell (external display disappear)
1876 * -> reevaluate lid state
1878 if (msg
& kIOPMEnableClamshell
)
1880 // Re-evaluate the lid state
1881 // System should sleep on external display disappearance
1882 // in lid closed operation.
1883 if( clamshellIsClosed
&& (true == ignoringClamshell
) )
1885 eval_clamshell
= true;
1888 ignoringClamshell
= false;
1890 sendClientClamshellNotification();
1894 * Disable Clamshell (external display appeared)
1895 * We don't bother re-evaluating clamshell state. If the system is awake,
1896 * the lid is probably open.
1898 if (msg
& kIOPMDisableClamshell
)
1900 ignoringClamshell
= true;
1902 sendClientClamshellNotification();
1906 * Evaluate clamshell and SLEEP if appropiate
1908 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
1913 privateSleepSystem (kIOPMClamshellSleepKey
);
1919 if (msg
& kIOPMPowerButton
)
1921 // toggle state of sleep/wake
1923 if ( getPowerState() == DOZE_STATE
)
1925 // yes, tell the tree we're waking
1927 // wake the Display Wrangler
1931 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
1932 // Check that power button sleep is enabled
1934 if( kOSBooleanTrue
!= getProperty(pbs
))
1935 privateSleepSystem (kIOPMPowerButtonSleepKey
);
1944 if ( (msg
& kIOPMAllowSleep
) && !allowSleep
)
1954 if (msg
& kIOPMPreventSleep
) {
1957 if ( getPowerState() == DOZE_STATE
) {
1958 // yes, tell the tree we're waking
1961 // wake the Display Wrangler
1965 // make sure we have power to clamp
1966 patriarch
->wakeSystem();
1974 //*********************************************************************************
1977 //*********************************************************************************
1979 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
1981 if ( flags
& kPCICantSleep
)
1986 platformSleepSupport
= flags
;
1989 setProperty(kIOSleepSupportedKey
, canSleep
);
1993 //*********************************************************************************
1994 // requestPowerDomainState
1996 // The root domain intercepts this call to the superclass.
1997 // Called on the PM work loop thread.
1999 // If the clamp bit is not set in the desire, then the child doesn't need the power
2000 // state it's requesting; it just wants it. The root ignores desires but not needs.
2001 // If the clamp bit is not set, the root takes it that the child can tolerate no
2002 // power and interprets the request accordingly. If all children can thus tolerate
2003 // no power, we are on our way to idle sleep.
2004 //*********************************************************************************
2006 IOReturn
IOPMrootDomain::requestPowerDomainState (
2007 IOPMPowerFlags desiredState
,
2008 IOPowerConnection
* whichChild
,
2009 unsigned long specification
)
2013 IOPowerConnection
*connection
;
2014 unsigned long powerRequestFlag
= 0;
2015 IOPMPowerFlags editedDesire
;
2018 IOService
*powerChild
;
2019 powerChild
= (IOService
*) whichChild
->getChildEntry(gIOPowerPlane
);
2022 DEBUG_LOG("RequestPowerDomainState: flags %lx, child %p [%s], spec %lx\n",
2023 desiredState
, powerChild
, powerChild
? powerChild
->getName() : "?",
2026 // Force the child's input power requirements to 0 unless the prevent
2027 // idle-sleep flag is set. No input power flags map to our state 0.
2028 // Our power clamp (deviceDesire) keeps the minimum power state at 2.
2030 if (desiredState
& kIOPMPreventIdleSleep
)
2031 editedDesire
= desiredState
;
2035 // Recompute sleep supported flag (doze if not supported)
2036 sleepIsSupported
= true;
2038 iter
= getChildIterator(gIOPowerPlane
);
2041 while ( (next
= iter
->getNextObject()) )
2043 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
2045 // Ignore child that are in the process of joining.
2046 if (connection
->getReadyFlag() == false)
2049 // Is this connection attached to the child that called
2050 // requestPowerDomainState()?
2052 if ( connection
== whichChild
)
2054 // Yes, OR in the child's input power requirements.
2055 powerRequestFlag
|= editedDesire
;
2057 if ( desiredState
& kIOPMPreventSystemSleep
)
2058 sleepIsSupported
= false;
2063 powerChild
= (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
2065 DEBUG_LOG(" child %p, PState %ld, noIdle %d, noSleep %d, valid %d %s\n",
2067 connection
->getDesiredDomainState(),
2068 connection
->getPreventIdleSleepFlag(),
2069 connection
->getPreventSystemSleepFlag(),
2070 connection
->getReadyFlag(),
2071 powerChild
? powerChild
->getName() : "?");
2073 // No, OR in the child's desired power domain state.
2074 // Which is our power state desired by this child.
2075 powerRequestFlag
|= connection
->getDesiredDomainState();
2077 if ( connection
->getPreventSystemSleepFlag() )
2078 sleepIsSupported
= false;
2085 if ( !powerRequestFlag
&& !systemBooting
)
2090 changePowerStateToPriv(ON_STATE
);
2093 AbsoluteTime deadline
;
2094 // stay awake for at least idleSeconds
2095 clock_interval_to_deadline(idleSeconds
, kSecondScale
, &deadline
);
2096 thread_call_enter_delayed(extraSleepTimer
, deadline
);
2097 // this gets turned off when we sleep again
2098 idleSleepPending
= true;
2101 else if (extraSleepDelay
== 0)
2107 DEBUG_LOG(" sleepDelay %lx, mergedFlags %lx, sleepASAP %x, booting %x\n",
2108 extraSleepDelay
, powerRequestFlag
, sleepASAP
, systemBooting
);
2110 // Drop our power clamp to SLEEP_STATE when all devices become idle.
2111 // Needed when the system sleep and display sleep timeouts are the same.
2112 // Otherwise, the extra sleep timer will also drop our power clamp.
2116 editedDesire
|= (desiredState
& kIOPMPreventSystemSleep
);
2118 // If our power clamp has already dropped to SLEEP_STATE, and no child
2119 // is keeping us at max power, then this will trigger idle sleep.
2121 return super::requestPowerDomainState(editedDesire
, whichChild
, specification
);
2125 //*********************************************************************************
2126 // getSleepSupported
2128 //*********************************************************************************
2130 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
2132 return( platformSleepSupport
);
2136 //*********************************************************************************
2137 // handlePlatformHaltRestart
2139 //*********************************************************************************
2141 struct HaltRestartApplierContext
{
2142 IOPMrootDomain
* RootDomain
;
2143 unsigned long PowerState
;
2144 IOPMPowerFlags PowerFlags
;
2150 platformHaltRestartApplier( OSObject
* object
, void * context
)
2152 IOPowerStateChangeNotification notify
;
2153 HaltRestartApplierContext
* ctx
;
2154 AbsoluteTime startTime
;
2157 ctx
= (HaltRestartApplierContext
*) context
;
2159 memset(¬ify
, 0, sizeof(notify
));
2160 notify
.powerRef
= (void *)ctx
->Counter
;
2161 notify
.returnValue
= 0;
2162 notify
.stateNumber
= ctx
->PowerState
;
2163 notify
.stateFlags
= ctx
->PowerFlags
;
2165 clock_get_uptime(&startTime
);
2166 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
2167 deltaTime
= computeDeltaTimeMS(&startTime
);
2169 if ((deltaTime
> kPMHaltTimeoutMS
) || (gIOKitDebug
& kIOLogDebugPower
))
2171 _IOServiceInterestNotifier
* notifier
;
2172 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
2174 // IOService children of IOPMrootDomain are not instrumented.
2175 // Only IORootParent currently falls under that group.
2179 HaltRestartLog("%s handler %p took %lu ms\n",
2180 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ?
2181 "PowerOff" : "Restart",
2182 notifier
->handler
, deltaTime
);
2189 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
2191 HaltRestartApplierContext ctx
;
2192 AbsoluteTime startTime
;
2195 memset(&ctx
, 0, sizeof(ctx
));
2196 ctx
.RootDomain
= this;
2198 clock_get_uptime(&startTime
);
2202 ctx
.PowerState
= OFF_STATE
;
2203 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
2207 ctx
.PowerState
= RESTART_STATE
;
2208 ctx
.MessageType
= kIOMessageSystemWillRestart
;
2215 // Notify legacy clients
2216 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
2218 // Notify in power tree order
2219 notifySystemShutdown(this, ctx
.MessageType
);
2221 deltaTime
= computeDeltaTimeMS(&startTime
);
2222 HaltRestartLog("%s all drivers took %lu ms\n",
2223 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ?
2224 "PowerOff" : "Restart",
2229 //*********************************************************************************
2232 // We override the superclass implementation so we can send a different message
2233 // type to the client or application being notified.
2234 //*********************************************************************************
2236 bool IOPMrootDomain::tellChangeDown ( unsigned long stateNum
)
2238 switch ( stateNum
) {
2242 // Direct callout into OSMetaClass so it can disable kmod unloads
2243 // during sleep/wake to prevent deadlocks.
2244 OSMetaClassSystemSleepOrWake( kIOMessageSystemWillSleep
);
2246 return super::tellClientsWithResponse(kIOMessageSystemWillSleep
);
2248 return super::tellChangeDown(stateNum
);
2252 //*********************************************************************************
2255 // We override the superclass implementation so we can send a different message
2256 // type to the client or application being notified.
2258 // This must be idle sleep since we don't ask apps during any other power change.
2259 //*********************************************************************************
2261 bool IOPMrootDomain::askChangeDown ( unsigned long )
2263 return super::tellClientsWithResponse(kIOMessageCanSystemSleep
);
2267 //*********************************************************************************
2270 // Notify registered applications and kernel clients that we are not
2273 // We override the superclass implementation so we can send a different message
2274 // type to the client or application being notified.
2276 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2277 //*********************************************************************************
2279 void IOPMrootDomain::tellNoChangeDown ( unsigned long )
2281 if (idleSeconds
&& !wrangler
)
2283 AbsoluteTime deadline
;
2285 // stay awake for at least idleSeconds
2286 clock_interval_to_deadline(idleSeconds
, kSecondScale
, &deadline
);
2287 thread_call_enter_delayed(extraSleepTimer
, deadline
);
2288 // this gets turned off when we sleep again
2289 idleSleepPending
= true;
2291 return tellClients(kIOMessageSystemWillNotSleep
);
2295 //*********************************************************************************
2298 // Notify registered applications and kernel clients that we are raising power.
2300 // We override the superclass implementation so we can send a different message
2301 // type to the client or application being notified.
2302 //*********************************************************************************
2304 void IOPMrootDomain::tellChangeUp ( unsigned long stateNum
)
2306 if ( stateNum
== ON_STATE
)
2309 // Direct callout into OSMetaClass so it can disable kmod unloads
2310 // during sleep/wake to prevent deadlocks.
2311 OSMetaClassSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2313 IOHibernateSystemPostWake();
2315 return tellClients(kIOMessageSystemHasPoweredOn
);
2319 //*********************************************************************************
2322 //*********************************************************************************
2324 void IOPMrootDomain::reportUserInput ( void )
2331 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
2334 wrangler
= (IOService
*) iter
->getNextObject();
2340 wrangler
->activityTickle(0,0);
2344 //*********************************************************************************
2345 // setQuickSpinDownTimeout
2347 //*********************************************************************************
2349 void IOPMrootDomain::setQuickSpinDownTimeout ( void )
2351 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown
,(unsigned long)1);
2354 //*********************************************************************************
2355 // restoreUserSpinDownTimeout
2357 //*********************************************************************************
2359 void IOPMrootDomain::restoreUserSpinDownTimeout ( void )
2361 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown
,(unsigned long)user_spindown
);
2364 //*********************************************************************************
2365 // changePowerStateTo & changePowerStateToPriv
2367 // Override of these methods for logging purposes.
2368 //*********************************************************************************
2370 IOReturn
IOPMrootDomain::changePowerStateTo ( unsigned long ordinal
)
2372 return super::changePowerStateTo(ordinal
);
2375 IOReturn
IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal
)
2379 DEBUG_LOG("ChangePowerStateToPriv: power state %ld\n", ordinal
);
2381 if ( (getPowerState() == DOZE_STATE
) && (ordinal
!= ON_STATE
) )
2383 return kIOReturnSuccess
;
2386 if( (userDisabledAllSleep
|| systemBooting
|| systemShutdown
)
2387 && (ordinal
== SLEEP_STATE
) )
2389 DEBUG_LOG(" sleep denied: disableAllSleep %d, booting %d, shutdown %d\n",
2390 userDisabledAllSleep
, systemBooting
, systemShutdown
);
2391 super::changePowerStateToPriv(ON_STATE
);
2394 if( (SLEEP_STATE
== ordinal
) && sleepSupportedPEFunction
)
2397 // Determine if the machine supports sleep, or must doze.
2398 ret
= getPlatform()->callPlatformFunction(
2399 sleepSupportedPEFunction
, false,
2400 NULL
, NULL
, NULL
, NULL
);
2402 // If the machine only supports doze, the callPlatformFunction call
2403 // boils down to IOPMrootDomain::setSleepSupported(kPCICantSleep),
2404 // otherwise nothing.
2407 return super::changePowerStateToPriv(ordinal
);
2411 //*********************************************************************************
2412 // sysPowerDownHandler
2414 // Receives a notification when the RootDomain changes state.
2416 // Allows us to take action on system sleep, power down, and restart after
2417 // applications have received their power change notifications and replied,
2418 // but before drivers have powered down. We perform a vfs sync on power down.
2419 //*********************************************************************************
2421 IOReturn
IOPMrootDomain::sysPowerDownHandler( void * target
, void * refCon
,
2422 UInt32 messageType
, IOService
* service
,
2423 void * messageArgument
, vm_size_t argSize
)
2426 IOPowerStateChangeNotification
*params
= (IOPowerStateChangeNotification
*) messageArgument
;
2427 IOPMrootDomain
*rootDomain
= OSDynamicCast(IOPMrootDomain
, service
);
2430 return kIOReturnUnsupported
;
2432 switch (messageType
) {
2433 case kIOMessageSystemWillSleep
:
2434 DEBUG_LOG("SystemWillSleep\n");
2436 // Interested applications have been notified of an impending power
2437 // change and have acked (when applicable).
2438 // This is our chance to save whatever state we can before powering
2440 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2443 // We will ack within 20 seconds
2444 params
->returnValue
= 20 * 1000 * 1000;
2446 if (gIOHibernateState
)
2447 params
->returnValue
+= gIOHibernateFreeTime
* 1000; //add in time we could spend freeing pages
2450 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2452 // Purposely delay the ack and hope that shutdown occurs quickly.
2453 // Another option is not to schedule the thread and wait for
2455 AbsoluteTime deadline
;
2456 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2457 thread_call_enter1_delayed( rootDomain
->diskSyncCalloutEntry
,
2458 (thread_call_param_t
)params
->powerRef
,
2462 thread_call_enter1(rootDomain
->diskSyncCalloutEntry
, (thread_call_param_t
)params
->powerRef
);
2463 ret
= kIOReturnSuccess
;
2466 case kIOMessageSystemWillPowerOff
:
2467 case kIOMessageSystemWillRestart
:
2468 ret
= kIOReturnUnsupported
;
2472 ret
= kIOReturnUnsupported
;
2478 //*********************************************************************************
2479 // displayWranglerNotification
2481 // Receives a notification when the IODisplayWrangler changes state.
2483 // Allows us to take action on display dim/undim.
2485 // When the display sleeps we:
2486 // - Start the idle sleep timer
2487 // - set the quick spin down timeout
2489 // On wake from display sleep:
2490 // - Cancel the idle sleep timer
2491 // - restore the user's chosen spindown timer from the "quick" spin down value
2492 //*********************************************************************************
2494 IOReturn
IOPMrootDomain::displayWranglerNotification(
2495 void * target
, void * refCon
,
2496 UInt32 messageType
, IOService
* service
,
2497 void * messageArgument
, vm_size_t argSize
)
2500 IOPMrootDomain
* rootDomain
= OSDynamicCast(IOPMrootDomain
, (IOService
*)target
);
2501 AbsoluteTime deadline
;
2502 static int displayPowerState
= 4;
2505 return kIOReturnUnsupported
;
2507 switch (messageType
) {
2508 case kIOMessageDeviceWillPowerOff
:
2509 DEBUG_LOG("DisplayWranglerWillPowerOff: new p-state %d\n",
2510 displayPowerState
- 1);
2512 // The display wrangler has dropped power because of idle display sleep
2513 // or force system sleep. We will receive 4 messages before the display
2514 // wrangler reaches its lowest state. Act only when going to state 2.
2517 // 3->2 Display Sleep
2518 // 2->1 Not visible to user
2519 // 1->0 Not visible to user
2521 displayPowerState
--;
2522 if ( 2 != displayPowerState
)
2523 return kIOReturnUnsupported
;
2525 // We start a timer here if the System Sleep timer is greater than the
2526 // Display Sleep timer. We kick off this timer when the display sleeps.
2528 // Note that, although Display Dim timings may change adaptively accordingly
2529 // to the user's activity patterns, Display Sleep _always_ occurs at the
2530 // specified interval since last user activity.
2532 if ( rootDomain
->extraSleepDelay
)
2534 clock_interval_to_deadline(rootDomain
->extraSleepDelay
*60, kSecondScale
, &deadline
);
2535 thread_call_enter_delayed(rootDomain
->extraSleepTimer
, deadline
);
2536 rootDomain
->idleSleepPending
= true;
2537 DEBUG_LOG(" sleep timer set to expire in %ld min\n",
2538 rootDomain
->extraSleepDelay
);
2540 // Accelerate disk spindown if system sleep and display sleep
2541 // sliders are set to the same value (e.g. both set to 5 min),
2542 // and display is about to go dark. Check that spin down timer
2543 // is non-zero (zero = never spin down) and system sleep is
2544 // not set to never sleep.
2546 if ( (0 != rootDomain
->user_spindown
) && (0 != rootDomain
->sleepSlider
) )
2548 DEBUG_LOG(" accelerate quick disk spindown, was %d min\n",
2549 rootDomain
->user_spindown
);
2550 rootDomain
->setQuickSpinDownTimeout();
2556 case kIOMessageDeviceHasPoweredOn
:
2557 DEBUG_LOG("DisplayWranglerHasPoweredOn: previous p-state %d\n",
2560 // The display wrangler has powered on either because of user activity
2561 // or wake from sleep/doze.
2563 displayPowerState
= 4;
2564 rootDomain
->adjustPowerState();
2566 // cancel any pending idle sleep timers
2567 if (rootDomain
->idleSleepPending
)
2569 DEBUG_LOG(" extra-sleep timer stopped\n");
2570 thread_call_cancel(rootDomain
->extraSleepTimer
);
2571 rootDomain
->idleSleepPending
= false;
2574 // Change the spindown value back to the user's selection from our
2575 // accelerated setting.
2576 if (0 != rootDomain
->user_spindown
)
2578 DEBUG_LOG(" restoring disk spindown to %d min\n",
2579 rootDomain
->user_spindown
);
2580 rootDomain
->restoreUserSpinDownTimeout();
2589 return kIOReturnUnsupported
;
2592 //*********************************************************************************
2593 // displayWranglerPublished
2595 // Receives a notification when the IODisplayWrangler is published.
2596 // When it's published we install a power state change handler.
2598 //*********************************************************************************
2600 bool IOPMrootDomain::displayWranglerPublished(
2603 IOService
* newService
)
2606 IOPMrootDomain
*rootDomain
=
2607 OSDynamicCast(IOPMrootDomain
, (IOService
*)target
);
2612 rootDomain
->wrangler
= newService
;
2614 // we found the display wrangler, now install a handler
2615 if( !rootDomain
->wrangler
->registerInterest( gIOGeneralInterest
,
2616 &displayWranglerNotification
, target
, 0) )
2624 //*********************************************************************************
2627 // Notification on battery class IOPowerSource appearance
2629 //******************************************************************************
2631 bool IOPMrootDomain::batteryPublished(
2634 IOService
* resourceService
)
2636 // rdar://2936060&4435589
2637 // All laptops have dimmable LCD displays
2638 // All laptops have batteries
2639 // So if this machine has a battery, publish the fact that the backlight
2640 // supports dimming.
2641 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
2646 //*********************************************************************************
2649 // Some condition that affects our wake/sleep/doze decision has changed.
2651 // If the sleep slider is in the off position, we cannot sleep or doze.
2652 // If the enclosure is open, we cannot sleep or doze.
2653 // If the system is still booting, we cannot sleep or doze.
2655 // In those circumstances, we prevent sleep and doze by holding power on with
2656 // changePowerStateToPriv(ON).
2658 // If the above conditions do not exist, and also the sleep timer has expired, we
2659 // allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
2660 // changePowerStateToPriv(DOZE) depending on whether or not we already know the
2661 // platform cannot sleep.
2663 // In this case, sleep or doze will either occur immediately or at the next time
2664 // that no children are holding the system out of idle sleep via the
2665 // kIOPMPreventIdleSleep flag in their power state arrays.
2666 //*********************************************************************************
2668 void IOPMrootDomain::adjustPowerState( void )
2670 if ( (sleepSlider
== 0)
2674 || userDisabledAllSleep
)
2676 DEBUG_LOG("AdjustPowerState %ld -> ON: slider %ld, allowSleep %d, "
2677 "booting %d, shutdown %d, userDisabled %d\n",
2678 getPowerState(), sleepSlider
, allowSleep
, systemBooting
,
2679 systemShutdown
, userDisabledAllSleep
);
2681 changePowerStateToPriv(ON_STATE
);
2685 DEBUG_LOG("AdjustPowerState SLEEP\n");
2687 /* Convenient place to run any code at idle sleep time
2688 * IOPMrootDomain initiates an idle sleep here
2690 * Set last sleep cause accordingly.
2692 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
2695 if ( !sleepIsSupported
)
2697 setSleepSupported( kPCICantSleep
);
2698 kprintf("Sleep prevented by kIOPMPreventSystemSleep flag\n");
2700 changePowerStateToPriv(SLEEP_STATE
);
2705 //*********************************************************************************
2706 // PMHaltWorker Class
2708 //*********************************************************************************
2710 static unsigned int gPMHaltBusyCount
;
2711 static unsigned int gPMHaltIdleCount
;
2712 static int gPMHaltDepth
;
2713 static unsigned long gPMHaltEvent
;
2714 static IOLock
* gPMHaltLock
= 0;
2715 static OSArray
* gPMHaltArray
= 0;
2716 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
2718 PMHaltWorker
* PMHaltWorker::worker( void )
2724 me
= OSTypeAlloc( PMHaltWorker
);
2725 if (!me
|| !me
->init())
2728 me
->lock
= IOLockAlloc();
2732 DEBUG_LOG("PMHaltWorker %p\n", me
);
2733 me
->retain(); // thread holds extra retain
2734 thread
= IOCreateThread( &PMHaltWorker::main
, me
);
2744 if (me
) me
->release();
2748 void PMHaltWorker::free( void )
2750 DEBUG_LOG("PMHaltWorker free %p\n", this);
2756 return OSObject::free();
2759 void PMHaltWorker::main( void * arg
)
2761 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
2763 IOLockLock( gPMHaltLock
);
2765 me
->depth
= gPMHaltDepth
;
2766 IOLockUnlock( gPMHaltLock
);
2768 while (me
->depth
>= 0)
2770 PMHaltWorker::work( me
);
2772 IOLockLock( gPMHaltLock
);
2773 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
2775 // This is the last thread to finish work on this level,
2776 // inform everyone to start working on next lower level.
2778 me
->depth
= gPMHaltDepth
;
2779 gPMHaltIdleCount
= 0;
2780 thread_wakeup((event_t
) &gPMHaltIdleCount
);
2784 // One or more threads are still working on this level,
2785 // this thread must wait.
2786 me
->depth
= gPMHaltDepth
- 1;
2788 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
2789 } while (me
->depth
!= gPMHaltDepth
);
2791 IOLockUnlock( gPMHaltLock
);
2794 // No more work to do, terminate thread
2795 DEBUG_LOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
2796 thread_wakeup( &gPMHaltDepth
);
2800 void PMHaltWorker::work( PMHaltWorker
* me
)
2802 IOService
* service
;
2804 AbsoluteTime startTime
;
2813 // Claim an unit of work from the shared pool
2814 IOLockLock( gPMHaltLock
);
2815 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
2818 service
= (IOService
*)inner
->getAnyObject();
2822 inner
->removeObject(service
);
2825 IOLockUnlock( gPMHaltLock
);
2827 break; // no more work at this depth
2829 clock_get_uptime(&startTime
);
2831 if (!service
->isInactive() &&
2832 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
2834 IOLockLock(me
->lock
);
2835 me
->startTime
= startTime
;
2836 me
->service
= service
;
2837 me
->timeout
= false;
2838 IOLockUnlock(me
->lock
);
2840 service
->systemWillShutdown( gPMHaltEvent
);
2842 // Wait for driver acknowledgement
2843 IOLockLock(me
->lock
);
2844 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
2846 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
2849 timeout
= me
->timeout
;
2850 IOLockUnlock(me
->lock
);
2853 deltaTime
= computeDeltaTimeMS(&startTime
);
2854 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
2855 (gIOKitDebug
& kIOLogDebugPower
))
2857 HaltRestartLog("%s driver %s (%p) took %lu ms\n",
2858 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
2859 "PowerOff" : "Restart",
2860 service
->getName(), service
,
2869 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
2872 AbsoluteTime startTime
;
2873 AbsoluteTime endTime
;
2877 IOLockLock(me
->lock
);
2878 if (me
->service
&& !me
->timeout
)
2880 startTime
= me
->startTime
;
2882 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
2884 SUB_ABSOLUTETIME(&endTime
, &startTime
);
2885 absolutetime_to_nanoseconds(endTime
, &nano
);
2887 if (nano
> 3000000000ULL)
2890 HaltRestartLog("%s still waiting on %s\n",
2891 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
2892 "PowerOff" : "Restart",
2893 me
->service
->getName());
2896 IOLockUnlock(me
->lock
);
2899 //*********************************************************************************
2900 // acknowledgeSystemWillShutdown
2902 // Acknowledgement from drivers that they have prepared for shutdown/restart.
2903 //*********************************************************************************
2905 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
2907 PMHaltWorker
* worker
;
2913 //DEBUG_LOG("%s acknowledged\n", from->getName());
2914 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
2917 worker
= (PMHaltWorker
*) prop
;
2918 IOLockLock(worker
->lock
);
2919 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
2920 thread_wakeup((event_t
) worker
);
2921 IOLockUnlock(worker
->lock
);
2926 DEBUG_LOG("%s acknowledged without worker property\n",
2931 //*********************************************************************************
2932 // notifySystemShutdown
2934 // Notify all objects in PM tree that system will shutdown or restart
2935 //*********************************************************************************
2938 notifySystemShutdown( IOService
* root
, unsigned long event
)
2940 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
2941 IORegistryIterator
* iter
;
2942 IORegistryEntry
* entry
;
2945 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
2946 AbsoluteTime deadline
;
2947 unsigned int totalNodes
= 0;
2949 unsigned int rootDepth
;
2950 unsigned int numWorkers
;
2956 DEBUG_LOG("%s event = %lx\n", __FUNCTION__
, event
);
2958 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
2960 // Iterate the entire PM tree starting from root
2962 rootDepth
= root
->getDepth( gIOPowerPlane
);
2963 if (!rootDepth
) goto done
;
2965 // debug - for repeated test runs
2966 while (PMHaltWorker::metaClass
->getInstanceCount())
2971 gPMHaltArray
= OSArray::withCapacity(40);
2972 if (!gPMHaltArray
) goto done
;
2975 gPMHaltArray
->flushCollection();
2979 gPMHaltLock
= IOLockAlloc();
2980 if (!gPMHaltLock
) goto done
;
2983 if (!gPMHaltClientAcknowledgeKey
)
2985 gPMHaltClientAcknowledgeKey
=
2986 OSSymbol::withCStringNoCopy("PMShutdown");
2987 if (!gPMHaltClientAcknowledgeKey
) goto done
;
2990 gPMHaltEvent
= event
;
2992 // Depth-first walk of PM plane
2994 iter
= IORegistryIterator::iterateOver(
2995 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
2999 while ((entry
= iter
->getNextObject()))
3001 node
= OSDynamicCast(IOService
, entry
);
3006 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
3009 depth
= node
->getDepth( gIOPowerPlane
);
3010 if (depth
<= rootDepth
)
3015 // adjust to zero based depth
3016 depth
-= (rootDepth
+ 1);
3018 // gPMHaltArray is an array of containers, each container
3019 // refers to nodes with the same depth.
3021 count
= gPMHaltArray
->getCount();
3022 while (depth
>= count
)
3024 // expand array and insert placeholders
3025 gPMHaltArray
->setObject(PLACEHOLDER
);
3028 count
= gPMHaltArray
->getCount();
3031 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
3032 if (inner
== PLACEHOLDER
)
3034 inner
= OSSet::withCapacity(40);
3037 gPMHaltArray
->replaceObject(depth
, inner
);
3042 // PM nodes that appear more than once in the tree will have
3043 // the same depth, OSSet will refuse to add the node twice.
3045 ok
= inner
->setObject(node
);
3048 DEBUG_LOG("Skipped PM node %s\n", node
->getName());
3054 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
3057 if (inner
!= PLACEHOLDER
)
3058 count
= inner
->getCount();
3059 DEBUG_LOG("Nodes at depth %u = %u\n", i
, count
);
3062 // strip placeholders (not all depths are populated)
3064 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
3066 if (inner
== PLACEHOLDER
)
3068 gPMHaltArray
->removeObject(i
);
3071 count
= inner
->getCount();
3072 if (count
> numWorkers
)
3074 totalNodes
+= count
;
3078 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
3081 gPMHaltBusyCount
= 0;
3082 gPMHaltIdleCount
= 0;
3083 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
3085 // Create multiple workers (and threads)
3087 if (numWorkers
> kPMHaltMaxWorkers
)
3088 numWorkers
= kPMHaltMaxWorkers
;
3090 DEBUG_LOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
3091 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
3093 for (unsigned int i
= 0; i
< numWorkers
; i
++)
3094 workers
[i
] = PMHaltWorker::worker();
3096 // Wait for workers to exhaust all available work
3098 IOLockLock(gPMHaltLock
);
3099 while (gPMHaltDepth
>= 0)
3101 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
3103 waitResult
= IOLockSleepDeadline(
3104 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
3105 if (THREAD_TIMED_OUT
== waitResult
)
3108 clock_get_uptime(&now
);
3110 IOLockUnlock(gPMHaltLock
);
3111 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
3114 PMHaltWorker::checkTimeout(workers
[i
], &now
);
3116 IOLockLock(gPMHaltLock
);
3119 IOLockUnlock(gPMHaltLock
);
3121 // Release all workers
3123 for (unsigned int i
= 0; i
< numWorkers
; i
++)
3126 workers
[i
]->release();
3127 // worker also retained by it's own thread
3131 DEBUG_LOG("%s done\n", __FUNCTION__
);
3136 // debug - exercise notifySystemShutdown()
3137 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
3139 IOPMrootDomain
* root
= (IOPMrootDomain
*) this;
3140 notifySystemShutdown( root
, kIOMessageSystemWillPowerOff
);
3141 return( super::serializeProperties(s
) );
3145 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3150 #define super OSObject
3151 OSDefineMetaClassAndStructors(PMSettingObject
, OSObject
)
3153 void PMSettingObject::setPMSetting(const OSSymbol
*type
, OSObject
*obj
)
3155 (*func
)(target
, type
, obj
, refcon
);
3159 * Static constructor/initializer for PMSettingObject
3161 PMSettingObject
*PMSettingObject::pmSettingObject(
3162 IOPMrootDomain
*parent_arg
,
3163 IOPMSettingControllerCallback handler_arg
,
3164 OSObject
*target_arg
,
3165 uintptr_t refcon_arg
,
3166 uint32_t supportedPowerSources
,
3167 const OSSymbol
* settings
[])
3169 uint32_t objCount
= 0;
3170 PMSettingObject
*pmso
;
3172 if( !parent_arg
|| !handler_arg
|| !settings
) return NULL
;
3174 // count OSSymbol entries in NULL terminated settings array
3175 while( settings
[objCount
] ) {
3178 if(0 == objCount
) return NULL
;
3180 pmso
= new PMSettingObject
;
3181 if(!pmso
|| !pmso
->init()) return NULL
;
3183 pmso
->parent
= parent_arg
;
3184 pmso
->func
= handler_arg
;
3185 pmso
->target
= target_arg
;
3186 pmso
->refcon
= refcon_arg
;
3187 pmso
->releaseAtCount
= objCount
+ 1; // release when it has count+1 retains
3189 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount
);
3190 if(pmso
->publishedFeatureID
) {
3191 for(unsigned int i
=0; i
<objCount
; i
++) {
3192 // Since there is now at least one listener to this setting, publish
3193 // PM root domain support for it.
3194 parent_arg
->publishFeature( settings
[i
]->getCStringNoCopy(),
3195 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
3202 void PMSettingObject::free(void)
3204 OSCollectionIterator
*settings_iter
;
3209 int objCount
= releaseAtCount
- 1;
3211 if(publishedFeatureID
) {
3212 for(i
=0; i
<objCount
; i
++) {
3213 if(0 != publishedFeatureID
[i
]) {
3214 parent
->removePublishedFeature( publishedFeatureID
[i
] );
3218 IOFree(publishedFeatureID
, sizeof(uint32_t) * objCount
);
3221 IORecursiveLockLock(parent
->settingsCtrlLock
);
3223 // Search each PM settings array in the kernel.
3224 settings_iter
= OSCollectionIterator::withCollection(parent
->settingsCallbacks
);
3227 while(( sym
= OSDynamicCast(OSSymbol
, settings_iter
->getNextObject()) ))
3229 arr
= (OSArray
*)parent
->settingsCallbacks
->getObject(sym
);
3230 arr_idx
= arr
->getNextIndexOfObject(this, 0);
3232 // 'this' was found in the array; remove it
3233 arr
->removeObject(arr_idx
);
3237 settings_iter
->release();
3240 IORecursiveLockUnlock(parent
->settingsCtrlLock
);
3245 void PMSettingObject::taggedRelease(const void *tag
, const int when
) const
3247 // We have n+1 retains - 1 per array that this PMSettingObject is a member
3248 // of, and 1 retain to ourself. When we get a release with n+1 retains
3249 // remaining, we go ahead and free ourselves, cleaning up array pointers
3252 super::taggedRelease(tag
, releaseAtCount
);
3257 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3260 #define super IOService
3262 OSDefineMetaClassAndStructors(IORootParent
, IOService
)
3264 // This array exactly parallels the state array for the root domain.
3265 // Power state changes initiated by a device can be vetoed by a client of the device, and
3266 // power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
3267 // so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
3268 // its parent to make the change. That is the reason for this complexity.
3270 static IOPMPowerState patriarchPowerStates
[number_of_power_states
] = {
3271 {1,0,0,0,0,0,0,0,0,0,0,0}, // off
3272 {1,0,RESTART_POWER
,0,0,0,0,0,0,0,0,0}, // reset
3273 {1,0,SLEEP_POWER
,0,0,0,0,0,0,0,0,0}, // sleep
3274 {1,0,DOZE_POWER
,0,0,0,0,0,0,0,0,0}, // doze
3275 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0} // running
3278 bool IORootParent::start ( IOService
* nub
)
3280 mostRecentChange
= ON_STATE
;
3284 registerPowerDriver(this,patriarchPowerStates
,number_of_power_states
);
3286 powerOverrideOnPriv();
3291 void IORootParent::shutDownSystem ( void )
3293 mostRecentChange
= OFF_STATE
;
3294 changePowerStateToPriv(OFF_STATE
);
3298 void IORootParent::restartSystem ( void )
3300 mostRecentChange
= RESTART_STATE
;
3301 changePowerStateToPriv(RESTART_STATE
);
3305 void IORootParent::sleepSystem ( void )
3307 mostRecentChange
= SLEEP_STATE
;
3308 changePowerStateToPriv(SLEEP_STATE
);
3312 void IORootParent::dozeSystem ( void )
3314 mostRecentChange
= DOZE_STATE
;
3315 changePowerStateToPriv(DOZE_STATE
);
3318 // Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
3319 // This brings the parent to doze, which allows the root to step up from sleep to doze.
3321 // In idle sleep, do nothing because the parent is still on and the root can freely change state.
3323 void IORootParent::sleepToDoze ( void )
3325 if ( mostRecentChange
== SLEEP_STATE
) {
3326 changePowerStateToPriv(DOZE_STATE
);
3331 void IORootParent::wakeSystem ( void )
3333 mostRecentChange
= ON_STATE
;
3334 changePowerStateToPriv(ON_STATE
);
3337 IOReturn
IORootParent::changePowerStateToPriv ( unsigned long ordinal
)
3341 if( (SLEEP_STATE
== ordinal
) && sleepSupportedPEFunction
)
3344 // Determine if the machine supports sleep, or must doze.
3345 ret
= getPlatform()->callPlatformFunction(
3346 sleepSupportedPEFunction
, false,
3347 NULL
, NULL
, NULL
, NULL
);
3349 // If the machine only supports doze, the callPlatformFunction call
3350 // boils down toIOPMrootDomain::setSleepSupported(kPCICantSleep),
3351 // otherwise nothing.
3354 return super::changePowerStateToPriv(ordinal
);