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