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