]> git.saurik.com Git - apple/xnu.git/blame - iokit/Drivers/platform/drvAppleRootDomain/RootDomain.cpp
xnu-201.tar.gz
[apple/xnu.git] / iokit / Drivers / platform / drvAppleRootDomain / RootDomain.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22#include <IOKit/IOWorkLoop.h>
23#include <IOKit/IOCommandQueue.h>
24#include <IOKit/IOTimerEventSource.h>
25#include <IOKit/IOPlatformExpert.h>
26#include <IOKit/pwr_mgt/RootDomain.h>
27#include <IOKit/pwr_mgt/IOPM.h>
28#include <IOKit/IOMessage.h>
29#include "RootDomainUserClient.h"
0b4e3aa0 30#include "IOKit/pwr_mgt/IOPowerConnection.h"
1c79356b
A
31
32extern "C" {
33extern void kprintf(const char *, ...);
34}
35
36extern const IORegistryPlane * gIOPowerPlane;
37
38void PMreceiveCmd ( OSObject *, void *, void *, void *, void * );
0b4e3aa0 39static void sleepTimerExpired(thread_call_param_t);
1c79356b
A
40
41
0b4e3aa0 42#define number_of_power_states 5
1c79356b 43#define OFF_STATE 0
0b4e3aa0
A
44#define RESTART_STATE 1
45#define SLEEP_STATE 2
46#define DOZE_STATE 3
47#define ON_STATE 4
1c79356b 48
0b4e3aa0
A
49#define ON_POWER kIOPMPowerOn
50#define RESTART_POWER kIOPMRestart
51#define SLEEP_POWER kIOPMAuxPowerOn
52#define DOZE_POWER kIOPMDoze
1c79356b
A
53
54static IOPMPowerState ourPowerStates[number_of_power_states] = {
0b4e3aa0
A
55 {1,0, 0, 0,0,0,0,0,0,0,0,0}, // state 0, off
56 {1,kIOPMRestartCapability, kIOPMRestart, RESTART_POWER,0,0,0,0,0,0,0,0}, // state 1, restart
57 {1,kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER,0,0,0,0,0,0,0,0}, // state 2, sleep
58 {1,kIOPMDoze, kIOPMDoze, DOZE_POWER,0,0,0,0,0,0,0,0}, // state 3, doze
59 {1,kIOPMPowerOn, kIOPMPowerOn, ON_POWER,0,0,0,0,0,0,0,0}, // state 4, on
1c79356b
A
60};
61
62static IOPMrootDomain * gRootDomain;
0b4e3aa0
A
63static UInt32 gSleepOrShutdownPending = 0;
64
1c79356b
A
65
66#define super IOService
67OSDefineMetaClassAndStructors(IOPMrootDomain,IOService)
68
69extern "C"
70{
71 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref = 0)
72 {
73 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
74 }
75
0b4e3aa0
A
76 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref = 0)
77 {
78 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
79 }
80
1c79356b
A
81 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
82 {
83 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
84 }
85
0b4e3aa0
A
86 IOReturn vetoSleepWakeNotification(void * PMrefcon)
87 {
88 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
89 }
90
91 IOReturn rootDomainRestart ( void )
92 {
93 return gRootDomain->restartSystem();
94 }
95
96 IOReturn rootDomainShutdown ( void )
97 {
98 return gRootDomain->shutdownSystem();
99 }
100
101 void IOSystemShutdownNotification ( void )
102 {
103 for ( int i = 0; i < 100; i++ )
104 {
105 if ( OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) ) break;
106 IOSleep( 100 );
107 }
108 }
109
110 int sync_internal(void);
1c79356b
A
111}
112
0b4e3aa0
A
113/*
114A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain
115children it has, but within the constraint of the power state provided by its parent. The driver expresses its desire by
116calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children
117express their desires by calling requestPowerDomainState().
118
119The Root Power Domain owns the policy for idle and demand sleep and doze for the system. It is a power-managed IOService just
120like the others in the system. It implements several power states which correspond to what we see as Sleep, Doze, etc.
121
122The sleep/doze policy is as follows:
123Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards.
124Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero.
125The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep.
126
127These three conditions are enforced using the "driver clamp" by calling changePowerStateTo(). For example, if the case is
128opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or
129the state of the other clamp.
130
131Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item.
132In this case the root's parent actually initiates the power state change so that the root has no choice and does not give
133applications the opportunity to veto the change.
134
135Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep. When this is true, the root's
136children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE)
137to hold itself on until the sleep timer expires. This timer is set for the difference between the sleep timeout slider and
138the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel. For example, if
139the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes,
140when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root
141sets its timer for 25 minutes (30 - 5). When the timer expires, it releases its clamp and now nothing is holding it awake,
142so it falls asleep.
143
144Demand sleep is prevented when the system is booting. When preferences are transmitted by the loginwindow at the end of
145boot, a flag is cleared, and this allows subsequent Demand Sleep.
146
147The 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
148a clamp, but sets a flag which is noticed before actually sleeping the kernel. If the flag is set, the root steps up
149one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and
150ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler
151to be tickled)).
152*/
153
154
155// **********************************************************************************
156
157IOPMrootDomain * IOPMrootDomain::construct( void )
158{
159 IOPMrootDomain * root;
160
161 root = new IOPMrootDomain;
162 if( root)
163 root->init();
164
165 return( root );
166}
167
168// **********************************************************************************
169
170static void disk_sync_callout(thread_call_param_t p0, thread_call_param_t p1)
171{
172 IOService * rootDomain = (IOService *) p0;
173 unsigned long pmRef = (unsigned long) p1;
174
175 sync_internal();
176 rootDomain->allowPowerChange(pmRef);
177}
1c79356b
A
178
179// **********************************************************************************
180// start
181//
182// We don't do much here. The real initialization occurs when the platform
183// expert informs us we are the root.
184// **********************************************************************************
0b4e3aa0
A
185
186
1c79356b
A
187bool IOPMrootDomain::start ( IOService * nub )
188{
189 super::start(nub);
190
191 gRootDomain = this;
192
193 PMinit();
0b4e3aa0 194 setProperty("IOSleepSupported","");
1c79356b 195 allowSleep = true;
0b4e3aa0 196 sleepIsSupported = true;
1c79356b 197 systemBooting = true;
0b4e3aa0
A
198 ignoringClamshell = true;
199 sleepSlider = 0;
200 idleSleepPending = false;
201 canSleep = true;
202 wrangler = NULL;
203 sleepASAP = false;
204
1c79356b
A
205 pm_vars->PMworkloop = IOWorkLoop::workLoop(); // make the workloop
206 pm_vars->commandQueue = IOCommandQueue::commandQueue(this, PMreceiveCmd); // make a command queue
207 if (! pm_vars->commandQueue ||
208 ( pm_vars->PMworkloop->addEventSource( pm_vars->commandQueue) != kIOReturnSuccess) ) {
209 return IOPMNoErr;
210 }
0b4e3aa0
A
211 extraSleepTimer = thread_call_allocate((thread_call_func_t)sleepTimerExpired, (thread_call_param_t) this);
212
213 diskSyncCalloutEntry = thread_call_allocate(&disk_sync_callout, (thread_call_param_t) this);
1c79356b
A
214
215 patriarch = new IORootParent; // create our parent
216 patriarch->init();
217 patriarch->attach(this);
218 patriarch->start(this);
219 patriarch->youAreRoot();
220 patriarch->wakeSystem();
221 patriarch->addPowerChild(this);
222
223 registerPowerDriver(this,ourPowerStates,number_of_power_states);
224
0b4e3aa0
A
225 setPMRootDomain(this);
226 changePowerStateToPriv(ON_STATE); // set a clamp until we sleep
227
228 registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0); // install power change handler
229
230 // Register for a notification when IODisplayWrangler is published
231 addNotification( gIOPublishNotification, serviceMatching("IODisplayWrangler"), &displayWranglerPublished, this, 0);
1c79356b
A
232
233 registerService(); // let clients find us
234
235 return true;
236}
237
238
239//*********************************************************************************
240// youAreRoot
241//
242// Power Managment is informing us that we are the root power domain.
243// We know we are not the root however, since we have just instantiated a parent
244// for ourselves and made it the root. We override this method so it will have
245// no effect
246//*********************************************************************************
247IOReturn IOPMrootDomain::youAreRoot ( void )
248{
249 return IOPMNoErr;
250}
251
1c79356b
A
252// **********************************************************************************
253// command_received
254//
255// We have received a command from ourselves on the command queue.
256// If it is to send a recently-received aggressiveness factor, do so.
257// Otherwise, it's something the superclass enqueued.
258// **********************************************************************************
259void IOPMrootDomain::command_received ( void * command, void * x, void * y, void * z )
260{
261 switch ( (int)command ) {
0b4e3aa0
A
262 case kIOPMBroadcastAggressiveness:
263
264 super::setAggressiveness((unsigned long)x,(unsigned long)y);
265
266 // Save user's spin down timer to restore after we replace it for idle sleep
267 if( (int)x == kPMMinutesToSpinDown ) user_spindown = (unsigned int) y;
268
269 // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer
270 longestNonSleepSlider = pm_vars->current_aggressiveness_values[kPMMinutesToDim];
271
272
1c79356b 273 if ( (int)x == kPMMinutesToSleep ) {
0b4e3aa0
A
274 if ( (sleepSlider == 0) && ((int)y != 0) ) {
275 sleepSlider = (int)y;
276 adjustPowerState(); // idle sleep is now enabled, maybe sleep now
1c79356b 277 }
0b4e3aa0
A
278 sleepSlider = (int)y;
279 if ( sleepSlider == 0 ) {
280 adjustPowerState(); // idle sleep is now disabled
281 patriarch->wakeSystem(); // make sure we're powered
282 }
283 }
284 if ( sleepSlider > longestNonSleepSlider ) {
285 extraSleepDelay = sleepSlider - longestNonSleepSlider ;
286 }
287 else {
288 extraSleepDelay = 0;
1c79356b
A
289 }
290 break;
0b4e3aa0 291
1c79356b
A
292 default:
293 super::command_received(command,x,y,z);
294 break;
295 }
296}
297
298
0b4e3aa0
A
299// **********************************************************************************
300// sleepTimerExpired
301//
302// **********************************************************************************
303static void sleepTimerExpired ( thread_call_param_t us)
304{
305 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
306 }
307
308
309// **********************************************************************************
310// handleSleepTimerExpiration
311//
312// The time between the sleep idle timeout and the next longest one has elapsed.
313// It's time to sleep. Start that by removing the clamp that's holding us awake.
314// **********************************************************************************
315void IOPMrootDomain::handleSleepTimerExpiration ( void )
316{
317 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
318 if(0 != user_spindown)
319 setQuickSpinDownTimeout();
320
321 sleepASAP = true;
322 adjustPowerState();
323}
324
325
1c79356b
A
326//*********************************************************************************
327// setAggressiveness
328//
329// Some aggressiveness factor has changed. We put this change on our
330// command queue so that we can broadcast it to the hierarchy while on
331// the Power Mangement workloop thread. This enables objects in the
332// hierarchy to successfully alter their idle timers, which are all on the
333// same thread.
334//*********************************************************************************
335
336IOReturn IOPMrootDomain::setAggressiveness ( unsigned long type, unsigned long newLevel )
337{
0b4e3aa0
A
338 if ( systemBooting && (type == kPMMinutesToDim) ) {
339 systemBooting = false; // when the login window launches, this method gets called -- system booting is done.
340 IOLog("Root power domain receiving initial preferences\n");
341 adjustPowerState();
342 }
1c79356b 343
0b4e3aa0 344 pm_vars->commandQueue->enqueueCommand(true, (void *)kIOPMBroadcastAggressiveness, (void *) type, (void *) newLevel );
1c79356b
A
345
346 return kIOReturnSuccess;
347}
348
349
350// **********************************************************************************
351// sleepSystem
352//
353// **********************************************************************************
354IOReturn IOPMrootDomain::sleepSystem ( void )
355{
356 kprintf("sleep demand received\n");
357 if ( !systemBooting && allowSleep && sleepIsSupported ) {
358 patriarch->sleepSystem();
0b4e3aa0 359 return kIOReturnSuccess;
1c79356b 360 }
0b4e3aa0
A
361 if ( !systemBooting && allowSleep && !sleepIsSupported ) {
362 patriarch->dozeSystem();
363 return kIOReturnSuccess;
364 }
365 return kIOReturnSuccess;
366}
367
368
369// **********************************************************************************
370// shutdownSystem
371//
372// **********************************************************************************
373IOReturn IOPMrootDomain::shutdownSystem ( void )
374{
375 patriarch->shutDownSystem();
376 return kIOReturnSuccess;
377}
378
379
380// **********************************************************************************
381// restartSystem
382//
383// **********************************************************************************
384IOReturn IOPMrootDomain::restartSystem ( void )
385{
386 patriarch->restartSystem();
1c79356b
A
387 return kIOReturnSuccess;
388}
389
390
391// **********************************************************************************
392// powerChangeDone
393//
394// This overrides powerChangeDone in IOService.
0b4e3aa0
A
395//
396// Finder sleep and idle sleep move us from the ON state to the SLEEP_STATE.
397// In this case:
398// If we just finished going to the SLEEP_STATE, and the platform is capable of true sleep,
399// sleep the kernel. Otherwise switch up to the DOZE_STATE which will keep almost
400// everything as off as it can get.
401//
402// **********************************************************************************
403void IOPMrootDomain::powerChangeDone ( unsigned long previousState )
404{
405 OSNumber * propertyPtr;
406 unsigned short theProperty;
407 AbsoluteTime deadline;
408
409 switch ( pm_vars->myCurrentState ) {
410 case SLEEP_STATE:
411 if ( canSleep && sleepIsSupported ) {
412 idleSleepPending = false; // re-enable this timer for next sleep
413 IOLog("System Sleep\n");
414 pm_vars->thePlatform->sleepKernel(); // sleep now
415
416 // now we're waking
417 clock_interval_to_deadline(30, kSecondScale, &deadline); // stay awake for at least 30 seconds
418 thread_call_enter_delayed(extraSleepTimer, deadline);
419 idleSleepPending = true; // this gets turned off when we sleep again
420 gSleepOrShutdownPending = 0; // sleep transition complete
421 patriarch->wakeSystem(); // get us some power
422
423 IOLog("System Wake\n");
424 systemWake(); // tell the tree we're waking
425
426 propertyPtr = OSDynamicCast(OSNumber,getProperty("WakeEvent"));
427 if ( propertyPtr ) { // find out what woke us
428 theProperty = propertyPtr->unsigned16BitValue();
429 IOLog("Wake event %04x\n",theProperty);
430 if ( (theProperty == 0x0008) || //lid
431 (theProperty == 0x0800) || // front panel button
432 (theProperty == 0x0020) || // external keyboard
433 (theProperty == 0x0001) ) { // internal keyboard
434 reportUserInput();
435 }
436 }
437 else {
438 IOLog("Unknown wake event\n");
439 reportUserInput(); // don't know, call it user input then
440 }
441
442 changePowerStateToPriv(ON_STATE); // wake for thirty seconds
443 powerOverrideOffPriv();
444 }
445 else {
446 patriarch->sleepToDoze(); // allow us to step up a power state
447 changePowerStateToPriv(DOZE_STATE); // and do it
448 }
449 break;
450
451 case DOZE_STATE:
452 if ( previousState != DOZE_STATE ) {
453 IOLog("System Doze\n");
454 }
455 idleSleepPending = false; // re-enable this timer for next sleep
456 gSleepOrShutdownPending = 0;
457 break;
458
459 case RESTART_STATE:
460 IOLog("System Restart\n");
461 PEHaltRestart(kPERestartCPU);
462 break;
463
464 case OFF_STATE:
465 IOLog("System Halt\n");
466 PEHaltRestart(kPEHaltCPU);
467 break;
468 }
469}
470
471
472// **********************************************************************************
473// wakeFromDoze
474//
475// The Display Wrangler calls here when it switches to its highest state. If the
476// system is currently dozing, allow it to wake by making sure the parent is
477// providing power.
1c79356b 478// **********************************************************************************
0b4e3aa0 479void IOPMrootDomain::wakeFromDoze( void )
1c79356b 480{
0b4e3aa0
A
481 if ( pm_vars->myCurrentState == DOZE_STATE ) {
482 canSleep = true; // reset this till next attempt
483 powerOverrideOffPriv();
484 patriarch->wakeSystem(); // allow us to wake if children so desire
1c79356b
A
485 }
486}
487
488
489// **********************************************************************************
490// newUserClient
491//
492// **********************************************************************************
493IOReturn IOPMrootDomain::newUserClient( task_t owningTask, void * /* security_id */, UInt32 type, IOUserClient ** handler )
494{
495 IOReturn err = kIOReturnSuccess;
496 RootDomainUserClient * client;
497
498 client = RootDomainUserClient::withTask(owningTask);
499
500 if( !client || (false == client->attach( this )) ||
501 (false == client->start( this )) ) {
502 if(client) {
503 client->detach( this );
504 client->release();
505 client = NULL;
506 }
507 err = kIOReturnNoMemory;
508 }
509 *handler = client;
510 return err;
511}
512
513//*********************************************************************************
514// receivePowerNotification
515//
516// The power controller is notifying us of a hardware-related power management
517// event that we must handle. This is a result of an 'environment' interrupt from
518// the power mgt micro.
519//*********************************************************************************
520
521IOReturn IOPMrootDomain::receivePowerNotification (UInt32 msg)
522{
523 if (msg & kIOPMSleepNow) {
524 (void) sleepSystem ();
525 }
526
1c79356b
A
527 if (msg & kIOPMPowerEmergency) {
528 (void) sleepSystem ();
529 }
530
531 if (msg & kIOPMClamshellClosed) {
532 if ( ! ignoringClamshell ) {
533 (void) sleepSystem ();
534 }
535 }
536
0b4e3aa0
A
537 if (msg & kIOPMEnableClamshell) {
538 ignoringClamshell = false;
539 }
540 if (msg & kIOPMDisableClamshell) {
1c79356b
A
541 ignoringClamshell = true;
542 }
543
0b4e3aa0
A
544 if (msg & kIOPMPowerButton) { // toggle state of sleep/wake
545 if ( pm_vars->myCurrentState == DOZE_STATE ) { // are we dozing?
546 systemWake(); // yes, tell the tree we're waking
547 reportUserInput(); // wake the Display Wrangler
548 }
549 else {
550 (void) sleepSystem ();
1c79356b 551 }
0b4e3aa0
A
552 }
553
554 // if the case has been closed, we allow
555 // the machine to be put to sleep or to idle sleep
556
557 if ( (msg & kIOPMAllowSleep) && !allowSleep ) {
1c79356b 558 allowSleep = true;
0b4e3aa0 559 adjustPowerState();
1c79356b
A
560 }
561
0b4e3aa0 562 // if the case has been opened, we disallow sleep/doze
1c79356b
A
563
564 if (msg & kIOPMPreventSleep) {
1c79356b 565 allowSleep = false;
0b4e3aa0
A
566 if ( pm_vars->myCurrentState == DOZE_STATE ) { // are we dozing?
567 systemWake(); // yes, tell the tree we're waking
568 adjustPowerState();
569 reportUserInput(); // wake the Display Wrangler
570 }
571 else {
572 adjustPowerState();
573 patriarch->wakeSystem(); // make sure we have power to clamp
574 }
1c79356b
A
575 }
576
577 return 0;
578}
579
580
581//*********************************************************************************
582// sleepSupported
583//
584//*********************************************************************************
585
586void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
587{
0b4e3aa0
A
588 if ( flags & kPCICantSleep ) {
589 canSleep = false;
1c79356b 590 }
0b4e3aa0
A
591 else {
592 platformSleepSupport = flags;
593 }
594
595}
596
597//*********************************************************************************
598// requestPowerDomainState
599//
600// The root domain intercepts this call to the superclass.
601//
602// If the clamp bit is not set in the desire, then the child doesn't need the power
603// state it's requesting; it just wants it. The root ignores desires but not needs.
604// If the clamp bit is not set, the root takes it that the child can tolerate no
605// power and interprets the request accordingly. If all children can thus tolerate
606// no power, we are on our way to idle sleep.
607//*********************************************************************************
608
609IOReturn IOPMrootDomain::requestPowerDomainState ( IOPMPowerFlags desiredState, IOPowerConnection * whichChild, unsigned long specification )
610{
611 OSIterator * iter;
612 OSObject * next;
613 IOPowerConnection * connection;
614 unsigned long powerRequestFlag = 0;
615 IOPMPowerFlags editedDesire = desiredState;
616
617 if ( !(desiredState & kIOPMPreventIdleSleep) ) { // if they don't really need it, they don't get it
618 editedDesire = 0;
619 }
620
621
622 IOLockLock(pm_vars->childLock); // recompute sleepIsSupported
623 // and see if all children are asleep
624 iter = getChildIterator(gIOPowerPlane);
625 sleepIsSupported = true;
626
627 if ( iter ) {
628 while ( (next = iter->getNextObject()) ) {
629 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
630 if ( connection == whichChild ) {
631 powerRequestFlag += editedDesire;
632 if ( desiredState & kIOPMPreventSystemSleep ) {
633 sleepIsSupported = false;
634 }
635 }
636 else {
637 powerRequestFlag += connection->getDesiredDomainState();
638 if ( connection->getPreventSystemSleepFlag() ) {
639 sleepIsSupported = false;
640 }
641 }
642 }
643 }
644 iter->release();
645 }
646
647 if ( (extraSleepDelay == 0) && (powerRequestFlag == 0) ) {
648 sleepASAP = true;
1c79356b 649 }
0b4e3aa0
A
650
651 adjustPowerState(); // this may put the system to sleep
652
653 IOLockUnlock(pm_vars->childLock);
654
655 editedDesire |= desiredState & kIOPMPreventSystemSleep;
1c79356b 656
0b4e3aa0 657 return super::requestPowerDomainState(editedDesire,whichChild,specification);
1c79356b
A
658}
659
0b4e3aa0 660
1c79356b
A
661//*********************************************************************************
662// getSleepSupported
663//
664//*********************************************************************************
665
666IOOptionBits IOPMrootDomain::getSleepSupported( void )
667{
668 return( platformSleepSupport );
669}
670
671
672//*********************************************************************************
673// tellChangeDown
674//
675// We override the superclass implementation so we can send a different message
676// type to the client or application being notified.
677//*********************************************************************************
678
679bool IOPMrootDomain::tellChangeDown ( unsigned long stateNum )
680{
0b4e3aa0
A
681 switch ( stateNum ) {
682 case DOZE_STATE:
683 case SLEEP_STATE:
684 return super::tellClientsWithResponse(kIOMessageSystemWillSleep);
685 case RESTART_STATE:
686 return super::tellClientsWithResponse(kIOMessageSystemWillRestart);
687 case OFF_STATE:
688 return super::tellClientsWithResponse(kIOMessageSystemWillPowerOff);
1c79356b 689 }
0b4e3aa0 690 return super::tellChangeDown(stateNum); // this shouldn't execute
1c79356b
A
691}
692
693
694//*********************************************************************************
695// askChangeDown
696//
697// We override the superclass implementation so we can send a different message
698// type to the client or application being notified.
0b4e3aa0
A
699//
700// This must be idle sleep since we don't ask apps during any other power change.
1c79356b
A
701//*********************************************************************************
702
0b4e3aa0 703bool IOPMrootDomain::askChangeDown ( unsigned long )
1c79356b 704{
0b4e3aa0 705 return super::tellClientsWithResponse(kIOMessageCanSystemSleep);
1c79356b
A
706}
707
708
709//*********************************************************************************
710// tellNoChangeDown
711//
712// Notify registered applications and kernel clients that we are not
713// dropping power.
714//
715// We override the superclass implementation so we can send a different message
716// type to the client or application being notified.
0b4e3aa0
A
717//
718// This must be a vetoed idle sleep, since no other power change can be vetoed.
1c79356b
A
719//*********************************************************************************
720
721void IOPMrootDomain::tellNoChangeDown ( unsigned long )
722{
723 return tellClients(kIOMessageSystemWillNotSleep);
724}
725
726
727//*********************************************************************************
728// tellChangeUp
729//
730// Notify registered applications and kernel clients that we are raising power.
731//
732// We override the superclass implementation so we can send a different message
733// type to the client or application being notified.
734//*********************************************************************************
735
736void IOPMrootDomain::tellChangeUp ( unsigned long )
737{
738 return tellClients(kIOMessageSystemHasPoweredOn);
739}
740
0b4e3aa0
A
741//*********************************************************************************
742// reportUserInput
743//
744//*********************************************************************************
745
746void IOPMrootDomain::reportUserInput ( void )
747{
748 OSIterator * iter;
1c79356b 749
0b4e3aa0
A
750 if(!wrangler) {
751 iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
752 if(iter) {
753 wrangler = (IOService *) iter->getNextObject();
754 iter->release();
755 }
756 }
757
758 if(wrangler)
759 wrangler->activityTickle(0,0);
760}
761
762//*********************************************************************************
763// setQuickSpinDownTimeout
1c79356b 764//
0b4e3aa0
A
765//*********************************************************************************
766
767void IOPMrootDomain::setQuickSpinDownTimeout ( void )
768{
769 //IOLog("setQuickSpinDownTimeout\n");
770 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)1);
771}
772
773//*********************************************************************************
774// restoreUserSpinDownTimeout
775//
776//*********************************************************************************
777
778void IOPMrootDomain::restoreUserSpinDownTimeout ( void )
779{
780 if(systemBooting) {
781 IOLog("!!!!! WARNING !!!!! restoreUserSpinDownTimeout called too early\n");
782 }
783 //IOLog("restoreUserSpinDownTimeout, user_spindown = %u\n", user_spindown);
784
785 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)user_spindown);
786}
787
788
789//*********************************************************************************
790// sysPowerDownHandler
791//
792// Receives a notification when the RootDomain changes state.
793//
794// Allows us to take action on system sleep, power down, and restart after
795// applications have received their power change notifications and replied,
796// but before drivers have powered down. We perform a vfs sync on power down.
797//*********************************************************************************
798
799IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon,
800 UInt32 messageType, IOService * service,
801 void * messageArgument, vm_size_t argSize )
802{
803 IOReturn ret;
804 IOPowerStateChangeNotification * params = (IOPowerStateChangeNotification *) messageArgument;
805 IOPMrootDomain * rootDomain = OSDynamicCast(IOPMrootDomain, service);
806
807 if(!rootDomain)
808 return kIOReturnUnsupported;
809
810 switch (messageType) {
811 case kIOMessageSystemWillSleep:
812 rootDomain->powerOverrideOnPriv(); // start ignoring children's requests
813 // (fall through to other cases)
814 case kIOMessageSystemWillPowerOff:
815 case kIOMessageSystemWillRestart:
816
817 // Interested applications have been notified of an impending power
818 // change and have acked (when applicable).
819 // This is our chance to save whatever state we can before powering
820 // down.
821 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
822 // via callout
823
824 // We will ack within 20 seconds
825 params->returnValue = 20 * 1000 * 1000;
826
827 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
828 {
829 // Purposely delay the ack and hope that shutdown occurs quickly.
830 // Another option is not to schedule the thread and wait for
831 // ack timeout...
832 AbsoluteTime deadline;
833 clock_interval_to_deadline( 15, kSecondScale, &deadline );
834 thread_call_enter1_delayed( rootDomain->diskSyncCalloutEntry,
835 (thread_call_param_t)params->powerRef,
836 deadline );
837 }
838 else
839 thread_call_enter1(rootDomain->diskSyncCalloutEntry, (thread_call_param_t)params->powerRef);
840 ret = kIOReturnSuccess;
841 break;
842 default:
843 ret = kIOReturnUnsupported;
844 break;
845 }
846 return ret;
847}
848
849//*********************************************************************************
850// displayWranglerNotification
851//
852// Receives a notification when the IODisplayWrangler changes state.
853//
854// Allows us to take action on display dim/undim.
855//
856// When the display goes dim we:
857// - Start the idle sleep timer
858// - set the quick spin down timeout
859//
860// On wake from display dim:
861// - Cancel the idle sleep timer
862// - restore the user's chosen spindown timer from the "quick" spin down value
863//*********************************************************************************
1c79356b 864
0b4e3aa0
A
865IOReturn IOPMrootDomain::displayWranglerNotification( void * target, void * refCon,
866 UInt32 messageType, IOService * service,
867 void * messageArgument, vm_size_t argSize )
1c79356b 868{
0b4e3aa0
A
869 IOPMrootDomain * rootDomain = OSDynamicCast(IOPMrootDomain, (IOService *)target);
870 AbsoluteTime deadline;
871 static bool deviceAlreadyPoweredOff = false;
872
873 if(!rootDomain)
874 return kIOReturnUnsupported;
875
876 switch (messageType) {
877 case kIOMessageDeviceWillPowerOff:
878 // The IODisplayWrangler has powered off either because of idle display sleep
879 // or force system sleep.
880
881 // The display wrangler will send the DeviceWillPowerOff message 4 times until
882 // it gets into its lowest state. We only want to act on the first of those 4.
883 if( deviceAlreadyPoweredOff ) return kIOReturnUnsupported;
884
885 deviceAlreadyPoweredOff = true;
886
887 if( rootDomain->extraSleepDelay ) {
888
889 // start the extra sleep timer
890 clock_interval_to_deadline(rootDomain->extraSleepDelay*60, kSecondScale, &deadline );
891 thread_call_enter_delayed(rootDomain->extraSleepTimer, deadline);
892 rootDomain->idleSleepPending = true;
893
894 } else {
895
896 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
897 if(0 != rootDomain->user_spindown)
898 rootDomain->setQuickSpinDownTimeout();
899 }
900
901 break;
902
903 case kIOMessageDeviceHasPoweredOn:
904
905 // The display has powered on either because of UI activity or wake from sleep/doze
906 deviceAlreadyPoweredOff = false;
907 rootDomain->adjustPowerState();
908
909
910 // cancel any pending idle sleep
911 if(rootDomain->idleSleepPending) {
912 thread_call_cancel(rootDomain->extraSleepTimer);
913 rootDomain->idleSleepPending = false;
914 }
915
916 // Change the spindown value back to the user's selection from our accelerated setting
917 if(0 != rootDomain->user_spindown)
918 rootDomain->restoreUserSpinDownTimeout();
919
920 // Put on the policy maker's on clamp.
921
922 break;
923
924 default:
925 break;
926 }
927 return kIOReturnUnsupported;
928 }
929
930//*********************************************************************************
931// displayWranglerPublished
932//
933// Receives a notification when the IODisplayWrangler is published.
934// When it's published we install a power state change handler.
935//
936//*********************************************************************************
937
938bool IOPMrootDomain::displayWranglerPublished( void * target, void * refCon,
939 IOService * newService)
940{
941 IOPMrootDomain * rootDomain = OSDynamicCast(IOPMrootDomain, (IOService *)target);
942
943 if(!rootDomain)
944 return false;
945
946 rootDomain->wrangler = newService;
947
948 // we found the display wrangler, now install a handler
949 if( !rootDomain->wrangler->registerInterest( gIOGeneralInterest, &displayWranglerNotification, target, 0) ) {
950 IOLog("IOPMrootDomain::displayWranglerPublished registerInterest failed\n");
951 return false;
952 }
953
954 return true;
1c79356b
A
955}
956
957
0b4e3aa0
A
958//*********************************************************************************
959// adjustPowerState
960//
961// Some condition that affects our wake/sleep/doze decision has changed.
962//
963// If the sleep slider is in the off position, we cannot sleep or doze.
964// If the enclosure is open, we cannot sleep or doze.
965// If the system is still booting, we cannot sleep or doze.
966//
967// In those circumstances, we prevent sleep and doze by holding power on with
968// changePowerStateToPriv(ON).
969//
970// If the above conditions do not exist, and also the sleep timer has expired, we
971// allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
972// changePowerStateToPriv(DOZE) depending on whether or not we already know the
973// platform cannot sleep.
974//
975// In this case, sleep or doze will either occur immediately or at the next time
976// that no children are holding the system out of idle sleep via the
977// kIOPMPreventIdleSleep flag in their power state arrays.
978//*********************************************************************************
979
980void IOPMrootDomain::adjustPowerState( void )
981{
982 if ( (sleepSlider == 0) ||
983 ! allowSleep ||
984 systemBooting ) {
985 changePowerStateToPriv(ON_STATE);
986 }
987 else {
988 if ( sleepASAP ) {
989 sleepASAP = false;
990 if ( sleepIsSupported ) {
991 changePowerStateToPriv(SLEEP_STATE);
992 }
993 else {
994 changePowerStateToPriv(DOZE_STATE);
995 }
996 }
997 }
998}
1c79356b
A
999
1000
1001/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1002
1003#undef super
1004#define super IOService
1005
1006OSDefineMetaClassAndStructors(IORootParent, IOService)
1007
0b4e3aa0
A
1008// This array exactly parallels the state array for the root domain.
1009// Power state changes initiated by a device can be vetoed by a client of the device, and
1010// power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
1011// so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
1012// its parent to make the change. That is the reason for this complexity.
1c79356b 1013
0b4e3aa0 1014static IOPMPowerState patriarchPowerStates[number_of_power_states] = {
1c79356b 1015 {1,0,0,0,0,0,0,0,0,0,0,0}, // off
0b4e3aa0 1016 {1,0,RESTART_POWER,0,0,0,0,0,0,0,0,0}, // reset
1c79356b 1017 {1,0,SLEEP_POWER,0,0,0,0,0,0,0,0,0}, // sleep
0b4e3aa0 1018 {1,0,DOZE_POWER,0,0,0,0,0,0,0,0,0}, // doze
1c79356b
A
1019 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0} // running
1020};
1021
1c79356b
A
1022bool IORootParent::start ( IOService * nub )
1023{
0b4e3aa0 1024 mostRecentChange = ON_STATE;
1c79356b
A
1025 super::start(nub);
1026 PMinit();
0b4e3aa0 1027 registerPowerDriver(this,patriarchPowerStates,number_of_power_states);
1c79356b
A
1028 powerOverrideOnPriv();
1029 return true;
1030}
1031
1032
1033void IORootParent::shutDownSystem ( void )
1034{
0b4e3aa0
A
1035 mostRecentChange = OFF_STATE;
1036 changePowerStateToPriv(OFF_STATE);
1037}
1038
1039
1040void IORootParent::restartSystem ( void )
1041{
1042 mostRecentChange = RESTART_STATE;
1043 changePowerStateToPriv(RESTART_STATE);
1c79356b
A
1044}
1045
1046
1047void IORootParent::sleepSystem ( void )
1048{
0b4e3aa0
A
1049 mostRecentChange = SLEEP_STATE;
1050 changePowerStateToPriv(SLEEP_STATE);
1051}
1052
1053
1054void IORootParent::dozeSystem ( void )
1055{
1056 mostRecentChange = DOZE_STATE;
1057 changePowerStateToPriv(DOZE_STATE);
1058}
1059
1060// Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
1061// This brings the parent to doze, which allows the root to step up from sleep to doze.
1062
1063// In idle sleep, do nothing because the parent is still on and the root can freely change state.
1064
1065void IORootParent::sleepToDoze ( void )
1066{
1067 if ( mostRecentChange == SLEEP_STATE ) {
1068 changePowerStateToPriv(DOZE_STATE);
1069 }
1c79356b
A
1070}
1071
1072
1073void IORootParent::wakeSystem ( void )
1074{
0b4e3aa0
A
1075 mostRecentChange = ON_STATE;
1076 changePowerStateToPriv(ON_STATE);
1c79356b
A
1077}
1078