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