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