2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 #include <IOKit/IOWorkLoop.h>
23 #include <IOKit/IOCommandGate.h>
24 #include <IOKit/IOTimerEventSource.h>
25 #include <IOKit/IOPlatformExpert.h>
26 #include <IOKit/IOKitDebug.h>
27 #include <IOKit/IOTimeStamp.h>
28 #include <IOKit/pwr_mgt/RootDomain.h>
29 #include <IOKit/pwr_mgt/IOPMPrivate.h>
30 #include <IOKit/IOMessage.h>
31 #include "RootDomainUserClient.h"
32 #include "IOKit/pwr_mgt/IOPowerConnection.h"
34 extern "C" void kprintf(const char *, ...);
36 extern const IORegistryPlane
* gIOPowerPlane
;
38 // debug trace function
40 ioSPMTrace(unsigned int csc
,
41 unsigned int a
= 0, unsigned int b
= 0,
42 unsigned int c
= 0, unsigned int d
= 0)
44 if (gIOKitDebug
& kIOLogTracePower
)
45 IOTimeStampConstant(IODBG_POWER(csc
), a
, b
, c
, d
);
48 IOReturn
broadcast_aggressiveness ( OSObject
*, void *, void *, void *, void * );
49 static void sleepTimerExpired(thread_call_param_t
);
50 static void wakeupClamshellTimerExpired ( thread_call_param_t us
);
53 #define number_of_power_states 5
55 #define RESTART_STATE 1
60 #define ON_POWER kIOPMPowerOn
61 #define RESTART_POWER kIOPMRestart
62 #define SLEEP_POWER kIOPMAuxPowerOn
63 #define DOZE_POWER kIOPMDoze
65 static IOPMPowerState ourPowerStates
[number_of_power_states
] = {
66 {1,0, 0, 0,0,0,0,0,0,0,0,0}, // state 0, off
67 {1,kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
,0,0,0,0,0,0,0,0}, // state 1, restart
68 {1,kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
,0,0,0,0,0,0,0,0}, // state 2, sleep
69 {1,kIOPMDoze
, kIOPMDoze
, DOZE_POWER
,0,0,0,0,0,0,0,0}, // state 3, doze
70 {1,kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
,0,0,0,0,0,0,0,0}, // state 4, on
73 static IOPMrootDomain
* gRootDomain
;
74 static UInt32 gSleepOrShutdownPending
= 0;
77 #define super IOService
78 OSDefineMetaClassAndStructors(IOPMrootDomain
,IOService
)
82 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
= 0)
84 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
87 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
= 0)
89 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
92 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
94 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
97 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
99 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
102 IOReturn
rootDomainRestart ( void )
104 return gRootDomain
->restartSystem();
107 IOReturn
rootDomainShutdown ( void )
109 return gRootDomain
->shutdownSystem();
112 void IOSystemShutdownNotification ( void )
114 for ( int i
= 0; i
< 100; i
++ )
116 if ( OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) ) break;
121 int sync_internal(void);
125 A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain
126 children it has, but within the constraint of the power state provided by its parent. The driver expresses its desire by
127 calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children
128 express their desires by calling requestPowerDomainState().
130 The Root Power Domain owns the policy for idle and demand sleep and doze for the system. It is a power-managed IOService just
131 like the others in the system. It implements several power states which correspond to what we see as Sleep, Doze, etc.
133 The sleep/doze policy is as follows:
134 Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards.
135 Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero.
136 The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep.
138 These three conditions are enforced using the "driver clamp" by calling changePowerStateTo(). For example, if the case is
139 opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or
140 the state of the other clamp.
142 Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item.
143 In this case the root's parent actually initiates the power state change so that the root has no choice and does not give
144 applications the opportunity to veto the change.
146 Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep. When this is true, the root's
147 children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE)
148 to hold itself on until the sleep timer expires. This timer is set for the difference between the sleep timeout slider and
149 the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel. For example, if
150 the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes,
151 when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root
152 sets its timer for 25 minutes (30 - 5). When the timer expires, it releases its clamp and now nothing is holding it awake,
155 Demand sleep is prevented when the system is booting. When preferences are transmitted by the loginwindow at the end of
156 boot, a flag is cleared, and this allows subsequent Demand Sleep.
158 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
159 a clamp, but sets a flag which is noticed before actually sleeping the kernel. If the flag is set, the root steps up
160 one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and
161 ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler
166 // **********************************************************************************
168 IOPMrootDomain
* IOPMrootDomain::construct( void )
170 IOPMrootDomain
* root
;
172 root
= new IOPMrootDomain
;
179 // **********************************************************************************
181 static void disk_sync_callout(thread_call_param_t p0
, thread_call_param_t p1
)
183 IOService
* rootDomain
= (IOService
*) p0
;
184 unsigned long pmRef
= (unsigned long) p1
;
187 rootDomain
->allowPowerChange(pmRef
);
190 // **********************************************************************************
193 // We don't do much here. The real initialization occurs when the platform
194 // expert informs us we are the root.
195 // **********************************************************************************
198 bool IOPMrootDomain::start ( IOService
* nub
)
200 OSDictionary
*tmpDict
;
207 setProperty("IOSleepSupported","");
209 sleepIsSupported
= true;
210 systemBooting
= true;
211 ignoringClamshell
= true;
213 idleSleepPending
= false;
217 ignoringClamshellDuringWakeup
= false;
219 tmpDict
= OSDictionary::withCapacity(1);
220 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
223 pm_vars
->PMworkloop
= IOWorkLoop::workLoop(); // make the workloop
224 extraSleepTimer
= thread_call_allocate((thread_call_func_t
)sleepTimerExpired
, (thread_call_param_t
) this);
225 clamshellWakeupIgnore
= thread_call_allocate((thread_call_func_t
)wakeupClamshellTimerExpired
, (thread_call_param_t
) this);
226 diskSyncCalloutEntry
= thread_call_allocate(&disk_sync_callout
, (thread_call_param_t
) this);
228 patriarch
= new IORootParent
; // create our parent
230 patriarch
->attach(this);
231 patriarch
->start(this);
232 patriarch
->youAreRoot();
233 patriarch
->wakeSystem();
234 patriarch
->addPowerChild(this);
236 registerPowerDriver(this,ourPowerStates
,number_of_power_states
);
238 setPMRootDomain(this);
239 changePowerStateToPriv(ON_STATE
); // set a clamp until we sleep
241 registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0); // install power change handler
243 // Register for a notification when IODisplayWrangler is published
244 addNotification( gIOPublishNotification
, serviceMatching("IODisplayWrangler"), &displayWranglerPublished
, this, 0);
246 registerService(); // let clients find us
251 // **********************************************************************************
254 // Receive a setProperty call
255 // The "System Boot" property means the system is completely booted.
256 // **********************************************************************************
257 IOReturn
IOPMrootDomain::setProperties ( OSObject
*props_obj
)
259 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
261 if(!dict
) return kIOReturnBadArgument
;
263 if(dict
->getObject(OSString::withCString("System Boot Complete"))) {
264 systemBooting
= false;
265 kprintf("IOPM: received System Boot Complete property");
269 return kIOReturnSuccess
;
273 //*********************************************************************************
276 // Power Managment is informing us that we are the root power domain.
277 // We know we are not the root however, since we have just instantiated a parent
278 // for ourselves and made it the root. We override this method so it will have
280 //*********************************************************************************
281 IOReturn
IOPMrootDomain::youAreRoot ( void )
286 // **********************************************************************************
290 // **********************************************************************************
291 void IOPMrootDomain::command_received ( void * w
, void * x
, void * y
, void * z
)
293 super::command_received(w
,x
,y
,z
);
297 // **********************************************************************************
298 // broadcast_aggressiveness
300 // **********************************************************************************
301 IOReturn
broadcast_aggressiveness ( OSObject
* root
, void * x
, void * y
, void *, void * )
303 ((IOPMrootDomain
*)root
)->broadcast_it((unsigned long)x
,(unsigned long)y
);
308 // **********************************************************************************
311 // We are behind the command gate to broadcast an aggressiveness factor. We let the
312 // superclass do it, but we need to snoop on factors that affect idle sleep.
313 // **********************************************************************************
314 void IOPMrootDomain::broadcast_it (unsigned long type
, unsigned long value
)
316 super::setAggressiveness(type
,value
);
318 // Save user's spin down timer to restore after we replace it for idle sleep
319 if( type
== kPMMinutesToSpinDown
) user_spindown
= value
;
321 // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer
322 longestNonSleepSlider
= pm_vars
->current_aggressiveness_values
[kPMMinutesToDim
];
325 if ( type
== kPMMinutesToSleep
) {
326 if ( (sleepSlider
== 0) && (value
!= 0) ) {
328 adjustPowerState(); // idle sleep is now enabled, maybe sleep now
331 if ( sleepSlider
== 0 ) {
332 adjustPowerState(); // idle sleep is now disabled
333 patriarch
->wakeSystem(); // make sure we're powered
336 if ( sleepSlider
> longestNonSleepSlider
) {
337 extraSleepDelay
= sleepSlider
- longestNonSleepSlider
;
345 // **********************************************************************************
348 // **********************************************************************************
349 static void sleepTimerExpired ( thread_call_param_t us
)
351 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
355 static void wakeupClamshellTimerExpired ( thread_call_param_t us
)
357 ((IOPMrootDomain
*)us
)->stopIgnoringClamshellEventsDuringWakeup();
361 // **********************************************************************************
362 // handleSleepTimerExpiration
364 // The time between the sleep idle timeout and the next longest one has elapsed.
365 // It's time to sleep. Start that by removing the clamp that's holding us awake.
366 // **********************************************************************************
367 void IOPMrootDomain::handleSleepTimerExpiration ( void )
369 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
370 if(0 != user_spindown
)
371 setQuickSpinDownTimeout();
378 void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void)
382 // Allow clamshell-induced sleep now
383 ignoringClamshellDuringWakeup
= false;
385 if ((state
= getProperty(kAppleClamshellStateKey
)))
386 publishResource(kAppleClamshellStateKey
, state
);
389 //*********************************************************************************
392 // Some aggressiveness factor has changed. We broadcast it to the hierarchy while on
393 // the Power Mangement workloop thread. This enables objects in the
394 // hierarchy to successfully alter their idle timers, which are all on the
396 //*********************************************************************************
398 IOReturn
IOPMrootDomain::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
400 if ( pm_vars
->PMcommandGate
) {
401 pm_vars
->PMcommandGate
->runAction(broadcast_aggressiveness
,(void *)type
,(void *)newLevel
);
404 return kIOReturnSuccess
;
408 // **********************************************************************************
411 // **********************************************************************************
412 IOReturn
IOPMrootDomain::sleepSystem ( void )
414 kprintf("sleep demand received\n");
415 if ( !systemBooting
&& allowSleep
&& sleepIsSupported
) {
416 patriarch
->sleepSystem();
417 return kIOReturnSuccess
;
419 if ( !systemBooting
&& allowSleep
&& !sleepIsSupported
) {
420 patriarch
->dozeSystem();
421 return kIOReturnSuccess
;
423 return kIOReturnSuccess
;
427 // **********************************************************************************
430 // **********************************************************************************
431 IOReturn
IOPMrootDomain::shutdownSystem ( void )
433 patriarch
->shutDownSystem();
434 return kIOReturnSuccess
;
438 // **********************************************************************************
441 // **********************************************************************************
442 IOReturn
IOPMrootDomain::restartSystem ( void )
444 patriarch
->restartSystem();
445 return kIOReturnSuccess
;
449 // **********************************************************************************
452 // This overrides powerChangeDone in IOService.
454 // Finder sleep and idle sleep move us from the ON state to the SLEEP_STATE.
456 // If we just finished going to the SLEEP_STATE, and the platform is capable of true sleep,
457 // sleep the kernel. Otherwise switch up to the DOZE_STATE which will keep almost
458 // everything as off as it can get.
460 // **********************************************************************************
461 void IOPMrootDomain::powerChangeDone ( unsigned long previousState
)
463 OSNumber
* propertyPtr
;
464 unsigned short theProperty
;
465 AbsoluteTime deadline
;
467 switch ( pm_vars
->myCurrentState
) {
469 if ( canSleep
&& sleepIsSupported
) {
470 idleSleepPending
= false; // re-enable this timer for next sleep
471 IOLog("System Sleep\n");
472 pm_vars
->thePlatform
->sleepKernel(); // sleep now
474 ioSPMTrace(IOPOWER_WAKE
, * (int *) this); // now we're waking
476 clock_interval_to_deadline(30, kSecondScale
, &deadline
); // stay awake for at least 30 seconds
477 thread_call_enter_delayed(extraSleepTimer
, deadline
);
478 idleSleepPending
= true; // this gets turned off when we sleep again
480 // Ignore closed clamshell during wakeup and for a few seconds
481 // after wakeup is complete
482 ignoringClamshellDuringWakeup
= true;
484 gSleepOrShutdownPending
= 0; // sleep transition complete
485 patriarch
->wakeSystem(); // get us some power
487 IOLog("System Wake\n");
488 systemWake(); // tell the tree we're waking
490 // Allow drivers to request extra processing time before clamshell
491 // sleep if kIOREMSleepEnabledKey is present.
492 // Ignore clamshell events for at least 5 seconds
493 if(getProperty(kIOREMSleepEnabledKey
)) {
494 // clamshellWakeupIgnore callout clears ignoreClamshellDuringWakeup bit
495 clock_interval_to_deadline(5, kSecondScale
, &deadline
);
496 if(clamshellWakeupIgnore
) thread_call_enter_delayed(clamshellWakeupIgnore
, deadline
);
497 } else ignoringClamshellDuringWakeup
= false;
499 propertyPtr
= OSDynamicCast(OSNumber
,getProperty("WakeEvent"));
500 if ( propertyPtr
) { // find out what woke us
501 theProperty
= propertyPtr
->unsigned16BitValue();
502 IOLog("Wake event %04x\n",theProperty
);
503 if ( (theProperty
== 0x0008) || //lid
504 (theProperty
== 0x0800) || // front panel button
505 (theProperty
== 0x0020) || // external keyboard
506 (theProperty
== 0x0001) ) { // internal keyboard
511 IOLog("Unknown wake event\n");
512 reportUserInput(); // don't know, call it user input then
515 changePowerStateToPriv(ON_STATE
); // wake for thirty seconds
516 powerOverrideOffPriv();
519 patriarch
->sleepToDoze(); // allow us to step up a power state
520 changePowerStateToPriv(DOZE_STATE
); // and do it
525 if ( previousState
!= DOZE_STATE
) {
526 IOLog("System Doze\n");
528 idleSleepPending
= false; // re-enable this timer for next sleep
529 gSleepOrShutdownPending
= 0;
533 IOLog("System Restart\n");
534 PEHaltRestart(kPERestartCPU
);
538 IOLog("System Halt\n");
539 PEHaltRestart(kPEHaltCPU
);
545 // **********************************************************************************
548 // The Display Wrangler calls here when it switches to its highest state. If the
549 // system is currently dozing, allow it to wake by making sure the parent is
551 // **********************************************************************************
552 void IOPMrootDomain::wakeFromDoze( void )
554 if ( pm_vars
->myCurrentState
== DOZE_STATE
) {
555 canSleep
= true; // reset this till next attempt
556 powerOverrideOffPriv();
557 patriarch
->wakeSystem(); // allow us to wake if children so desire
562 // **********************************************************************************
565 // Adds a new feature to the supported features dictionary
568 // **********************************************************************************
569 void IOPMrootDomain::publishFeature( const char * feature
)
571 OSDictionary
*features
= (OSDictionary
*)getProperty(kRootDomainSupportedFeatures
);
573 features
->setObject(feature
, kOSBooleanTrue
);
577 // **********************************************************************************
580 // **********************************************************************************
581 IOReturn
IOPMrootDomain::newUserClient( task_t owningTask
, void * /* security_id */, UInt32 type
, IOUserClient
** handler
)
583 IOReturn err
= kIOReturnSuccess
;
584 RootDomainUserClient
* client
;
586 client
= RootDomainUserClient::withTask(owningTask
);
588 if( !client
|| (false == client
->attach( this )) ||
589 (false == client
->start( this )) ) {
591 client
->detach( this );
595 err
= kIOReturnNoMemory
;
601 //*********************************************************************************
602 // receivePowerNotification
604 // The power controller is notifying us of a hardware-related power management
605 // event that we must handle. This is a result of an 'environment' interrupt from
606 // the power mgt micro.
607 //*********************************************************************************
609 IOReturn
IOPMrootDomain::receivePowerNotification (UInt32 msg
)
611 if (msg
& kIOPMOverTemp
) {
612 IOLog("Power Management received emergency overtemp signal. Going to sleep.");
613 (void) sleepSystem ();
615 if (msg
& kIOPMSetDesktopMode
) {
616 desktopMode
= (0 != (msg
& kIOPMSetValue
));
617 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
619 if (msg
& kIOPMSetACAdaptorConnected
) {
620 acAdaptorConnect
= (0 != (msg
& kIOPMSetValue
));
621 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
623 if (msg
& kIOPMEnableClamshell
) {
624 ignoringClamshell
= false;
626 if (msg
& kIOPMDisableClamshell
) {
627 ignoringClamshell
= true;
630 if (msg
& kIOPMProcessorSpeedChange
) {
631 IOService
*pmu
= waitForService(serviceMatching("ApplePMU"));
632 pmu
->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
633 pm_vars
->thePlatform
->sleepKernel();
634 pmu
->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
637 if (msg
& kIOPMSleepNow
) {
638 (void) sleepSystem ();
641 if (msg
& kIOPMPowerEmergency
) {
642 (void) sleepSystem ();
645 if (msg
& kIOPMClamshellClosed
) {
646 if ( !ignoringClamshell
&& !ignoringClamshellDuringWakeup
647 && (!desktopMode
|| !acAdaptorConnect
) ) {
649 (void) sleepSystem ();
653 if (msg
& kIOPMPowerButton
) { // toggle state of sleep/wake
654 if ( pm_vars
->myCurrentState
== DOZE_STATE
) { // are we dozing?
655 systemWake(); // yes, tell the tree we're waking
656 reportUserInput(); // wake the Display Wrangler
659 (void) sleepSystem ();
663 // if the case has been closed, we allow
664 // the machine to be put to sleep or to idle sleep
666 if ( (msg
& kIOPMAllowSleep
) && !allowSleep
) {
671 // if the case has been opened, we disallow sleep/doze
673 if (msg
& kIOPMPreventSleep
) {
675 if ( pm_vars
->myCurrentState
== DOZE_STATE
) { // are we dozing?
676 systemWake(); // yes, tell the tree we're waking
678 reportUserInput(); // wake the Display Wrangler
682 patriarch
->wakeSystem(); // make sure we have power to clamp
690 //*********************************************************************************
693 //*********************************************************************************
695 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
697 if ( flags
& kPCICantSleep
) {
701 platformSleepSupport
= flags
;
706 //*********************************************************************************
707 // requestPowerDomainState
709 // The root domain intercepts this call to the superclass.
711 // If the clamp bit is not set in the desire, then the child doesn't need the power
712 // state it's requesting; it just wants it. The root ignores desires but not needs.
713 // If the clamp bit is not set, the root takes it that the child can tolerate no
714 // power and interprets the request accordingly. If all children can thus tolerate
715 // no power, we are on our way to idle sleep.
716 //*********************************************************************************
718 IOReturn
IOPMrootDomain::requestPowerDomainState ( IOPMPowerFlags desiredState
, IOPowerConnection
* whichChild
, unsigned long specification
)
722 IOPowerConnection
* connection
;
723 unsigned long powerRequestFlag
= 0;
724 IOPMPowerFlags editedDesire
= desiredState
;
726 if ( !(desiredState
& kIOPMPreventIdleSleep
) ) { // if they don't really need it, they don't get it
731 IOLockLock(pm_vars
->childLock
); // recompute sleepIsSupported
732 // and see if all children are asleep
733 iter
= getChildIterator(gIOPowerPlane
);
734 sleepIsSupported
= true;
737 while ( (next
= iter
->getNextObject()) ) {
738 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
739 if ( connection
== whichChild
) {
740 powerRequestFlag
+= editedDesire
;
741 if ( desiredState
& kIOPMPreventSystemSleep
) {
742 sleepIsSupported
= false;
746 powerRequestFlag
+= connection
->getDesiredDomainState();
747 if ( connection
->getPreventSystemSleepFlag() ) {
748 sleepIsSupported
= false;
756 if ( (extraSleepDelay
== 0) && (powerRequestFlag
== 0) ) {
760 adjustPowerState(); // this may put the system to sleep
762 IOLockUnlock(pm_vars
->childLock
);
764 editedDesire
|= desiredState
& kIOPMPreventSystemSleep
;
766 return super::requestPowerDomainState(editedDesire
,whichChild
,specification
);
770 //*********************************************************************************
773 //*********************************************************************************
775 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
777 return( platformSleepSupport
);
781 //*********************************************************************************
784 // We override the superclass implementation so we can send a different message
785 // type to the client or application being notified.
786 //*********************************************************************************
788 bool IOPMrootDomain::tellChangeDown ( unsigned long stateNum
)
790 switch ( stateNum
) {
793 return super::tellClientsWithResponse(kIOMessageSystemWillSleep
);
795 return super::tellClientsWithResponse(kIOMessageSystemWillRestart
);
797 return super::tellClientsWithResponse(kIOMessageSystemWillPowerOff
);
799 return super::tellChangeDown(stateNum
); // this shouldn't execute
803 //*********************************************************************************
806 // We override the superclass implementation so we can send a different message
807 // type to the client or application being notified.
809 // This must be idle sleep since we don't ask apps during any other power change.
810 //*********************************************************************************
812 bool IOPMrootDomain::askChangeDown ( unsigned long )
814 return super::tellClientsWithResponse(kIOMessageCanSystemSleep
);
818 //*********************************************************************************
821 // Notify registered applications and kernel clients that we are not
824 // We override the superclass implementation so we can send a different message
825 // type to the client or application being notified.
827 // This must be a vetoed idle sleep, since no other power change can be vetoed.
828 //*********************************************************************************
830 void IOPMrootDomain::tellNoChangeDown ( unsigned long )
832 return tellClients(kIOMessageSystemWillNotSleep
);
836 //*********************************************************************************
839 // Notify registered applications and kernel clients that we are raising power.
841 // We override the superclass implementation so we can send a different message
842 // type to the client or application being notified.
843 //*********************************************************************************
845 void IOPMrootDomain::tellChangeUp ( unsigned long stateNum
)
847 if ( stateNum
== ON_STATE
) {
848 return tellClients(kIOMessageSystemHasPoweredOn
);
852 //*********************************************************************************
855 //*********************************************************************************
857 void IOPMrootDomain::reportUserInput ( void )
862 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
864 wrangler
= (IOService
*) iter
->getNextObject();
870 wrangler
->activityTickle(0,0);
873 //*********************************************************************************
874 // setQuickSpinDownTimeout
876 //*********************************************************************************
878 void IOPMrootDomain::setQuickSpinDownTimeout ( void )
880 //IOLog("setQuickSpinDownTimeout\n");
881 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown
,(unsigned long)1);
884 //*********************************************************************************
885 // restoreUserSpinDownTimeout
887 //*********************************************************************************
889 void IOPMrootDomain::restoreUserSpinDownTimeout ( void )
891 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown
,(unsigned long)user_spindown
);
894 //*********************************************************************************
895 // changePowerStateTo & changePowerStateToPriv
897 // Override of these methods for logging purposes.
898 //*********************************************************************************
900 IOReturn
IOPMrootDomain::changePowerStateTo ( unsigned long ordinal
)
902 ioSPMTrace(IOPOWER_ROOT
, * (int *) this, (int) true, (int) ordinal
);
904 return super::changePowerStateTo(ordinal
);
907 IOReturn
IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal
)
909 ioSPMTrace(IOPOWER_ROOT
, * (int *) this, (int) false, (int) ordinal
);
911 return super::changePowerStateToPriv(ordinal
);
915 //*********************************************************************************
916 // sysPowerDownHandler
918 // Receives a notification when the RootDomain changes state.
920 // Allows us to take action on system sleep, power down, and restart after
921 // applications have received their power change notifications and replied,
922 // but before drivers have powered down. We perform a vfs sync on power down.
923 //*********************************************************************************
925 IOReturn
IOPMrootDomain::sysPowerDownHandler( void * target
, void * refCon
,
926 UInt32 messageType
, IOService
* service
,
927 void * messageArgument
, vm_size_t argSize
)
930 IOPowerStateChangeNotification
* params
= (IOPowerStateChangeNotification
*) messageArgument
;
931 IOPMrootDomain
* rootDomain
= OSDynamicCast(IOPMrootDomain
, service
);
934 return kIOReturnUnsupported
;
936 switch (messageType
) {
937 case kIOMessageSystemWillSleep
:
938 rootDomain
->powerOverrideOnPriv(); // start ignoring children's requests
939 // (fall through to other cases)
941 // Interested applications have been notified of an impending power
942 // change and have acked (when applicable).
943 // This is our chance to save whatever state we can before powering
945 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
948 // We will ack within 20 seconds
949 params
->returnValue
= 20 * 1000 * 1000;
951 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
953 // Purposely delay the ack and hope that shutdown occurs quickly.
954 // Another option is not to schedule the thread and wait for
956 AbsoluteTime deadline
;
957 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
958 thread_call_enter1_delayed( rootDomain
->diskSyncCalloutEntry
,
959 (thread_call_param_t
)params
->powerRef
,
963 thread_call_enter1(rootDomain
->diskSyncCalloutEntry
, (thread_call_param_t
)params
->powerRef
);
964 ret
= kIOReturnSuccess
;
967 case kIOMessageSystemWillPowerOff
:
968 case kIOMessageSystemWillRestart
:
969 ret
= kIOReturnUnsupported
;
973 ret
= kIOReturnUnsupported
;
979 //*********************************************************************************
980 // displayWranglerNotification
982 // Receives a notification when the IODisplayWrangler changes state.
984 // Allows us to take action on display dim/undim.
986 // When the display goes dim we:
987 // - Start the idle sleep timer
988 // - set the quick spin down timeout
990 // On wake from display dim:
991 // - Cancel the idle sleep timer
992 // - restore the user's chosen spindown timer from the "quick" spin down value
993 //*********************************************************************************
995 IOReturn
IOPMrootDomain::displayWranglerNotification( void * target
, void * refCon
,
996 UInt32 messageType
, IOService
* service
,
997 void * messageArgument
, vm_size_t argSize
)
999 IOPMrootDomain
* rootDomain
= OSDynamicCast(IOPMrootDomain
, (IOService
*)target
);
1000 AbsoluteTime deadline
;
1001 static bool deviceAlreadyPoweredOff
= false;
1004 return kIOReturnUnsupported
;
1006 switch (messageType
) {
1007 case kIOMessageDeviceWillPowerOff
:
1008 // The IODisplayWrangler has powered off either because of idle display sleep
1009 // or force system sleep.
1011 // The display wrangler will send the DeviceWillPowerOff message 4 times until
1012 // it gets into its lowest state. We only want to act on the first of those 4.
1013 if( deviceAlreadyPoweredOff
) return kIOReturnUnsupported
;
1015 deviceAlreadyPoweredOff
= true;
1017 if( rootDomain
->extraSleepDelay
) {
1019 // start the extra sleep timer
1020 clock_interval_to_deadline(rootDomain
->extraSleepDelay
*60, kSecondScale
, &deadline
);
1021 thread_call_enter_delayed(rootDomain
->extraSleepTimer
, deadline
);
1022 rootDomain
->idleSleepPending
= true;
1026 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
1027 // and if system sleep is non-Never
1028 if( (0 != rootDomain
->user_spindown
) && (0 != rootDomain
->sleepSlider
) )
1029 rootDomain
->setQuickSpinDownTimeout();
1034 case kIOMessageDeviceHasPoweredOn
:
1036 // The display has powered on either because of UI activity or wake from sleep/doze
1037 deviceAlreadyPoweredOff
= false;
1038 rootDomain
->adjustPowerState();
1041 // cancel any pending idle sleep
1042 if(rootDomain
->idleSleepPending
) {
1043 thread_call_cancel(rootDomain
->extraSleepTimer
);
1044 rootDomain
->idleSleepPending
= false;
1047 // Change the spindown value back to the user's selection from our accelerated setting
1048 if(0 != rootDomain
->user_spindown
)
1049 rootDomain
->restoreUserSpinDownTimeout();
1051 // Put on the policy maker's on clamp.
1058 return kIOReturnUnsupported
;
1061 //*********************************************************************************
1062 // displayWranglerPublished
1064 // Receives a notification when the IODisplayWrangler is published.
1065 // When it's published we install a power state change handler.
1067 //*********************************************************************************
1069 bool IOPMrootDomain::displayWranglerPublished( void * target
, void * refCon
,
1070 IOService
* newService
)
1072 IOPMrootDomain
* rootDomain
= OSDynamicCast(IOPMrootDomain
, (IOService
*)target
);
1077 rootDomain
->wrangler
= newService
;
1079 // we found the display wrangler, now install a handler
1080 if( !rootDomain
->wrangler
->registerInterest( gIOGeneralInterest
, &displayWranglerNotification
, target
, 0) ) {
1081 IOLog("IOPMrootDomain::displayWranglerPublished registerInterest failed\n");
1089 //*********************************************************************************
1092 // Some condition that affects our wake/sleep/doze decision has changed.
1094 // If the sleep slider is in the off position, we cannot sleep or doze.
1095 // If the enclosure is open, we cannot sleep or doze.
1096 // If the system is still booting, we cannot sleep or doze.
1098 // In those circumstances, we prevent sleep and doze by holding power on with
1099 // changePowerStateToPriv(ON).
1101 // If the above conditions do not exist, and also the sleep timer has expired, we
1102 // allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
1103 // changePowerStateToPriv(DOZE) depending on whether or not we already know the
1104 // platform cannot sleep.
1106 // In this case, sleep or doze will either occur immediately or at the next time
1107 // that no children are holding the system out of idle sleep via the
1108 // kIOPMPreventIdleSleep flag in their power state arrays.
1109 //*********************************************************************************
1111 void IOPMrootDomain::adjustPowerState( void )
1113 if ( (sleepSlider
== 0) ||
1116 changePowerStateToPriv(ON_STATE
);
1121 if ( sleepIsSupported
) {
1122 changePowerStateToPriv(SLEEP_STATE
);
1125 changePowerStateToPriv(DOZE_STATE
);
1132 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1135 #define super IOService
1137 OSDefineMetaClassAndStructors(IORootParent
, IOService
)
1139 // This array exactly parallels the state array for the root domain.
1140 // Power state changes initiated by a device can be vetoed by a client of the device, and
1141 // power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
1142 // so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
1143 // its parent to make the change. That is the reason for this complexity.
1145 static IOPMPowerState patriarchPowerStates
[number_of_power_states
] = {
1146 {1,0,0,0,0,0,0,0,0,0,0,0}, // off
1147 {1,0,RESTART_POWER
,0,0,0,0,0,0,0,0,0}, // reset
1148 {1,0,SLEEP_POWER
,0,0,0,0,0,0,0,0,0}, // sleep
1149 {1,0,DOZE_POWER
,0,0,0,0,0,0,0,0,0}, // doze
1150 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0} // running
1153 bool IORootParent::start ( IOService
* nub
)
1155 mostRecentChange
= ON_STATE
;
1158 registerPowerDriver(this,patriarchPowerStates
,number_of_power_states
);
1159 powerOverrideOnPriv();
1164 void IORootParent::shutDownSystem ( void )
1166 mostRecentChange
= OFF_STATE
;
1167 changePowerStateToPriv(OFF_STATE
);
1171 void IORootParent::restartSystem ( void )
1173 mostRecentChange
= RESTART_STATE
;
1174 changePowerStateToPriv(RESTART_STATE
);
1178 void IORootParent::sleepSystem ( void )
1180 mostRecentChange
= SLEEP_STATE
;
1181 changePowerStateToPriv(SLEEP_STATE
);
1185 void IORootParent::dozeSystem ( void )
1187 mostRecentChange
= DOZE_STATE
;
1188 changePowerStateToPriv(DOZE_STATE
);
1191 // Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
1192 // This brings the parent to doze, which allows the root to step up from sleep to doze.
1194 // In idle sleep, do nothing because the parent is still on and the root can freely change state.
1196 void IORootParent::sleepToDoze ( void )
1198 if ( mostRecentChange
== SLEEP_STATE
) {
1199 changePowerStateToPriv(DOZE_STATE
);
1204 void IORootParent::wakeSystem ( void )
1206 mostRecentChange
= ON_STATE
;
1207 changePowerStateToPriv(ON_STATE
);