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>
43 #include <IOKit/IOHibernatePrivate.h>
44 #include "IOPMWorkArbiter.h"
51 IOReturn
OSMetaClassSystemSleepOrWake( UInt32
);
54 extern const IORegistryPlane
* gIOPowerPlane
;
56 IOReturn
broadcast_aggressiveness ( OSObject
*, void *, void *, void *, void * );
57 static void sleepTimerExpired(thread_call_param_t
);
58 static void wakeupClamshellTimerExpired ( thread_call_param_t us
);
60 // "IOPMSetSleepSupported" callPlatformFunction name
61 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
63 #define kIOSleepSupportedKey "IOSleepSupported"
65 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
66 | kIOPMSupportedOnBatt \
67 | kIOPMSupportedOnUPS)
69 #define number_of_power_states 5
71 #define RESTART_STATE 1
76 #define ON_POWER kIOPMPowerOn
77 #define RESTART_POWER kIOPMRestart
78 #define SLEEP_POWER kIOPMAuxPowerOn
79 #define DOZE_POWER kIOPMDoze
81 #define kLocalEvalClamshellCommand (1 << 15)
83 static IOPMPowerState ourPowerStates
[number_of_power_states
] = {
85 {1,0, 0, 0,0,0,0,0,0,0,0,0},
87 {1,kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
,0,0,0,0,0,0,0,0},
89 {1,kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
,0,0,0,0,0,0,0,0},
91 {1,kIOPMDoze
, kIOPMDoze
, DOZE_POWER
,0,0,0,0,0,0,0,0},
93 {1,kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
,0,0,0,0,0,0,0,0},
96 static IOPMrootDomain
* gRootDomain
;
97 static UInt32 gSleepOrShutdownPending
= 0;
100 class PMSettingObject
: public OSObject
102 OSDeclareDefaultStructors(PMSettingObject
)
104 IOPMrootDomain
*parent
;
105 IOPMSettingControllerCallback func
;
108 uint32_t *publishedFeatureID
;
111 static PMSettingObject
*pmSettingObject(
112 IOPMrootDomain
*parent_arg
,
113 IOPMSettingControllerCallback handler_arg
,
114 OSObject
*target_arg
,
115 uintptr_t refcon_arg
,
116 uint32_t supportedPowerSources
,
117 const OSSymbol
*settings
[]);
119 void setPMSetting(const OSSymbol
*type
, OSObject
*obj
);
121 void taggedRelease(const void *tag
, const int when
) const;
127 #define super IOService
128 OSDefineMetaClassAndStructors(IOPMrootDomain
,IOService
)
132 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
134 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
137 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
139 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
142 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
144 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
147 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
149 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
152 IOReturn
rootDomainRestart ( void )
154 return gRootDomain
->restartSystem();
157 IOReturn
rootDomainShutdown ( void )
159 return gRootDomain
->shutdownSystem();
162 void IOSystemShutdownNotification ( void )
164 IOCatalogue::disableExternalLinker();
165 for ( int i
= 0; i
< 100; i
++ )
167 if ( OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) ) break;
172 int sync_internal(void);
176 A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain
177 children it has, but within the constraint of the power state provided by its parent. The driver expresses its desire by
178 calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children
179 express their desires by calling requestPowerDomainState().
181 The Root Power Domain owns the policy for idle and demand sleep and doze for the system. It is a power-managed IOService just
182 like the others in the system. It implements several power states which correspond to what we see as Sleep, Doze, etc.
184 The sleep/doze policy is as follows:
185 Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards.
186 Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero.
187 The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep.
189 These three conditions are enforced using the "driver clamp" by calling changePowerStateTo(). For example, if the case is
190 opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or
191 the state of the other clamp.
193 Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item.
194 In this case the root's parent actually initiates the power state change so that the root has no choice and does not give
195 applications the opportunity to veto the change.
197 Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep. When this is true, the root's
198 children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE)
199 to hold itself on until the sleep timer expires. This timer is set for the difference between the sleep timeout slider and
200 the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel. For example, if
201 the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes,
202 when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root
203 sets its timer for 25 minutes (30 - 5). When the timer expires, it releases its clamp and now nothing is holding it awake,
206 Demand sleep is prevented when the system is booting. When preferences are transmitted by the loginwindow at the end of
207 boot, a flag is cleared, and this allows subsequent Demand Sleep.
209 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
210 a clamp, but sets a flag which is noticed before actually sleeping the kernel. If the flag is set, the root steps up
211 one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and
212 ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler
216 // **********************************************************************************
218 IOPMrootDomain
* IOPMrootDomain::construct( void )
220 IOPMrootDomain
*root
;
222 root
= new IOPMrootDomain
;
229 // **********************************************************************************
231 static void disk_sync_callout(thread_call_param_t p0
, thread_call_param_t p1
)
233 IOService
*rootDomain
= (IOService
*) p0
;
234 unsigned long pmRef
= (unsigned long) p1
;
236 IOHibernateSystemSleep();
238 rootDomain
->allowPowerChange(pmRef
);
241 // **********************************************************************************
242 IOPMWorkArbiter
*IOPMrootDomain::getPMArbiter(void)
248 // **********************************************************************************
251 // We don't do much here. The real initialization occurs when the platform
252 // expert informs us we are the root.
253 // **********************************************************************************
255 #define kRootDomainSettingsCount 12
257 bool IOPMrootDomain::start ( IOService
* nub
)
259 OSIterator
*psIterator
;
260 OSDictionary
*tmpDict
;
261 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
263 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
264 OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
),
265 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
266 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
),
267 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
268 OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
),
269 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
270 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
271 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
272 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
273 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
274 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
)
278 pmPowerStateQueue
= 0;
280 _reserved
= (ExpansionData
*)IOMalloc(sizeof(ExpansionData
));
281 if(!_reserved
) return false;
289 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
291 setProperty(kIOSleepSupportedKey
,true);
294 sleepIsSupported
= true;
295 systemBooting
= true;
297 idleSleepPending
= false;
300 clamshellIsClosed
= false;
301 clamshellExists
= false;
302 ignoringClamshell
= true;
303 ignoringClamshellDuringWakeup
= false;
304 acAdaptorConnect
= true;
306 tmpDict
= OSDictionary::withCapacity(1);
307 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
310 settingsCallbacks
= OSDictionary::withCapacity(1);
312 // Create a list of the valid PM settings that we'll relay to
313 // interested clients in setProperties() => setPMSetting()
314 allowedPMSettings
= OSArray::withObjects(
315 (const OSObject
**)settingsArr
,
316 kRootDomainSettingsCount
,
319 fPMSettingsDict
= OSDictionary::withCapacity(5);
321 pm_vars
->PMworkloop
= IOWorkLoop::workLoop();
322 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(this);
323 pm_vars
->PMworkloop
->addEventSource(pmPowerStateQueue
);
325 /* Initialize PM arbiter */
326 pmArbiter
= IOPMWorkArbiter::pmWorkArbiter(this);
327 arbiterWorkLoop
= IOWorkLoop::workLoop();
328 arbiterWorkLoop
->addEventSource(pmArbiter
);
330 featuresDictLock
= IOLockAlloc();
331 settingsCtrlLock
= IORecursiveLockAlloc();
333 extraSleepTimer
= thread_call_allocate(
334 (thread_call_func_t
)sleepTimerExpired
,
335 (thread_call_param_t
) this);
336 clamshellWakeupIgnore
= thread_call_allocate(
337 (thread_call_func_t
)wakeupClamshellTimerExpired
,
338 (thread_call_param_t
) this);
339 diskSyncCalloutEntry
= thread_call_allocate(
341 (thread_call_param_t
) this);
344 patriarch
= new IORootParent
;
346 patriarch
->attach(this);
347 patriarch
->start(this);
348 patriarch
->youAreRoot();
349 patriarch
->wakeSystem();
350 patriarch
->addPowerChild(this);
352 registerPowerDriver(this,ourPowerStates
,number_of_power_states
);
354 setPMRootDomain(this);
355 // set a clamp until we sleep
356 changePowerStateToPriv(ON_STATE
);
358 // install power change handler
359 registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
361 // Register for a notification when IODisplayWrangler is published
362 _displayWranglerNotifier
= addNotification(
363 gIOPublishNotification
, serviceMatching("IODisplayWrangler"),
364 &displayWranglerPublished
, this, 0);
366 // Battery location published - ApplePMU support only
367 _batteryPublishNotifier
= addNotification(
368 gIOPublishNotification
, serviceMatching("IOPMPowerSource"),
369 &batteryPublished
, this, this);
372 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
373 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
374 ucClassName
->release();
376 // IOBacklightDisplay can take a long time to load at boot, or it may
377 // not load at all if you're booting with clamshell closed. We publish
378 // 'DisplayDims' here redundantly to get it published early and at all.
379 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
380 if( psIterator
&& psIterator
->getNextObject() )
382 // There's at least one battery on the system, so we publish
383 // 'DisplayDims' support for the LCD.
384 publishFeature("DisplayDims");
387 psIterator
->release();
390 IOHibernateSystemInit(this);
392 registerService(); // let clients find us
397 // **********************************************************************************
400 // Receive a setProperty call
401 // The "System Boot" property means the system is completely booted.
402 // **********************************************************************************
403 IOReturn
IOPMrootDomain::setProperties ( OSObject
*props_obj
)
405 IOReturn return_value
= kIOReturnSuccess
;
406 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
414 const OSSymbol
*boot_complete_string
=
415 OSSymbol::withCString("System Boot Complete");
416 const OSSymbol
*sys_shutdown_string
=
417 OSSymbol::withCString("System Shutdown");
418 const OSSymbol
*stall_halt_string
=
419 OSSymbol::withCString("StallSystemAtHalt");
420 const OSSymbol
*hibernatemode_string
=
421 OSSymbol::withCString(kIOHibernateModeKey
);
422 const OSSymbol
*hibernatefile_string
=
423 OSSymbol::withCString(kIOHibernateFileKey
);
424 const OSSymbol
*hibernatefreeratio_string
=
425 OSSymbol::withCString(kIOHibernateFreeRatioKey
);
426 const OSSymbol
*hibernatefreetime_string
=
427 OSSymbol::withCString(kIOHibernateFreeTimeKey
);
431 return_value
= kIOReturnBadArgument
;
436 && boot_complete_string
437 && dict
->getObject(boot_complete_string
))
439 systemBooting
= false;
442 // If lid is closed, re-send lid closed notification
443 // now that booting is complete.
444 if( clamshellIsClosed
)
446 this->receivePowerNotification(kLocalEvalClamshellCommand
);
450 if( sys_shutdown_string
451 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sys_shutdown_string
))))
454 if(kOSBooleanTrue
== b
)
456 /* We set systemShutdown = true during shutdown
457 to prevent sleep at unexpected times while loginwindow is trying
458 to shutdown apps and while the OS is trying to transition to
461 Set to true during shutdown, as soon as loginwindow shows
462 the "shutdown countdown dialog", through individual app
463 termination, and through black screen kernel shutdown.
465 kprintf("systemShutdown true\n");
466 systemShutdown
= true;
469 A shutdown was initiated, but then the shutdown
470 was cancelled, clearing systemShutdown to false here.
472 kprintf("systemShutdown false\n");
473 systemShutdown
= false;
477 if( stall_halt_string
478 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(stall_halt_string
))) )
480 setProperty(stall_halt_string
, b
);
483 if ( hibernatemode_string
484 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatemode_string
))))
486 setProperty(hibernatemode_string
, n
);
488 if ( hibernatefreeratio_string
489 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreeratio_string
))))
491 setProperty(hibernatefreeratio_string
, n
);
493 if ( hibernatefreetime_string
494 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreetime_string
))))
496 setProperty(hibernatefreetime_string
, n
);
498 if ( hibernatefile_string
499 && (str
= OSDynamicCast(OSString
, dict
->getObject(hibernatefile_string
))))
501 setProperty(hibernatefile_string
, str
);
504 // Relay our allowed PM settings onto our registered PM clients
505 for(i
= 0; i
< allowedPMSettings
->getCount(); i
++) {
507 type
= (OSSymbol
*)allowedPMSettings
->getObject(i
);
510 obj
= dict
->getObject(type
);
513 return_value
= setPMSetting(type
, obj
);
515 if(kIOReturnSuccess
!= return_value
) goto exit
;
519 if(boot_complete_string
) boot_complete_string
->release();
520 if(stall_halt_string
) stall_halt_string
->release();
525 //*********************************************************************************
528 // Power Managment is informing us that we are the root power domain.
529 // We know we are not the root however, since we have just instantiated a parent
530 // for ourselves and made it the root. We override this method so it will have
532 //*********************************************************************************
533 IOReturn
IOPMrootDomain::youAreRoot ( void )
538 // **********************************************************************************
542 // **********************************************************************************
543 void IOPMrootDomain::command_received ( void * w
, void * x
, void * y
, void * z
)
545 super::command_received(w
,x
,y
,z
);
549 // **********************************************************************************
550 // broadcast_aggressiveness
552 // **********************************************************************************
553 IOReturn
broadcast_aggressiveness ( OSObject
* root
, void * x
, void * y
, void *, void * )
555 ((IOPMrootDomain
*)root
)->broadcast_it((unsigned long)x
,(unsigned long)y
);
560 // **********************************************************************************
563 // We are behind the command gate to broadcast an aggressiveness factor. We let the
564 // superclass do it, but we need to snoop on factors that affect idle sleep.
565 // **********************************************************************************
566 void IOPMrootDomain::broadcast_it (unsigned long type
, unsigned long value
)
568 super::setAggressiveness(type
,value
);
570 // Save user's spin down timer to restore after we replace it for idle sleep
571 if( type
== kPMMinutesToSpinDown
) user_spindown
= value
;
573 // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer
574 longestNonSleepSlider
= pm_vars
->current_aggressiveness_values
[kPMMinutesToDim
];
577 if ( type
== kPMMinutesToSleep
) {
578 if ( (sleepSlider
== 0) && (value
!= 0) ) {
580 // idle sleep is now enabled, maybe sleep now
584 if ( sleepSlider
== 0 ) {
585 // idle sleep is now disabled
587 // make sure we're powered
588 patriarch
->wakeSystem();
591 if ( sleepSlider
> longestNonSleepSlider
) {
592 extraSleepDelay
= sleepSlider
- longestNonSleepSlider
;
600 // **********************************************************************************
603 // **********************************************************************************
604 static void sleepTimerExpired ( thread_call_param_t us
)
606 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
610 static void wakeupClamshellTimerExpired ( thread_call_param_t us
)
612 ((IOPMrootDomain
*)us
)->stopIgnoringClamshellEventsDuringWakeup();
616 // **********************************************************************************
617 // handleSleepTimerExpiration
619 // The time between the sleep idle timeout and the next longest one has elapsed.
620 // It's time to sleep. Start that by removing the clamp that's holding us awake.
621 // **********************************************************************************
622 void IOPMrootDomain::handleSleepTimerExpiration ( void )
624 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
625 if(0 != user_spindown
)
626 setQuickSpinDownTimeout();
633 void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void)
635 // Allow clamshell-induced sleep now
636 ignoringClamshellDuringWakeup
= false;
638 // Re-send clamshell event, in case it causes a sleep
639 if(clamshellIsClosed
)
640 this->receivePowerNotification( kLocalEvalClamshellCommand
);
643 //*********************************************************************************
646 // Some aggressiveness factor has changed. We broadcast it to the hierarchy while on
647 // the Power Mangement workloop thread. This enables objects in the
648 // hierarchy to successfully alter their idle timers, which are all on the
650 //*********************************************************************************
652 static int pmsallsetup
= 0;
654 IOReturn
IOPMrootDomain::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
657 if(pmsExperimental
& 3) kprintf("setAggressiveness: type = %08X, newlevel = %08X\n", type
, newLevel
);
658 if(pmsExperimental
& 1) { /* Is experimental mode enabled? */
659 if(pmsInstalled
&& (type
== kPMSetProcessorSpeed
)) { /* We want to look at all processor speed changes if stepper is installed */
660 if(pmsallsetup
) return kIOReturnSuccess
; /* If already running, just eat this */
661 kprintf("setAggressiveness: starting stepper...\n");
662 pmsallsetup
= 1; /* Remember we did this */
664 pmsStart(); /* Get it all started up... */
665 return kIOReturnSuccess
; /* Leave now... */
670 if ( pm_vars
->PMcommandGate
) {
671 pm_vars
->PMcommandGate
->runAction(broadcast_aggressiveness
,(void *)type
,(void *)newLevel
);
674 return kIOReturnSuccess
;
678 // **********************************************************************************
681 // **********************************************************************************
682 IOReturn
IOPMrootDomain::sleepSystem ( void )
685 kprintf("Preventing system sleep on grounds of systemShutdown.\n");
688 if ( !systemBooting
&& !systemShutdown
&& allowSleep
&& sleepIsSupported
) {
689 patriarch
->sleepSystem();
691 return kIOReturnSuccess
;
693 if ( !systemBooting
&& !systemShutdown
&& allowSleep
&& !sleepIsSupported
) {
694 patriarch
->dozeSystem();
695 return kIOReturnSuccess
;
697 return kIOReturnError
;
701 // **********************************************************************************
704 // **********************************************************************************
705 IOReturn
IOPMrootDomain::shutdownSystem ( void )
707 //patriarch->shutDownSystem();
708 return kIOReturnUnsupported
;
712 // **********************************************************************************
715 // **********************************************************************************
716 IOReturn
IOPMrootDomain::restartSystem ( void )
718 //patriarch->restartSystem();
719 return kIOReturnUnsupported
;
723 // **********************************************************************************
726 // This overrides powerChangeDone in IOService.
728 // Finder sleep and idle sleep move us from the ON state to the SLEEP_STATE.
730 // If we just finished going to the SLEEP_STATE, and the platform is capable of true sleep,
731 // sleep the kernel. Otherwise switch up to the DOZE_STATE which will keep almost
732 // everything as off as it can get.
734 // **********************************************************************************
735 void IOPMrootDomain::powerChangeDone ( unsigned long previousState
)
737 OSNumber
* propertyPtr
;
738 unsigned short theProperty
;
739 AbsoluteTime deadline
;
741 switch ( pm_vars
->myCurrentState
) {
743 if ( canSleep
&& sleepIsSupported
)
745 // re-enable this timer for next sleep
746 idleSleepPending
= false;
748 IOLog("System %sSleep\n", gIOHibernateState
? "Safe" : "");
750 IOHibernateSystemHasSlept();
752 pm_vars
->thePlatform
->sleepKernel();
754 // The CPU(s) are off at this point. When they're awakened by CPU interrupt,
755 // code will resume execution here.
757 // Now we're waking...
758 IOHibernateSystemWake();
760 // stay awake for at least 30 seconds
761 clock_interval_to_deadline(30, kSecondScale
, &deadline
);
762 thread_call_enter_delayed(extraSleepTimer
, deadline
);
763 // this gets turned off when we sleep again
764 idleSleepPending
= true;
766 // Ignore closed clamshell during wakeup and for a few seconds
767 // after wakeup is complete
768 ignoringClamshellDuringWakeup
= true;
770 // sleep transition complete
771 gSleepOrShutdownPending
= 0;
773 // trip the reset of the calendar clock
774 clock_wakeup_calendar();
777 patriarch
->wakeSystem();
779 // early stage wake notification
780 tellClients(kIOMessageSystemWillPowerOn
);
782 // tell the tree we're waking
783 IOLog("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
786 // Allow drivers to request extra processing time before clamshell
787 // sleep if kIOREMSleepEnabledKey is present.
788 // Ignore clamshell events for at least 5 seconds
789 if(getProperty(kIOREMSleepEnabledKey
)) {
790 // clamshellWakeupIgnore callout clears ignoreClamshellDuringWakeup bit
791 clock_interval_to_deadline(5, kSecondScale
, &deadline
);
792 if(clamshellWakeupIgnore
) {
793 thread_call_enter_delayed(clamshellWakeupIgnore
, deadline
);
795 } else ignoringClamshellDuringWakeup
= false;
797 // Find out what woke us
798 propertyPtr
= OSDynamicCast(OSNumber
,getProperty("WakeEvent"));
800 theProperty
= propertyPtr
->unsigned16BitValue();
801 IOLog("Wake event %04x\n",theProperty
);
802 if ( (theProperty
& 0x0008) || //lid
803 (theProperty
& 0x0800) || // front panel button
804 (theProperty
& 0x0020) || // external keyboard
805 (theProperty
& 0x0001) ) { // internal keyboard
806 // We've identified the wakeup event as UI driven
810 // Since we can't identify the wakeup event, treat it as UI activity
814 // Wake for thirty seconds
815 changePowerStateToPriv(ON_STATE
);
816 powerOverrideOffPriv();
818 // allow us to step up a power state
819 patriarch
->sleepToDoze();
821 changePowerStateToPriv(DOZE_STATE
);
826 if ( previousState
!= DOZE_STATE
)
828 IOLog("System Doze\n");
830 // re-enable this timer for next sleep
831 idleSleepPending
= false;
832 gSleepOrShutdownPending
= 0;
836 IOLog("System Restart\n");
837 PEHaltRestart(kPERestartCPU
);
841 IOLog("System Halt\n");
842 PEHaltRestart(kPEHaltCPU
);
848 // **********************************************************************************
851 // The Display Wrangler calls here when it switches to its highest state. If the
852 // system is currently dozing, allow it to wake by making sure the parent is
854 // **********************************************************************************
855 void IOPMrootDomain::wakeFromDoze( void )
857 if ( pm_vars
->myCurrentState
== DOZE_STATE
)
859 // Reset sleep support till next sleep attempt.
860 // A machine's support of sleep vs. doze can change over the course of
861 // a running system, so we recalculate it before every sleep.
862 setSleepSupported(0);
864 powerOverrideOffPriv();
866 // early wake notification
867 tellClients(kIOMessageSystemWillPowerOn
);
869 // allow us to wake if children so desire
870 patriarch
->wakeSystem();
875 // *****************************************************************************
878 // Adds a new feature to the supported features dictionary
881 // *****************************************************************************
882 void IOPMrootDomain::publishFeature( const char * feature
)
884 publishFeature(feature
, kIOPMSupportedOnAC
885 | kIOPMSupportedOnBatt
886 | kIOPMSupportedOnUPS
,
892 // *****************************************************************************
893 // publishFeature (with supported power source specified)
895 // Adds a new feature to the supported features dictionary
898 // *****************************************************************************
899 void IOPMrootDomain::publishFeature(
901 uint32_t supportedWhere
,
902 uint32_t *uniqueFeatureID
)
904 static uint16_t next_feature_id
= 500;
906 OSNumber
*new_feature_data
= NULL
;
907 OSNumber
*existing_feature
= NULL
;
908 OSArray
*existing_feature_arr
= NULL
;
909 OSObject
*osObj
= NULL
;
910 uint32_t feature_value
= 0;
912 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
914 if(!supportedWhere
) {
915 // Feature isn't supported anywhere!
919 if(next_feature_id
> 5000) {
920 // Far, far too many features!
924 if(featuresDictLock
) IOLockLock(featuresDictLock
);
926 OSDictionary
*features
=
927 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
929 // Create new features dict if necessary
930 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
931 features
= OSDictionary::withDictionary(features
);
933 features
= OSDictionary::withCapacity(1);
936 // Create OSNumber to track new feature
938 next_feature_id
+= 1;
939 if( uniqueFeatureID
) {
940 // We don't really mind if the calling kext didn't give us a place
941 // to stash their unique id. Many kexts don't plan to unload, and thus
942 // have no need to remove themselves later.
943 *uniqueFeatureID
= next_feature_id
;
946 feature_value
= supportedWhere
+ (next_feature_id
<< 16);
947 new_feature_data
= OSNumber::withNumber(
948 (unsigned long long)feature_value
, 32);
950 // Does features object already exist?
951 if( (osObj
= features
->getObject(feature
)) )
953 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
955 // We need to create an OSArray to hold the now 2 elements.
956 existing_feature_arr
= OSArray::withObjects(
957 (const OSObject
**)&existing_feature
, 1, 2);
958 existing_feature_arr
->setObject(new_feature_data
);
959 features
->setObject(feature
, existing_feature_arr
);
960 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
962 // Add object to existing array
963 existing_feature_arr
->setObject(new_feature_data
);
966 // The easy case: no previously existing features listed. We simply
967 // set the OSNumber at key 'feature' and we're on our way.
968 features
->setObject(feature
, new_feature_data
);
971 new_feature_data
->release();
973 setProperty(kRootDomainSupportedFeatures
, features
);
977 // Notify EnergySaver and all those in user space so they might
978 // re-populate their feature specific UI
979 messageClients(kIOPMMessageFeatureChange
, this);
981 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
984 // *****************************************************************************
985 // removePublishedFeature
987 // Removes previously published feature
990 // *****************************************************************************
991 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
993 IOReturn ret
= kIOReturnError
;
994 uint32_t feature_value
= 0;
995 uint16_t feature_id
= 0;
996 bool madeAChange
= false;
998 OSSymbol
*dictKey
= NULL
;
999 OSCollectionIterator
*dictIterator
= NULL
;
1000 OSArray
*arrayMember
= NULL
;
1001 OSNumber
*numberMember
= NULL
;
1002 OSObject
*osObj
= NULL
;
1003 OSNumber
*osNum
= NULL
;
1005 if(featuresDictLock
) IOLockLock(featuresDictLock
);
1007 OSDictionary
*features
=
1008 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
1010 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
1012 // Any modifications to the dictionary are made to the copy to prevent
1013 // races & crashes with userland clients. Dictionary updated
1014 // automically later.
1015 features
= OSDictionary::withDictionary(features
);
1018 ret
= kIOReturnNotFound
;
1022 // We iterate 'features' dictionary looking for an entry tagged
1023 // with 'removeFeatureID'. If found, we remove it from our tracking
1024 // structures and notify the OS via a general interest message.
1026 dictIterator
= OSCollectionIterator::withCollection(features
);
1031 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
1033 osObj
= features
->getObject(dictKey
);
1035 // Each Feature is either tracked by an OSNumber
1036 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
1038 feature_value
= numberMember
->unsigned32BitValue();
1039 feature_id
= (uint16_t)(feature_value
>> 16);
1041 if( feature_id
== (uint16_t)removeFeatureID
)
1044 features
->removeObject(dictKey
);
1049 // Or tracked by an OSArray of OSNumbers
1050 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
1052 unsigned int arrayCount
= arrayMember
->getCount();
1054 for(unsigned int i
=0; i
<arrayCount
; i
++)
1056 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
1061 feature_value
= osNum
->unsigned32BitValue();
1062 feature_id
= (uint16_t)(feature_value
>> 16);
1064 if( feature_id
== (uint16_t)removeFeatureID
)
1067 if( 1 == arrayCount
) {
1068 // If the array only contains one element, remove
1070 features
->removeObject(dictKey
);
1072 // Otherwise just remove the element in question.
1073 arrayMember
->removeObject(i
);
1084 dictIterator
->release();
1088 ret
= kIOReturnSuccess
;
1090 setProperty(kRootDomainSupportedFeatures
, features
);
1092 // Notify EnergySaver and all those in user space so they might
1093 // re-populate their feature specific UI
1094 messageClients(kIOPMMessageFeatureChange
, this);
1096 ret
= kIOReturnNotFound
;
1100 if(features
) features
->release();
1101 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
1106 // **********************************************************************************
1109 // Enqueues unidle event to be performed later in a serialized context.
1111 // **********************************************************************************
1112 void IOPMrootDomain::unIdleDevice( IOService
*theDevice
, unsigned long theState
)
1114 if(pmPowerStateQueue
)
1115 pmPowerStateQueue
->unIdleOccurred(theDevice
, theState
);
1118 // **********************************************************************************
1119 // announcePowerSourceChange
1121 // Notifies "interested parties" that the batteries have changed state
1123 // **********************************************************************************
1124 void IOPMrootDomain::announcePowerSourceChange( void )
1126 IORegistryEntry
*_batteryRegEntry
= (IORegistryEntry
*) getProperty("BatteryEntry");
1128 // (if possible) re-publish power source state under IOPMrootDomain;
1129 // only do so if the battery controller publishes an IOResource
1130 // defining battery location. Called from ApplePMU battery driver.
1132 if(_batteryRegEntry
)
1135 batt_info
= (OSArray
*) _batteryRegEntry
->getProperty(kIOBatteryInfoKey
);
1137 setProperty(kIOBatteryInfoKey
, batt_info
);
1143 // *****************************************************************************
1144 // setPMSetting (private)
1146 // Internal helper to relay PM settings changes from user space to individual
1147 // drivers. Should be called only by IOPMrootDomain::setProperties.
1149 // *****************************************************************************
1150 IOReturn
IOPMrootDomain::setPMSetting(
1151 const OSSymbol
*type
,
1154 OSArray
*arr
= NULL
;
1155 PMSettingObject
*p_obj
= NULL
;
1159 if(NULL
== type
) return kIOReturnBadArgument
;
1161 IORecursiveLockLock(settingsCtrlLock
);
1163 fPMSettingsDict
->setObject(type
, obj
);
1165 arr
= (OSArray
*)settingsCallbacks
->getObject(type
);
1166 if(NULL
== arr
) goto exit
;
1167 count
= arr
->getCount();
1168 for(i
=0; i
<count
; i
++) {
1169 p_obj
= (PMSettingObject
*)OSDynamicCast(PMSettingObject
, arr
->getObject(i
));
1170 if(p_obj
) p_obj
->setPMSetting(type
, obj
);
1174 IORecursiveLockUnlock(settingsCtrlLock
);
1175 return kIOReturnSuccess
;
1178 // *****************************************************************************
1179 // copyPMSetting (public)
1181 // Allows kexts to safely read setting values, without being subscribed to
1184 // *****************************************************************************
1185 OSObject
* IOPMrootDomain::copyPMSetting(
1186 OSSymbol
*whichSetting
)
1188 OSObject
*obj
= NULL
;
1190 if(!whichSetting
) return NULL
;
1192 IORecursiveLockLock(settingsCtrlLock
);
1193 obj
= fPMSettingsDict
->getObject(whichSetting
);
1197 IORecursiveLockUnlock(settingsCtrlLock
);
1202 // *****************************************************************************
1203 // registerPMSettingController (public)
1205 // direct wrapper to registerPMSettingController with uint32_t power source arg
1206 // *****************************************************************************
1207 IOReturn
IOPMrootDomain::registerPMSettingController(
1208 const OSSymbol
* settings
[],
1209 IOPMSettingControllerCallback func
,
1214 return registerPMSettingController(
1216 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
1217 func
, target
, refcon
, handle
);
1220 // *****************************************************************************
1221 // registerPMSettingController (public)
1223 // Kexts may register for notifications when a particular setting is changed.
1224 // A list of settings is available in IOPM.h.
1226 // * settings - An OSArray containing OSSymbols. Caller should populate this
1227 // array with a list of settings caller wants notifications from.
1228 // * func - A C function callback of the type IOPMSettingControllerCallback
1229 // * target - caller may provide an OSObject *, which PM will pass as an
1230 // target to calls to "func"
1231 // * refcon - caller may provide an void *, which PM will pass as an
1232 // argument to calls to "func"
1233 // * handle - This is a return argument. We will populate this pointer upon
1234 // call success. Hold onto this and pass this argument to
1235 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
1237 // kIOReturnSuccess on success
1238 // *****************************************************************************
1239 IOReturn
IOPMrootDomain::registerPMSettingController(
1240 const OSSymbol
* settings
[],
1241 uint32_t supportedPowerSources
,
1242 IOPMSettingControllerCallback func
,
1247 PMSettingObject
*pmso
= NULL
;
1248 OSArray
*list
= NULL
;
1249 IOReturn ret
= kIOReturnSuccess
;
1252 if( NULL
== settings
||
1256 return kIOReturnBadArgument
;
1260 pmso
= PMSettingObject::pmSettingObject(
1261 (IOPMrootDomain
*)this, func
, target
,
1262 refcon
, supportedPowerSources
, settings
);
1265 ret
= kIOReturnInternalError
;
1266 goto bail_no_unlock
;
1269 IORecursiveLockLock(settingsCtrlLock
);
1270 for(i
=0; settings
[i
]; i
++)
1272 list
= (OSArray
*)settingsCallbacks
->getObject(settings
[i
]);
1274 // New array of callbacks for this setting
1275 list
= OSArray::withCapacity(1);
1276 settingsCallbacks
->setObject(settings
[i
], list
);
1280 // Add caller to the callback list
1281 list
->setObject(pmso
);
1284 ret
= kIOReturnSuccess
;
1286 // Track this instance by its OSData ptr from now on
1289 IORecursiveLockUnlock(settingsCtrlLock
);
1292 if(kIOReturnSuccess
!= ret
)
1294 // Error return case
1295 if(pmso
) pmso
->release();
1296 if(handle
) *handle
= NULL
;
1301 //******************************************************************************
1302 // sleepOnClamshellClosed
1304 // contains the logic to determine if the system should sleep when the clamshell
1306 //******************************************************************************
1308 bool IOPMrootDomain::shouldSleepOnClamshellClosed ( void )
1310 return ( !ignoringClamshell
1311 && !ignoringClamshellDuringWakeup
1312 && !(desktopMode
&& acAdaptorConnect
) );
1315 void IOPMrootDomain::sendClientClamshellNotification ( void )
1317 /* Only broadcast clamshell alert if clamshell exists. */
1318 if(!clamshellExists
)
1321 setProperty(kAppleClamshellStateKey
,
1322 clamshellIsClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
1324 setProperty(kAppleClamshellCausesSleepKey
,
1325 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
1328 /* Argument to message is a bitfield of
1329 * ( kClamshellStateBit | kClamshellSleepBit )
1330 * Carry on the clamshell state change notification from an
1331 * independent thread.
1333 pmArbiter
->clamshellStateChangeOccurred(
1334 (uint32_t) ( (clamshellIsClosed
? kClamshellStateBit
: 0)
1335 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)));
1338 //******************************************************************************
1339 // receivePowerNotification
1341 // The power controller is notifying us of a hardware-related power management
1342 // event that we must handle. This is a result of an 'environment' interrupt from
1343 // the power mgt micro.
1344 //******************************************************************************
1346 IOReturn
IOPMrootDomain::receivePowerNotification (UInt32 msg
)
1348 bool eval_clamshell
= false;
1351 * Local (IOPMrootDomain only) eval clamshell command
1353 if (msg
& kLocalEvalClamshellCommand
)
1355 eval_clamshell
= true;
1361 if (msg
& kIOPMOverTemp
)
1363 IOLog("PowerManagement emergency overtemp signal. Going to sleep!");
1364 (void) sleepSystem ();
1368 * PMU Processor Speed Change
1370 if (msg
& kIOPMProcessorSpeedChange
)
1372 IOService
*pmu
= waitForService(serviceMatching("ApplePMU"));
1373 pmu
->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
1374 pm_vars
->thePlatform
->sleepKernel();
1375 pmu
->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
1381 if (msg
& kIOPMSleepNow
)
1383 (void) sleepSystem ();
1389 if (msg
& kIOPMPowerEmergency
)
1391 (void) sleepSystem ();
1398 if (msg
& kIOPMClamshellOpened
)
1400 // Received clamshel open message from clamshell controlling driver
1401 // Update our internal state and tell general interest clients
1402 clamshellIsClosed
= false;
1403 clamshellExists
= true;
1405 sendClientClamshellNotification();
1410 * Send the clamshell interest notification since the lid is closing.
1412 if (msg
& kIOPMClamshellClosed
)
1414 // Received clamshel open message from clamshell controlling driver
1415 // Update our internal state and tell general interest clients
1416 clamshellIsClosed
= true;
1417 clamshellExists
= true;
1419 sendClientClamshellNotification();
1421 // And set eval_clamshell = so we can attempt
1422 eval_clamshell
= true;
1426 * Set Desktop mode (sent from graphics)
1428 * -> reevaluate lid state
1430 if (msg
& kIOPMSetDesktopMode
)
1432 desktopMode
= (0 != (msg
& kIOPMSetValue
));
1433 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
1435 sendClientClamshellNotification();
1437 // Re-evaluate the lid state
1438 if( clamshellIsClosed
)
1440 eval_clamshell
= true;
1445 * AC Adaptor connected
1447 * -> reevaluate lid state
1449 if (msg
& kIOPMSetACAdaptorConnected
)
1451 acAdaptorConnect
= (0 != (msg
& kIOPMSetValue
));
1452 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
1454 sendClientClamshellNotification();
1456 // Re-evaluate the lid state
1457 if( clamshellIsClosed
)
1459 eval_clamshell
= true;
1465 * Enable Clamshell (external display disappear)
1467 * -> reevaluate lid state
1469 if (msg
& kIOPMEnableClamshell
)
1471 // Re-evaluate the lid state
1472 // System should sleep on external display disappearance
1473 // in lid closed operation.
1474 if( clamshellIsClosed
&& (true == ignoringClamshell
) )
1476 eval_clamshell
= true;
1479 ignoringClamshell
= false;
1481 sendClientClamshellNotification();
1485 * Disable Clamshell (external display appeared)
1486 * We don't bother re-evaluating clamshell state. If the system is awake,
1487 * the lid is probably open.
1489 if (msg
& kIOPMDisableClamshell
)
1491 ignoringClamshell
= true;
1493 sendClientClamshellNotification();
1497 * Evaluate clamshell and SLEEP if appropiate
1499 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
1510 if (msg
& kIOPMPowerButton
)
1512 // toggle state of sleep/wake
1514 if ( pm_vars
->myCurrentState
== DOZE_STATE
)
1516 // yes, tell the tree we're waking
1518 // wake the Display Wrangler
1522 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
1523 // Check that power button sleep is enabled
1525 if( kOSBooleanTrue
!= getProperty(pbs
))
1535 if ( (msg
& kIOPMAllowSleep
) && !allowSleep
)
1545 if (msg
& kIOPMPreventSleep
) {
1548 if ( pm_vars
->myCurrentState
== DOZE_STATE
) {
1549 // yes, tell the tree we're waking
1552 // wake the Display Wrangler
1556 // make sure we have power to clamp
1557 patriarch
->wakeSystem();
1565 //*********************************************************************************
1568 //*********************************************************************************
1570 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
1572 if ( flags
& kPCICantSleep
)
1577 platformSleepSupport
= flags
;
1580 setProperty(kIOSleepSupportedKey
, canSleep
);
1584 //*********************************************************************************
1585 // requestPowerDomainState
1587 // The root domain intercepts this call to the superclass.
1589 // If the clamp bit is not set in the desire, then the child doesn't need the power
1590 // state it's requesting; it just wants it. The root ignores desires but not needs.
1591 // If the clamp bit is not set, the root takes it that the child can tolerate no
1592 // power and interprets the request accordingly. If all children can thus tolerate
1593 // no power, we are on our way to idle sleep.
1594 //*********************************************************************************
1596 IOReturn
IOPMrootDomain::requestPowerDomainState ( IOPMPowerFlags desiredState
, IOPowerConnection
* whichChild
, unsigned long specification
)
1600 IOPowerConnection
*connection
;
1601 unsigned long powerRequestFlag
= 0;
1602 IOPMPowerFlags editedDesire
= desiredState
;
1604 // if they don't really need it, they don't get it
1605 if ( !(desiredState
& kIOPMPreventIdleSleep
) ) {
1610 IOLockLock(pm_vars
->childLock
);
1612 // recompute sleepIsSupported and see if all children are asleep
1613 iter
= getChildIterator(gIOPowerPlane
);
1614 sleepIsSupported
= true;
1617 while ( (next
= iter
->getNextObject()) )
1619 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1621 if ( connection
== whichChild
)
1623 powerRequestFlag
+= editedDesire
;
1624 if ( desiredState
& kIOPMPreventSystemSleep
)
1626 sleepIsSupported
= false;
1629 powerRequestFlag
+= connection
->getDesiredDomainState();
1630 if ( connection
->getPreventSystemSleepFlag() )
1632 sleepIsSupported
= false;
1640 if ( (extraSleepDelay
== 0) && (powerRequestFlag
== 0) )
1645 // this may put the system to sleep
1648 IOLockUnlock(pm_vars
->childLock
);
1650 editedDesire
|= desiredState
& kIOPMPreventSystemSleep
;
1652 return super::requestPowerDomainState(editedDesire
,whichChild
,specification
);
1656 //*********************************************************************************
1657 // getSleepSupported
1659 //*********************************************************************************
1661 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
1663 return( platformSleepSupport
);
1667 //*********************************************************************************
1670 // We override the superclass implementation so we can send a different message
1671 // type to the client or application being notified.
1672 //*********************************************************************************
1674 bool IOPMrootDomain::tellChangeDown ( unsigned long stateNum
)
1676 switch ( stateNum
) {
1680 // Direct callout into OSMetaClass so it can disable kmod unloads
1681 // during sleep/wake to prevent deadlocks.
1682 OSMetaClassSystemSleepOrWake( kIOMessageSystemWillSleep
);
1684 return super::tellClientsWithResponse(kIOMessageSystemWillSleep
);
1686 // Unsupported shutdown ordering hack on RESTART only
1687 // For Bluetooth and USB (4368327)
1688 super::tellClients(iokit_common_msg(0x759));
1690 return super::tellClientsWithResponse(kIOMessageSystemWillRestart
);
1692 // Unsupported shutdown ordering hack on SHUTDOWN only
1693 // For Bluetooth and USB (4554440)
1694 super::tellClients(iokit_common_msg(0x749));
1696 return super::tellClientsWithResponse(kIOMessageSystemWillPowerOff
);
1698 // this shouldn't execute
1699 return super::tellChangeDown(stateNum
);
1703 //*********************************************************************************
1706 // We override the superclass implementation so we can send a different message
1707 // type to the client or application being notified.
1709 // This must be idle sleep since we don't ask apps during any other power change.
1710 //*********************************************************************************
1712 bool IOPMrootDomain::askChangeDown ( unsigned long )
1714 return super::tellClientsWithResponse(kIOMessageCanSystemSleep
);
1718 //*********************************************************************************
1721 // Notify registered applications and kernel clients that we are not
1724 // We override the superclass implementation so we can send a different message
1725 // type to the client or application being notified.
1727 // This must be a vetoed idle sleep, since no other power change can be vetoed.
1728 //*********************************************************************************
1730 void IOPMrootDomain::tellNoChangeDown ( unsigned long )
1732 return tellClients(kIOMessageSystemWillNotSleep
);
1736 //*********************************************************************************
1739 // Notify registered applications and kernel clients that we are raising power.
1741 // We override the superclass implementation so we can send a different message
1742 // type to the client or application being notified.
1743 //*********************************************************************************
1745 void IOPMrootDomain::tellChangeUp ( unsigned long stateNum
)
1747 if ( stateNum
== ON_STATE
)
1749 // Direct callout into OSMetaClass so it can disable kmod unloads
1750 // during sleep/wake to prevent deadlocks.
1751 OSMetaClassSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
1753 IOHibernateSystemPostWake();
1754 return tellClients(kIOMessageSystemHasPoweredOn
);
1758 //*********************************************************************************
1761 //*********************************************************************************
1763 void IOPMrootDomain::reportUserInput ( void )
1769 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
1772 wrangler
= (IOService
*) iter
->getNextObject();
1778 wrangler
->activityTickle(0,0);
1781 //*********************************************************************************
1782 // setQuickSpinDownTimeout
1784 //*********************************************************************************
1786 void IOPMrootDomain::setQuickSpinDownTimeout ( void )
1788 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown
,(unsigned long)1);
1791 //*********************************************************************************
1792 // restoreUserSpinDownTimeout
1794 //*********************************************************************************
1796 void IOPMrootDomain::restoreUserSpinDownTimeout ( void )
1798 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown
,(unsigned long)user_spindown
);
1801 //*********************************************************************************
1802 // changePowerStateTo & changePowerStateToPriv
1804 // Override of these methods for logging purposes.
1805 //*********************************************************************************
1807 IOReturn
IOPMrootDomain::changePowerStateTo ( unsigned long ordinal
)
1809 return super::changePowerStateTo(ordinal
);
1812 IOReturn
IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal
)
1816 if( (systemBooting
|| systemShutdown
) && (ordinal
== SLEEP_STATE
) )
1818 kprintf("DANGER DANGER DANGER unexpected code path. aborting SLEEPSTATE change.\n");
1819 super::changePowerStateToPriv(ON_STATE
);
1822 if( (SLEEP_STATE
== ordinal
) && sleepSupportedPEFunction
)
1825 // Determine if the machine supports sleep, or must doze.
1826 ret
= getPlatform()->callPlatformFunction(
1827 sleepSupportedPEFunction
, false,
1828 NULL
, NULL
, NULL
, NULL
);
1830 // If the machine only supports doze, the callPlatformFunction call
1831 // boils down toIOPMrootDomain::setSleepSupported(kPCICantSleep),
1832 // otherwise nothing.
1835 return super::changePowerStateToPriv(ordinal
);
1839 //*********************************************************************************
1840 // sysPowerDownHandler
1842 // Receives a notification when the RootDomain changes state.
1844 // Allows us to take action on system sleep, power down, and restart after
1845 // applications have received their power change notifications and replied,
1846 // but before drivers have powered down. We perform a vfs sync on power down.
1847 //*********************************************************************************
1849 IOReturn
IOPMrootDomain::sysPowerDownHandler( void * target
, void * refCon
,
1850 UInt32 messageType
, IOService
* service
,
1851 void * messageArgument
, vm_size_t argSize
)
1854 IOPowerStateChangeNotification
*params
= (IOPowerStateChangeNotification
*) messageArgument
;
1855 IOPMrootDomain
*rootDomain
= OSDynamicCast(IOPMrootDomain
, service
);
1858 return kIOReturnUnsupported
;
1860 switch (messageType
) {
1861 case kIOMessageSystemWillSleep
:
1862 rootDomain
->powerOverrideOnPriv(); // start ignoring children's requests
1863 // (fall through to other cases)
1865 // Interested applications have been notified of an impending power
1866 // change and have acked (when applicable).
1867 // This is our chance to save whatever state we can before powering
1869 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
1872 // We will ack within 20 seconds
1873 params
->returnValue
= 20 * 1000 * 1000;
1874 if (gIOHibernateState
)
1875 params
->returnValue
+= gIOHibernateFreeTime
* 1000; //add in time we could spend freeing pages
1877 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
1879 // Purposely delay the ack and hope that shutdown occurs quickly.
1880 // Another option is not to schedule the thread and wait for
1882 AbsoluteTime deadline
;
1883 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
1884 thread_call_enter1_delayed( rootDomain
->diskSyncCalloutEntry
,
1885 (thread_call_param_t
)params
->powerRef
,
1889 thread_call_enter1(rootDomain
->diskSyncCalloutEntry
, (thread_call_param_t
)params
->powerRef
);
1890 ret
= kIOReturnSuccess
;
1893 case kIOMessageSystemWillPowerOff
:
1894 case kIOMessageSystemWillRestart
:
1895 ret
= kIOReturnUnsupported
;
1899 ret
= kIOReturnUnsupported
;
1905 //*********************************************************************************
1906 // displayWranglerNotification
1908 // Receives a notification when the IODisplayWrangler changes state.
1910 // Allows us to take action on display dim/undim.
1912 // When the display goes dim we:
1913 // - Start the idle sleep timer
1914 // - set the quick spin down timeout
1916 // On wake from display dim:
1917 // - Cancel the idle sleep timer
1918 // - restore the user's chosen spindown timer from the "quick" spin down value
1919 //*********************************************************************************
1921 IOReturn
IOPMrootDomain::displayWranglerNotification( void * target
, void * refCon
,
1922 UInt32 messageType
, IOService
* service
,
1923 void * messageArgument
, vm_size_t argSize
)
1925 IOPMrootDomain
* rootDomain
= OSDynamicCast(IOPMrootDomain
, (IOService
*)target
);
1926 AbsoluteTime deadline
;
1927 static bool deviceAlreadyPoweredOff
= false;
1930 return kIOReturnUnsupported
;
1932 switch (messageType
) {
1933 case kIOMessageDeviceWillPowerOff
:
1934 // The IODisplayWrangler has powered off either because of idle display sleep
1935 // or force system sleep.
1937 // The display wrangler will send the DeviceWillPowerOff message 4 times until
1938 // it gets into its lowest state. We only want to act on the first of those 4.
1939 if( deviceAlreadyPoweredOff
) return kIOReturnUnsupported
;
1941 deviceAlreadyPoweredOff
= true;
1943 if( rootDomain
->extraSleepDelay
)
1945 // start the extra sleep timer
1946 clock_interval_to_deadline(rootDomain
->extraSleepDelay
*60, kSecondScale
, &deadline
);
1947 thread_call_enter_delayed(rootDomain
->extraSleepTimer
, deadline
);
1948 rootDomain
->idleSleepPending
= true;
1950 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
1951 // and if system sleep is non-Never
1952 if( (0 != rootDomain
->user_spindown
) && (0 != rootDomain
->sleepSlider
) )
1953 rootDomain
->setQuickSpinDownTimeout();
1958 case kIOMessageDeviceHasPoweredOn
:
1960 // The display has powered on either because of UI activity or wake from sleep/doze
1961 deviceAlreadyPoweredOff
= false;
1962 rootDomain
->adjustPowerState();
1965 // cancel any pending idle sleep
1966 if(rootDomain
->idleSleepPending
)
1968 thread_call_cancel(rootDomain
->extraSleepTimer
);
1969 rootDomain
->idleSleepPending
= false;
1972 // Change the spindown value back to the user's selection from our accelerated setting
1973 if(0 != rootDomain
->user_spindown
)
1974 rootDomain
->restoreUserSpinDownTimeout();
1976 // Put on the policy maker's on clamp.
1983 return kIOReturnUnsupported
;
1986 //*********************************************************************************
1987 // displayWranglerPublished
1989 // Receives a notification when the IODisplayWrangler is published.
1990 // When it's published we install a power state change handler.
1992 //*********************************************************************************
1994 bool IOPMrootDomain::displayWranglerPublished(
1997 IOService
* newService
)
1999 IOPMrootDomain
*rootDomain
=
2000 OSDynamicCast(IOPMrootDomain
, (IOService
*)target
);
2005 rootDomain
->wrangler
= newService
;
2007 // we found the display wrangler, now install a handler
2008 if( !rootDomain
->wrangler
->registerInterest( gIOGeneralInterest
,
2009 &displayWranglerNotification
, target
, 0) )
2018 //*********************************************************************************
2021 // Notification on battery class IOPowerSource appearance
2023 //******************************************************************************
2025 bool IOPMrootDomain::batteryPublished(
2028 IOService
* resourceService
)
2030 // rdar://2936060&4435589
2031 // All laptops have dimmable LCD displays
2032 // All laptops have batteries
2033 // So if this machine has a battery, publish the fact that the backlight
2034 // supports dimming.
2035 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
2042 //*********************************************************************************
2045 // Some condition that affects our wake/sleep/doze decision has changed.
2047 // If the sleep slider is in the off position, we cannot sleep or doze.
2048 // If the enclosure is open, we cannot sleep or doze.
2049 // If the system is still booting, we cannot sleep or doze.
2051 // In those circumstances, we prevent sleep and doze by holding power on with
2052 // changePowerStateToPriv(ON).
2054 // If the above conditions do not exist, and also the sleep timer has expired, we
2055 // allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
2056 // changePowerStateToPriv(DOZE) depending on whether or not we already know the
2057 // platform cannot sleep.
2059 // In this case, sleep or doze will either occur immediately or at the next time
2060 // that no children are holding the system out of idle sleep via the
2061 // kIOPMPreventIdleSleep flag in their power state arrays.
2062 //*********************************************************************************
2064 void IOPMrootDomain::adjustPowerState( void )
2066 if ( (sleepSlider
== 0)
2071 if(systemBooting
|| systemShutdown
) {
2072 kprintf("adjusting power state to ON_STATE [2063] on grounds of systemBooting.\n");
2075 changePowerStateToPriv(ON_STATE
);
2080 if ( sleepIsSupported
)
2082 changePowerStateToPriv(SLEEP_STATE
);
2084 changePowerStateToPriv(DOZE_STATE
);
2090 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2095 #define super OSObject
2096 OSDefineMetaClassAndStructors(PMSettingObject
, OSObject
)
2098 void PMSettingObject::setPMSetting(const OSSymbol
*type
, OSObject
*obj
)
2100 (*func
)(target
, type
, obj
, refcon
);
2104 * Static constructor/initializer for PMSettingObject
2106 PMSettingObject
*PMSettingObject::pmSettingObject(
2107 IOPMrootDomain
*parent_arg
,
2108 IOPMSettingControllerCallback handler_arg
,
2109 OSObject
*target_arg
,
2110 uintptr_t refcon_arg
,
2111 uint32_t supportedPowerSources
,
2112 const OSSymbol
* settings
[])
2114 uint32_t objCount
= 0;
2115 PMSettingObject
*pmso
;
2117 if( !parent_arg
|| !handler_arg
|| !settings
) return NULL
;
2119 // count OSSymbol entries in NULL terminated settings array
2120 while( settings
[objCount
] ) {
2123 if(0 == objCount
) return NULL
;
2125 pmso
= new PMSettingObject
;
2126 if(!pmso
|| !pmso
->init()) return NULL
;
2128 pmso
->parent
= parent_arg
;
2129 pmso
->func
= handler_arg
;
2130 pmso
->target
= target_arg
;
2131 pmso
->refcon
= refcon_arg
;
2132 pmso
->releaseAtCount
= objCount
+ 1; // release when it has count+1 retains
2134 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount
);
2135 if(pmso
->publishedFeatureID
) {
2136 for(unsigned int i
=0; i
<objCount
; i
++) {
2137 // Since there is now at least one listener to this setting, publish
2138 // PM root domain support for it.
2139 parent_arg
->publishFeature( settings
[i
]->getCStringNoCopy(),
2140 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
2147 void PMSettingObject::free(void)
2149 OSCollectionIterator
*settings_iter
;
2154 int objCount
= releaseAtCount
- 1;
2156 if(publishedFeatureID
) {
2157 for(i
=0; i
<objCount
; i
++) {
2158 if(0 != publishedFeatureID
[i
]) {
2159 parent
->removePublishedFeature( publishedFeatureID
[i
] );
2163 IOFree(publishedFeatureID
, sizeof(uint32_t) * objCount
);
2166 IORecursiveLockLock(parent
->settingsCtrlLock
);
2168 // Search each PM settings array in the kernel.
2169 settings_iter
= OSCollectionIterator::withCollection(parent
->settingsCallbacks
);
2172 while(( sym
= OSDynamicCast(OSSymbol
, settings_iter
->getNextObject()) ))
2174 arr
= (OSArray
*)parent
->settingsCallbacks
->getObject(sym
);
2175 arr_idx
= arr
->getNextIndexOfObject(this, 0);
2177 // 'this' was found in the array; remove it
2178 arr
->removeObject(arr_idx
);
2182 settings_iter
->release();
2185 IORecursiveLockUnlock(parent
->settingsCtrlLock
);
2190 void PMSettingObject::taggedRelease(const void *tag
, const int when
) const
2192 // We have n+1 retains - 1 per array that this PMSettingObject is a member
2193 // of, and 1 retain to ourself. When we get a release with n+1 retains
2194 // remaining, we go ahead and free ourselves, cleaning up array pointers
2197 super::taggedRelease(tag
, releaseAtCount
);
2202 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2205 #define super IOService
2207 OSDefineMetaClassAndStructors(IORootParent
, IOService
)
2209 // This array exactly parallels the state array for the root domain.
2210 // Power state changes initiated by a device can be vetoed by a client of the device, and
2211 // power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
2212 // so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
2213 // its parent to make the change. That is the reason for this complexity.
2215 static IOPMPowerState patriarchPowerStates
[number_of_power_states
] = {
2216 {1,0,0,0,0,0,0,0,0,0,0,0}, // off
2217 {1,0,RESTART_POWER
,0,0,0,0,0,0,0,0,0}, // reset
2218 {1,0,SLEEP_POWER
,0,0,0,0,0,0,0,0,0}, // sleep
2219 {1,0,DOZE_POWER
,0,0,0,0,0,0,0,0,0}, // doze
2220 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0} // running
2223 bool IORootParent::start ( IOService
* nub
)
2225 mostRecentChange
= ON_STATE
;
2228 registerPowerDriver(this,patriarchPowerStates
,number_of_power_states
);
2229 powerOverrideOnPriv();
2234 void IORootParent::shutDownSystem ( void )
2236 mostRecentChange
= OFF_STATE
;
2237 changePowerStateToPriv(OFF_STATE
);
2241 void IORootParent::restartSystem ( void )
2243 mostRecentChange
= RESTART_STATE
;
2244 changePowerStateToPriv(RESTART_STATE
);
2248 void IORootParent::sleepSystem ( void )
2250 mostRecentChange
= SLEEP_STATE
;
2251 changePowerStateToPriv(SLEEP_STATE
);
2255 void IORootParent::dozeSystem ( void )
2257 mostRecentChange
= DOZE_STATE
;
2258 changePowerStateToPriv(DOZE_STATE
);
2261 // Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
2262 // This brings the parent to doze, which allows the root to step up from sleep to doze.
2264 // In idle sleep, do nothing because the parent is still on and the root can freely change state.
2266 void IORootParent::sleepToDoze ( void )
2268 if ( mostRecentChange
== SLEEP_STATE
) {
2269 changePowerStateToPriv(DOZE_STATE
);
2274 void IORootParent::wakeSystem ( void )
2276 mostRecentChange
= ON_STATE
;
2277 changePowerStateToPriv(ON_STATE
);
2280 IOReturn
IORootParent::changePowerStateToPriv ( unsigned long ordinal
)
2284 if( (SLEEP_STATE
== ordinal
) && sleepSupportedPEFunction
)
2287 // Determine if the machine supports sleep, or must doze.
2288 ret
= getPlatform()->callPlatformFunction(
2289 sleepSupportedPEFunction
, false,
2290 NULL
, NULL
, NULL
, NULL
);
2292 // If the machine only supports doze, the callPlatformFunction call
2293 // boils down toIOPMrootDomain::setSleepSupported(kPCICantSleep),
2294 // otherwise nothing.
2297 return super::changePowerStateToPriv(ordinal
);