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