]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOPMrootDomain.cpp
xnu-1228.0.2.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
CommitLineData
91447636 1/*
0c530ab8 2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28#include <IOKit/IOWorkLoop.h>
9bccf70c 29#include <IOKit/IOCommandGate.h>
1c79356b
A
30#include <IOKit/IOTimerEventSource.h>
31#include <IOKit/IOPlatformExpert.h>
9bccf70c
A
32#include <IOKit/IOKitDebug.h>
33#include <IOKit/IOTimeStamp.h>
1c79356b 34#include <IOKit/pwr_mgt/RootDomain.h>
d52fe63f 35#include <IOKit/pwr_mgt/IOPMPrivate.h>
91447636 36#include <IOKit/IODeviceTreeSupport.h>
1c79356b 37#include <IOKit/IOMessage.h>
0c530ab8 38#include <IOKit/IOReturn.h>
1c79356b 39#include "RootDomainUserClient.h"
0b4e3aa0 40#include "IOKit/pwr_mgt/IOPowerConnection.h"
55e303ae 41#include "IOPMPowerStateQueue.h"
91447636 42#include <IOKit/IOCatalogue.h>
2d21ac55 43#if HIBERNATION
3a60a9f5 44#include <IOKit/IOHibernatePrivate.h>
2d21ac55
A
45#endif
46#include <sys/syslog.h>
47#include <sys/sysctl.h>
48#include <sys/time.h>
49#include "IOServicePrivate.h" // _IOServiceInterestNotifier
50
51
52#if __i386__
53__BEGIN_DECLS
54#include "IOPMrootDomainInternal.h"
55__END_DECLS
56#endif
57
91447636 58
2d21ac55
A
59//#define DEBUG 1
60#if DEBUG
61#define DEBUG_LOG(x...) do { kprintf(x); } while (0)
62#else
63#define DEBUG_LOG(x...)
3a60a9f5 64#endif
2d21ac55 65#define HaltRestartLog(x...) do { kprintf(x); } while (0)
1c79356b 66
0c530ab8
A
67extern "C" {
68IOReturn OSMetaClassSystemSleepOrWake( UInt32 );
69}
1c79356b
A
70
71extern const IORegistryPlane * gIOPowerPlane;
72
9bccf70c 73IOReturn broadcast_aggressiveness ( OSObject *, void *, void *, void *, void * );
0b4e3aa0 74static void sleepTimerExpired(thread_call_param_t);
d52fe63f 75static void wakeupClamshellTimerExpired ( thread_call_param_t us);
2d21ac55 76static void notifySystemShutdown( IOService * root, unsigned long event );
1c79356b 77
0c530ab8
A
78// "IOPMSetSleepSupported" callPlatformFunction name
79static const OSSymbol *sleepSupportedPEFunction = NULL;
80
81#define kIOSleepSupportedKey "IOSleepSupported"
82
83#define kRD_AllPowerSources (kIOPMSupportedOnAC \
84 | kIOPMSupportedOnBatt \
85 | kIOPMSupportedOnUPS)
1c79356b 86
0b4e3aa0 87#define number_of_power_states 5
1c79356b 88#define OFF_STATE 0
0b4e3aa0
A
89#define RESTART_STATE 1
90#define SLEEP_STATE 2
91#define DOZE_STATE 3
92#define ON_STATE 4
1c79356b 93
0b4e3aa0
A
94#define ON_POWER kIOPMPowerOn
95#define RESTART_POWER kIOPMRestart
96#define SLEEP_POWER kIOPMAuxPowerOn
97#define DOZE_POWER kIOPMDoze
1c79356b 98
2d21ac55
A
99enum
100{
101 // not idle around autowake time, secs
102 kAutoWakePreWindow = 45,
103 kAutoWakePostWindow = 15
104};
105
106
0c530ab8
A
107#define kLocalEvalClamshellCommand (1 << 15)
108
1c79356b 109static IOPMPowerState ourPowerStates[number_of_power_states] = {
0c530ab8
A
110 // state 0, off
111 {1,0, 0, 0,0,0,0,0,0,0,0,0},
112 // state 1, restart
113 {1,kIOPMRestartCapability, kIOPMRestart, RESTART_POWER,0,0,0,0,0,0,0,0},
114 // state 2, sleep
115 {1,kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER,0,0,0,0,0,0,0,0},
116 // state 3, doze
117 {1,kIOPMDoze, kIOPMDoze, DOZE_POWER,0,0,0,0,0,0,0,0},
118 // state 4, on
119 {1,kIOPMPowerOn, kIOPMPowerOn, ON_POWER,0,0,0,0,0,0,0,0},
1c79356b
A
120};
121
6601e61a
A
122static IOPMrootDomain * gRootDomain;
123static UInt32 gSleepOrShutdownPending = 0;
4452a7af 124
2d21ac55
A
125struct timeval gIOLastSleepTime;
126struct timeval gIOLastWakeTime;
127
128// Constants used as arguments to IOPMrootDomain::informCPUStateChange
129#define kCPUUnknownIndex 9999999
130enum {
131 kInformAC = 0,
132 kInformLid = 1,
133 kInformableCount = 2
134};
4452a7af 135
0c530ab8
A
136class PMSettingObject : public OSObject
137{
138 OSDeclareDefaultStructors(PMSettingObject)
139private:
140 IOPMrootDomain *parent;
141 IOPMSettingControllerCallback func;
142 OSObject *target;
143 uintptr_t refcon;
144 uint32_t *publishedFeatureID;
145 int releaseAtCount;
146public:
147 static PMSettingObject *pmSettingObject(
148 IOPMrootDomain *parent_arg,
149 IOPMSettingControllerCallback handler_arg,
150 OSObject *target_arg,
151 uintptr_t refcon_arg,
152 uint32_t supportedPowerSources,
153 const OSSymbol *settings[]);
154
155 void setPMSetting(const OSSymbol *type, OSObject *obj);
156
157 void taggedRelease(const void *tag, const int when) const;
158 void free(void);
159};
160
2d21ac55
A
161/*
162 * Internal helper object for Shutdown/Restart notifications.
163 */
164#define kPMHaltMaxWorkers 8
165#define kPMHaltTimeoutMS 100
166
167class PMHaltWorker : public OSObject
168{
169 OSDeclareDefaultStructors( PMHaltWorker )
170
171public:
172 IOService * service; // service being worked on
173 AbsoluteTime startTime; // time when work started
174 int depth; // work on nubs at this PM-tree depth
175 int visits; // number of nodes visited (debug)
176 IOLock * lock;
177 bool timeout; // service took too long
178
179 static PMHaltWorker * worker( void );
180 static void main( void * arg );
181 static void work( PMHaltWorker * me );
182 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
183 virtual void free( void );
184};
185
186OSDefineMetaClassAndStructors( PMHaltWorker, OSObject )
0c530ab8
A
187
188
1c79356b
A
189#define super IOService
190OSDefineMetaClassAndStructors(IOPMrootDomain,IOService)
191
192extern "C"
193{
91447636 194 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
1c79356b
A
195 {
196 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
197 }
198
91447636 199 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
0b4e3aa0
A
200 {
201 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
202 }
203
1c79356b
A
204 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
205 {
206 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
207 }
208
0b4e3aa0
A
209 IOReturn vetoSleepWakeNotification(void * PMrefcon)
210 {
211 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
212 }
213
214 IOReturn rootDomainRestart ( void )
215 {
216 return gRootDomain->restartSystem();
217 }
218
219 IOReturn rootDomainShutdown ( void )
220 {
221 return gRootDomain->shutdownSystem();
222 }
223
224 void IOSystemShutdownNotification ( void )
225 {
91447636 226 IOCatalogue::disableExternalLinker();
0b4e3aa0
A
227 for ( int i = 0; i < 100; i++ )
228 {
229 if ( OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) ) break;
230 IOSleep( 100 );
231 }
232 }
233
234 int sync_internal(void);
1c79356b
A
235}
236
0b4e3aa0
A
237/*
238A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain
239children it has, but within the constraint of the power state provided by its parent. The driver expresses its desire by
240calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children
241express their desires by calling requestPowerDomainState().
242
243The Root Power Domain owns the policy for idle and demand sleep and doze for the system. It is a power-managed IOService just
244like the others in the system. It implements several power states which correspond to what we see as Sleep, Doze, etc.
245
246The sleep/doze policy is as follows:
247Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards.
248Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero.
249The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep.
250
251These three conditions are enforced using the "driver clamp" by calling changePowerStateTo(). For example, if the case is
252opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or
253the state of the other clamp.
254
255Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item.
256In this case the root's parent actually initiates the power state change so that the root has no choice and does not give
257applications the opportunity to veto the change.
258
259Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep. When this is true, the root's
260children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE)
261to hold itself on until the sleep timer expires. This timer is set for the difference between the sleep timeout slider and
262the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel. For example, if
263the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes,
264when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root
265sets its timer for 25 minutes (30 - 5). When the timer expires, it releases its clamp and now nothing is holding it awake,
266so it falls asleep.
267
268Demand sleep is prevented when the system is booting. When preferences are transmitted by the loginwindow at the end of
269boot, a flag is cleared, and this allows subsequent Demand Sleep.
270
271The 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
272a clamp, but sets a flag which is noticed before actually sleeping the kernel. If the flag is set, the root steps up
273one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and
274ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler
275to be tickled)).
276*/
2d21ac55 277
0b4e3aa0
A
278// **********************************************************************************
279
280IOPMrootDomain * IOPMrootDomain::construct( void )
281{
55e303ae 282 IOPMrootDomain *root;
0b4e3aa0
A
283
284 root = new IOPMrootDomain;
285 if( root)
286 root->init();
287
288 return( root );
289}
290
291// **********************************************************************************
292
293static void disk_sync_callout(thread_call_param_t p0, thread_call_param_t p1)
294{
2d21ac55
A
295 IOService *rootDomain = (IOService *) p0;
296 unsigned long pmRef = (unsigned long) p1;
297
298 DEBUG_LOG("disk_sync_callout: start\n");
0b4e3aa0 299
2d21ac55 300#if HIBERNATION
3a60a9f5 301 IOHibernateSystemSleep();
2d21ac55 302#endif
0b4e3aa0
A
303 sync_internal();
304 rootDomain->allowPowerChange(pmRef);
2d21ac55 305 DEBUG_LOG("disk_sync_callout: finish\n");
0b4e3aa0 306}
1c79356b 307
0c530ab8 308// **********************************************************************************
2d21ac55
A
309
310static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime )
0c530ab8 311{
2d21ac55
A
312 AbsoluteTime endTime;
313 UInt64 nano = 0;
314
315 clock_get_uptime(&endTime);
316 if (CMP_ABSOLUTETIME(&endTime, startTime) > 0)
317 {
318 SUB_ABSOLUTETIME(&endTime, startTime);
319 absolutetime_to_nanoseconds(endTime, &nano);
320 }
0c530ab8 321
2d21ac55
A
322 return (UInt32)(nano / 1000000ULL);
323}
0c530ab8 324
1c79356b
A
325// **********************************************************************************
326// start
327//
328// We don't do much here. The real initialization occurs when the platform
329// expert informs us we are the root.
330// **********************************************************************************
0b4e3aa0 331
2d21ac55
A
332#define kRootDomainSettingsCount 14
333
334static SYSCTL_STRUCT(_kern, OID_AUTO, sleeptime,
335 CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN,
336 &gIOLastSleepTime, timeval, "");
337
338static SYSCTL_STRUCT(_kern, OID_AUTO, waketime,
339 CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN,
340 &gIOLastWakeTime, timeval, "");
341
342static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
0b4e3aa0 343
1c79356b
A
344bool IOPMrootDomain::start ( IOService * nub )
345{
0c530ab8
A
346 OSIterator *psIterator;
347 OSDictionary *tmpDict;
2d21ac55
A
348
349 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
350
0c530ab8
A
351 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
352 {
353 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
2d21ac55 354 gIOPMSettingAutoWakeSecondsKey,
0c530ab8
A
355 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
356 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey),
357 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
358 OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey),
359 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
360 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
361 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
362 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
363 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
364 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
2d21ac55 365 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
0c530ab8
A
366 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey)
367 };
368
55e303ae
A
369
370 pmPowerStateQueue = 0;
d52fe63f 371
e5568f75
A
372 _reserved = (ExpansionData *)IOMalloc(sizeof(ExpansionData));
373 if(!_reserved) return false;
374
1c79356b
A
375 super::start(nub);
376
377 gRootDomain = this;
378
379 PMinit();
0c530ab8
A
380
381 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
382 canSleep = true;
383 setProperty(kIOSleepSupportedKey,true);
91447636 384
2d21ac55 385 userDisabledAllSleep = false;
1c79356b 386 allowSleep = true;
0b4e3aa0 387 sleepIsSupported = true;
1c79356b 388 systemBooting = true;
0b4e3aa0
A
389 sleepSlider = 0;
390 idleSleepPending = false;
0b4e3aa0
A
391 wrangler = NULL;
392 sleepASAP = false;
0c530ab8
A
393 clamshellIsClosed = false;
394 clamshellExists = false;
395 ignoringClamshell = true;
d52fe63f 396 ignoringClamshellDuringWakeup = false;
0c530ab8 397 acAdaptorConnect = true;
2d21ac55
A
398
399 idxPMCPUClamshell = kCPUUnknownIndex;
400 idxPMCPULimitedPower = kCPUUnknownIndex;
401
d52fe63f
A
402 tmpDict = OSDictionary::withCapacity(1);
403 setProperty(kRootDomainSupportedFeatures, tmpDict);
404 tmpDict->release();
91447636 405
0c530ab8
A
406 settingsCallbacks = OSDictionary::withCapacity(1);
407
408 // Create a list of the valid PM settings that we'll relay to
409 // interested clients in setProperties() => setPMSetting()
410 allowedPMSettings = OSArray::withObjects(
411 (const OSObject **)settingsArr,
412 kRootDomainSettingsCount,
413 0);
414
415 fPMSettingsDict = OSDictionary::withCapacity(5);
416
55e303ae 417 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(this);
2d21ac55 418 getPMworkloop()->addEventSource(pmPowerStateQueue);
0c530ab8 419
91447636 420 featuresDictLock = IOLockAlloc();
0c530ab8 421 settingsCtrlLock = IORecursiveLockAlloc();
91447636 422
0c530ab8
A
423 extraSleepTimer = thread_call_allocate(
424 (thread_call_func_t)sleepTimerExpired,
425 (thread_call_param_t) this);
426 clamshellWakeupIgnore = thread_call_allocate(
427 (thread_call_func_t)wakeupClamshellTimerExpired,
428 (thread_call_param_t) this);
429 diskSyncCalloutEntry = thread_call_allocate(
430 &disk_sync_callout,
431 (thread_call_param_t) this);
1c79356b 432
55e303ae
A
433 // create our parent
434 patriarch = new IORootParent;
1c79356b
A
435 patriarch->init();
436 patriarch->attach(this);
437 patriarch->start(this);
1c79356b 438 patriarch->addPowerChild(this);
e5568f75 439
1c79356b
A
440 registerPowerDriver(this,ourPowerStates,number_of_power_states);
441
0b4e3aa0 442 setPMRootDomain(this);
55e303ae
A
443 // set a clamp until we sleep
444 changePowerStateToPriv(ON_STATE);
0b4e3aa0 445
55e303ae
A
446 // install power change handler
447 registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
0b4e3aa0 448
2d21ac55 449#if !NO_KERNEL_HID
0b4e3aa0 450 // Register for a notification when IODisplayWrangler is published
0c530ab8
A
451 _displayWranglerNotifier = addNotification(
452 gIOPublishNotification, serviceMatching("IODisplayWrangler"),
453 &displayWranglerPublished, this, 0);
2d21ac55 454#endif
483a1d10 455
0c530ab8
A
456 // Battery location published - ApplePMU support only
457 _batteryPublishNotifier = addNotification(
458 gIOPublishNotification, serviceMatching("IOPMPowerSource"),
459 &batteryPublished, this, this);
460
1c79356b 461
55e303ae 462 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
91447636 463 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
55e303ae
A
464 ucClassName->release();
465
0c530ab8
A
466 // IOBacklightDisplay can take a long time to load at boot, or it may
467 // not load at all if you're booting with clamshell closed. We publish
468 // 'DisplayDims' here redundantly to get it published early and at all.
469 psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") );
470 if( psIterator && psIterator->getNextObject() )
91447636 471 {
0c530ab8
A
472 // There's at least one battery on the system, so we publish
473 // 'DisplayDims' support for the LCD.
91447636 474 publishFeature("DisplayDims");
0c530ab8
A
475 }
476 if(psIterator) {
477 psIterator->release();
91447636
A
478 }
479
2d21ac55
A
480
481 sysctl_register_oid(&sysctl__kern_sleeptime);
482 sysctl_register_oid(&sysctl__kern_waketime);
483
484#if HIBERNATION
3a60a9f5 485 IOHibernateSystemInit(this);
2d21ac55 486#endif
91447636 487
1c79356b
A
488 registerService(); // let clients find us
489
490 return true;
491}
492
9bccf70c
A
493// **********************************************************************************
494// setProperties
495//
496// Receive a setProperty call
497// The "System Boot" property means the system is completely booted.
498// **********************************************************************************
499IOReturn IOPMrootDomain::setProperties ( OSObject *props_obj)
500{
0c530ab8
A
501 IOReturn return_value = kIOReturnSuccess;
502 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
503 OSBoolean *b;
504 OSNumber *n;
505 OSString *str;
506 OSSymbol *type;
507 OSObject *obj;
508 unsigned int i;
509
510 const OSSymbol *boot_complete_string =
511 OSSymbol::withCString("System Boot Complete");
512 const OSSymbol *sys_shutdown_string =
513 OSSymbol::withCString("System Shutdown");
514 const OSSymbol *stall_halt_string =
515 OSSymbol::withCString("StallSystemAtHalt");
2d21ac55
A
516 const OSSymbol *battery_warning_disabled_string =
517 OSSymbol::withCString("BatteryWarningsDisabled");
518 const OSSymbol *idle_seconds_string =
519 OSSymbol::withCString("System Idle Seconds");
520#if HIBERNATION
0c530ab8
A
521 const OSSymbol *hibernatemode_string =
522 OSSymbol::withCString(kIOHibernateModeKey);
523 const OSSymbol *hibernatefile_string =
524 OSSymbol::withCString(kIOHibernateFileKey);
525 const OSSymbol *hibernatefreeratio_string =
526 OSSymbol::withCString(kIOHibernateFreeRatioKey);
527 const OSSymbol *hibernatefreetime_string =
528 OSSymbol::withCString(kIOHibernateFreeTimeKey);
2d21ac55
A
529#endif
530 const OSSymbol *sleepdisabled_string =
531 OSSymbol::withCString("SleepDisabled");
9bccf70c 532
e5568f75
A
533 if(!dict)
534 {
535 return_value = kIOReturnBadArgument;
536 goto exit;
537 }
4a249263 538
2d21ac55
A
539 if ((n = OSDynamicCast(OSNumber, dict->getObject(idle_seconds_string))))
540 {
541 setProperty(idle_seconds_string, n);
542 idleSeconds = n->unsigned32BitValue();
543 }
544
e5568f75
A
545 if( systemBooting
546 && boot_complete_string
547 && dict->getObject(boot_complete_string))
55e303ae 548 {
9bccf70c 549 systemBooting = false;
9bccf70c 550 adjustPowerState();
0c530ab8
A
551
552 // If lid is closed, re-send lid closed notification
553 // now that booting is complete.
554 if( clamshellIsClosed )
555 {
556 this->receivePowerNotification(kLocalEvalClamshellCommand);
557 }
9bccf70c
A
558 }
559
2d21ac55
A
560 if( battery_warning_disabled_string
561 && dict->getObject(battery_warning_disabled_string))
562 {
563 setProperty( battery_warning_disabled_string,
564 dict->getObject(battery_warning_disabled_string));
565 }
566
0c530ab8
A
567 if( sys_shutdown_string
568 && (b = OSDynamicCast(OSBoolean, dict->getObject(sys_shutdown_string))))
8f6c56a5 569 {
0c530ab8
A
570
571 if(kOSBooleanTrue == b)
572 {
573 /* We set systemShutdown = true during shutdown
574 to prevent sleep at unexpected times while loginwindow is trying
575 to shutdown apps and while the OS is trying to transition to
576 complete power of.
577
578 Set to true during shutdown, as soon as loginwindow shows
579 the "shutdown countdown dialog", through individual app
580 termination, and through black screen kernel shutdown.
581 */
582 kprintf("systemShutdown true\n");
583 systemShutdown = true;
584 } else {
585 /*
586 A shutdown was initiated, but then the shutdown
587 was cancelled, clearing systemShutdown to false here.
588 */
589 kprintf("systemShutdown false\n");
590 systemShutdown = false;
591 }
8f6c56a5 592 }
0c530ab8 593
e5568f75
A
594 if( stall_halt_string
595 && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) )
55e303ae 596 {
4a249263 597 setProperty(stall_halt_string, b);
55e303ae 598 }
91447636 599
2d21ac55 600#if HIBERNATION
3a60a9f5 601 if ( hibernatemode_string
0c530ab8 602 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string))))
3a60a9f5 603 {
0c530ab8 604 setProperty(hibernatemode_string, n);
3a60a9f5
A
605 }
606 if ( hibernatefreeratio_string
0c530ab8 607 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string))))
3a60a9f5 608 {
0c530ab8 609 setProperty(hibernatefreeratio_string, n);
3a60a9f5
A
610 }
611 if ( hibernatefreetime_string
0c530ab8 612 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string))))
3a60a9f5 613 {
0c530ab8 614 setProperty(hibernatefreetime_string, n);
3a60a9f5
A
615 }
616 if ( hibernatefile_string
0c530ab8 617 && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string))))
8f6c56a5 618 {
0c530ab8 619 setProperty(hibernatefile_string, str);
8f6c56a5 620 }
2d21ac55
A
621#endif
622
623 if( sleepdisabled_string
624 && (b = OSDynamicCast(OSBoolean, dict->getObject(sleepdisabled_string))) )
625 {
626 setProperty(sleepdisabled_string, b);
627
628 userDisabledAllSleep = (kOSBooleanTrue == b);
629 }
8f6c56a5 630
0c530ab8
A
631 // Relay our allowed PM settings onto our registered PM clients
632 for(i = 0; i < allowedPMSettings->getCount(); i++) {
e5568f75 633
0c530ab8
A
634 type = (OSSymbol *)allowedPMSettings->getObject(i);
635 if(!type) continue;
8ad349bb 636
0c530ab8
A
637 obj = dict->getObject(type);
638 if(!obj) continue;
2d21ac55
A
639
640 if ((gIOPMSettingAutoWakeSecondsKey == type) && ((n = OSDynamicCast(OSNumber, obj))))
641 {
642 UInt32 rsecs = n->unsigned32BitValue();
643 if (!rsecs)
644 autoWakeStart = autoWakeEnd = 0;
645 else
646 {
647 AbsoluteTime deadline;
648 clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline);
649 autoWakeEnd = AbsoluteTime_to_scalar(&deadline);
650 if (rsecs > kAutoWakePreWindow)
651 rsecs -= kAutoWakePreWindow;
652 else
653 rsecs = 0;
654 clock_interval_to_deadline(rsecs, kSecondScale, &deadline);
655 autoWakeStart = AbsoluteTime_to_scalar(&deadline);
656 }
657 }
0c530ab8
A
658
659 return_value = setPMSetting(type, obj);
660
6601e61a
A
661 if(kIOReturnSuccess != return_value) goto exit;
662 }
663
2d21ac55
A
664exit:
665 if(sleepdisabled_string) sleepdisabled_string->release();
4a249263 666 if(boot_complete_string) boot_complete_string->release();
4a249263 667 if(stall_halt_string) stall_halt_string->release();
2d21ac55 668 if(idle_seconds_string) idle_seconds_string->release();
e5568f75 669 return return_value;
9bccf70c
A
670}
671
1c79356b
A
672
673//*********************************************************************************
674// youAreRoot
675//
676// Power Managment is informing us that we are the root power domain.
677// We know we are not the root however, since we have just instantiated a parent
678// for ourselves and made it the root. We override this method so it will have
679// no effect
680//*********************************************************************************
681IOReturn IOPMrootDomain::youAreRoot ( void )
682{
683 return IOPMNoErr;
684}
685
1c79356b
A
686// **********************************************************************************
687// command_received
688//
9bccf70c 689// No longer used
1c79356b 690// **********************************************************************************
9bccf70c 691void IOPMrootDomain::command_received ( void * w, void * x, void * y, void * z )
1c79356b 692{
9bccf70c
A
693 super::command_received(w,x,y,z);
694}
0b4e3aa0 695
0b4e3aa0 696
9bccf70c
A
697// **********************************************************************************
698// broadcast_aggressiveness
699//
700// **********************************************************************************
701IOReturn broadcast_aggressiveness ( OSObject * root, void * x, void * y, void *, void * )
702{
703 ((IOPMrootDomain *)root)->broadcast_it((unsigned long)x,(unsigned long)y);
704 return IOPMNoErr;
705}
0b4e3aa0
A
706
707
9bccf70c
A
708// **********************************************************************************
709// broadcast_it
710//
711// We are behind the command gate to broadcast an aggressiveness factor. We let the
712// superclass do it, but we need to snoop on factors that affect idle sleep.
713// **********************************************************************************
714void IOPMrootDomain::broadcast_it (unsigned long type, unsigned long value)
715{
716 super::setAggressiveness(type,value);
717
718 // Save user's spin down timer to restore after we replace it for idle sleep
719 if( type == kPMMinutesToSpinDown ) user_spindown = value;
720
721 // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer
2d21ac55
A
722 if (getAggressiveness(kPMMinutesToDim, (unsigned long *)&longestNonSleepSlider)
723 != kIOReturnSuccess)
724 longestNonSleepSlider = 0;
9bccf70c
A
725
726 if ( type == kPMMinutesToSleep ) {
2d21ac55
A
727 DEBUG_LOG("PM idle time -> %ld secs (ena %d)\n", idleSeconds, (value != 0));
728 if (0x7fffffff == value)
729 value = idleSeconds;
730
9bccf70c 731 if ( (sleepSlider == 0) && (value != 0) ) {
2d21ac55
A
732 if (!wrangler)
733 {
734 sleepASAP = false;
735 changePowerStateToPriv(ON_STATE);
736 if (idleSeconds)
737 {
738 AbsoluteTime deadline;
739 // stay awake for at least idleSeconds
740 clock_interval_to_deadline(idleSeconds, kSecondScale, &deadline);
741 thread_call_enter_delayed(extraSleepTimer, deadline);
742 // this gets turned off when we sleep again
743 idleSleepPending = true;
744 }
745 }
746 else
747 {
748 // If sleepASAP is already set, then calling adjustPowerState() here
749 // will put the system to sleep immediately which is bad. Note that
750 // this aggressiveness change can occur without waking up the display
751 // by (dis)connecting the AC adapter. To get around this, the power
752 // clamp is restore to ON state then dropped after waiting for the
753 // sleep timer to expire.
754
755 if (sleepASAP)
756 {
757 AbsoluteTime deadline;
758 // stay awake for at least sleepSlider minutes
759 clock_interval_to_deadline(value * 60, kSecondScale, &deadline);
760 thread_call_enter_delayed(extraSleepTimer, deadline);
761 // this gets turned off when we sleep again
762 idleSleepPending = true;
763 sleepASAP = false;
764 }
765 }
9bccf70c
A
766 }
767 sleepSlider = value;
768 if ( sleepSlider == 0 ) {
55e303ae
A
769 // idle sleep is now disabled
770 adjustPowerState();
771 // make sure we're powered
772 patriarch->wakeSystem();
9bccf70c
A
773 }
774 }
775 if ( sleepSlider > longestNonSleepSlider ) {
776 extraSleepDelay = sleepSlider - longestNonSleepSlider ;
777 }
778 else {
779 extraSleepDelay = 0;
1c79356b
A
780 }
781}
782
783
0b4e3aa0
A
784// **********************************************************************************
785// sleepTimerExpired
786//
787// **********************************************************************************
788static void sleepTimerExpired ( thread_call_param_t us)
789{
790 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
791 }
792
d52fe63f
A
793
794static void wakeupClamshellTimerExpired ( thread_call_param_t us)
795{
796 ((IOPMrootDomain *)us)->stopIgnoringClamshellEventsDuringWakeup();
797}
798
0b4e3aa0
A
799
800// **********************************************************************************
801// handleSleepTimerExpiration
802//
803// The time between the sleep idle timeout and the next longest one has elapsed.
804// It's time to sleep. Start that by removing the clamp that's holding us awake.
805// **********************************************************************************
806void IOPMrootDomain::handleSleepTimerExpiration ( void )
807{
2d21ac55
A
808 DEBUG_LOG("SleepTimerExpired\n");
809
810 AbsoluteTime time;
811
812 clock_get_uptime(&time);
813 if ((AbsoluteTime_to_scalar(&time) > autoWakeStart) && (AbsoluteTime_to_scalar(&time) < autoWakeEnd))
814 {
815 thread_call_enter_delayed(extraSleepTimer, *((AbsoluteTime *) &autoWakeEnd));
816 return;
817 }
818
0b4e3aa0
A
819 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
820 if(0 != user_spindown)
821 setQuickSpinDownTimeout();
822
823 sleepASAP = true;
824 adjustPowerState();
825}
826
827
d52fe63f
A
828void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void)
829{
d52fe63f
A
830 // Allow clamshell-induced sleep now
831 ignoringClamshellDuringWakeup = false;
832
0c530ab8
A
833 // Re-send clamshell event, in case it causes a sleep
834 if(clamshellIsClosed)
835 this->receivePowerNotification( kLocalEvalClamshellCommand );
d52fe63f
A
836}
837
1c79356b
A
838//*********************************************************************************
839// setAggressiveness
840//
9bccf70c 841// Some aggressiveness factor has changed. We broadcast it to the hierarchy while on
1c79356b
A
842// the Power Mangement workloop thread. This enables objects in the
843// hierarchy to successfully alter their idle timers, which are all on the
844// same thread.
845//*********************************************************************************
846
847IOReturn IOPMrootDomain::setAggressiveness ( unsigned long type, unsigned long newLevel )
848{
2d21ac55
A
849 IOWorkLoop * pmWorkLoop = getPMworkloop();
850 if (pmWorkLoop)
851 pmWorkLoop->runAction(broadcast_aggressiveness,this,(void *)type,(void *)newLevel);
3a60a9f5 852
1c79356b
A
853 return kIOReturnSuccess;
854}
855
856
857// **********************************************************************************
858// sleepSystem
859//
860// **********************************************************************************
2d21ac55 861/* public */
1c79356b
A
862IOReturn IOPMrootDomain::sleepSystem ( void )
863{
2d21ac55
A
864 return sleepSystemOptions (NULL);
865}
866
867/* private */
868IOReturn IOPMrootDomain::sleepSystemOptions ( OSDictionary *options )
869{
870 /* sleepSystem is a public function, and may be called by any kernel driver.
871 * And that's bad - drivers should sleep the system by calling
872 * receivePowerNotification() instead. Drivers should not use sleepSystem.
873 *
874 * Note that user space app calls to IOPMSleepSystem() will also travel
875 * this code path and thus be correctly identified as software sleeps.
876 */
877
878 if (options && options->getObject("OSSwitch"))
879 {
880
881 // Log specific sleep cause for OS Switch hibernation
882 return privateSleepSystem( kIOPMOSSwitchHibernationKey) ;
883
884 } else {
885
886 return privateSleepSystem( kIOPMSoftwareSleepKey);
887
888 }
889}
890
891/* private */
892IOReturn IOPMrootDomain::privateSleepSystem ( const char *sleepReason )
893{
894 // Record sleep cause in IORegistry
895 if (sleepReason) {
896 setProperty(kRootDomainSleepReasonKey, sleepReason);
897 }
898
0c530ab8
A
899 if(systemShutdown) {
900 kprintf("Preventing system sleep on grounds of systemShutdown.\n");
1c79356b 901 }
2d21ac55
A
902
903 if( userDisabledAllSleep )
904 {
905 /* Prevent sleep of all kinds if directed to by user space */
906 return kIOReturnNotPermitted;
907 }
0c530ab8 908
2d21ac55
A
909 if ( !systemBooting
910 && !systemShutdown
911 && allowSleep)
912 {
913 if ( !sleepIsSupported ) {
0c530ab8 914 setSleepSupported( kPCICantSleep );
2d21ac55
A
915 kprintf("Sleep prevented by kIOPMPreventSystemSleep flag\n");
916 }
0c530ab8 917 patriarch->sleepSystem();
0b4e3aa0 918 return kIOReturnSuccess;
2d21ac55
A
919 } else {
920 // Unable to sleep because system is in the process of booting or shutting down,
921 // or sleep has otherwise been disallowed.
922 return kIOReturnError;
0b4e3aa0 923 }
0b4e3aa0
A
924}
925
926
927// **********************************************************************************
928// shutdownSystem
929//
930// **********************************************************************************
931IOReturn IOPMrootDomain::shutdownSystem ( void )
932{
55e303ae
A
933 //patriarch->shutDownSystem();
934 return kIOReturnUnsupported;
0b4e3aa0
A
935}
936
937
938// **********************************************************************************
939// restartSystem
940//
941// **********************************************************************************
942IOReturn IOPMrootDomain::restartSystem ( void )
943{
55e303ae
A
944 //patriarch->restartSystem();
945 return kIOReturnUnsupported;
1c79356b
A
946}
947
948
949// **********************************************************************************
950// powerChangeDone
951//
952// This overrides powerChangeDone in IOService.
0b4e3aa0
A
953//
954// Finder sleep and idle sleep move us from the ON state to the SLEEP_STATE.
955// In this case:
956// If we just finished going to the SLEEP_STATE, and the platform is capable of true sleep,
957// sleep the kernel. Otherwise switch up to the DOZE_STATE which will keep almost
958// everything as off as it can get.
959//
960// **********************************************************************************
961void IOPMrootDomain::powerChangeDone ( unsigned long previousState )
962{
963 OSNumber * propertyPtr;
964 unsigned short theProperty;
2d21ac55
A
965 AbsoluteTime deadline;
966
967 DEBUG_LOG("PowerChangeDone: %ld -> %ld\n", previousState, getPowerState());
968
969 switch ( getPowerState() ) {
0b4e3aa0 970 case SLEEP_STATE:
2d21ac55
A
971 if ( previousState != ON_STATE )
972 break;
973
55e303ae
A
974 if ( canSleep && sleepIsSupported )
975 {
976 // re-enable this timer for next sleep
977 idleSleepPending = false;
91447636 978
2d21ac55
A
979 uint32_t secs, microsecs;
980 clock_get_calendar_microtime(&secs, &microsecs);
981 logtime(secs);
982 gIOLastSleepTime.tv_sec = secs;
983 gIOLastSleepTime.tv_usec = microsecs;
984
985#if HIBERNATION
3a60a9f5
A
986 IOLog("System %sSleep\n", gIOHibernateState ? "Safe" : "");
987
988 IOHibernateSystemHasSlept();
2d21ac55
A
989#else
990 IOLog("System Sleep\n");
991#endif
3a60a9f5 992
2d21ac55 993 getPlatform()->sleepKernel();
9bccf70c 994
55e303ae 995 // The CPU(s) are off at this point. When they're awakened by CPU interrupt,
91447636
A
996 // code will resume execution here.
997
55e303ae 998 // Now we're waking...
2d21ac55 999#if HIBERNATION
0c530ab8 1000 IOHibernateSystemWake();
2d21ac55 1001#endif
9bccf70c 1002
55e303ae
A
1003 // stay awake for at least 30 seconds
1004 clock_interval_to_deadline(30, kSecondScale, &deadline);
0b4e3aa0 1005 thread_call_enter_delayed(extraSleepTimer, deadline);
55e303ae
A
1006 // this gets turned off when we sleep again
1007 idleSleepPending = true;
d52fe63f
A
1008
1009 // Ignore closed clamshell during wakeup and for a few seconds
1010 // after wakeup is complete
1011 ignoringClamshellDuringWakeup = true;
1012
55e303ae
A
1013 // sleep transition complete
1014 gSleepOrShutdownPending = 0;
1015
2d21ac55
A
1016 // trip the reset of the calendar clock
1017 clock_wakeup_calendar();
55e303ae
A
1018
1019 // get us some power
1020 patriarch->wakeSystem();
0b4e3aa0 1021
55e303ae
A
1022 // early stage wake notification
1023 tellClients(kIOMessageSystemWillPowerOn);
1024
1025 // tell the tree we're waking
2d21ac55 1026#if HIBERNATION
3a60a9f5 1027 IOLog("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
2d21ac55 1028#endif
55e303ae 1029 systemWake();
d52fe63f
A
1030
1031 // Allow drivers to request extra processing time before clamshell
1032 // sleep if kIOREMSleepEnabledKey is present.
1033 // Ignore clamshell events for at least 5 seconds
1034 if(getProperty(kIOREMSleepEnabledKey)) {
1035 // clamshellWakeupIgnore callout clears ignoreClamshellDuringWakeup bit
1036 clock_interval_to_deadline(5, kSecondScale, &deadline);
0c530ab8
A
1037 if(clamshellWakeupIgnore) {
1038 thread_call_enter_delayed(clamshellWakeupIgnore, deadline);
1039 }
d52fe63f 1040 } else ignoringClamshellDuringWakeup = false;
55e303ae
A
1041
1042 // Find out what woke us
0b4e3aa0 1043 propertyPtr = OSDynamicCast(OSNumber,getProperty("WakeEvent"));
2d21ac55 1044 if ( propertyPtr ) {
0b4e3aa0
A
1045 theProperty = propertyPtr->unsigned16BitValue();
1046 IOLog("Wake event %04x\n",theProperty);
43866e37
A
1047 if ( (theProperty & 0x0008) || //lid
1048 (theProperty & 0x0800) || // front panel button
1049 (theProperty & 0x0020) || // external keyboard
1050 (theProperty & 0x0001) ) { // internal keyboard
55e303ae
A
1051 // We've identified the wakeup event as UI driven
1052 reportUserInput();
0b4e3aa0 1053 }
55e303ae
A
1054 } else {
1055 // Since we can't identify the wakeup event, treat it as UI activity
1056 reportUserInput();
0b4e3aa0 1057 }
55e303ae
A
1058
1059 // Wake for thirty seconds
2d21ac55 1060 changePowerStateToPriv(ON_STATE);
55e303ae
A
1061 } else {
1062 // allow us to step up a power state
1063 patriarch->sleepToDoze();
2d21ac55
A
1064
1065 // ignore children's request for higher power during doze.
1066 powerOverrideOnPriv();
55e303ae 1067 changePowerStateToPriv(DOZE_STATE);
0b4e3aa0
A
1068 }
1069 break;
1070
1071 case DOZE_STATE:
55e303ae
A
1072 if ( previousState != DOZE_STATE )
1073 {
0b4e3aa0
A
1074 IOLog("System Doze\n");
1075 }
55e303ae
A
1076 // re-enable this timer for next sleep
1077 idleSleepPending = false;
0b4e3aa0
A
1078 gSleepOrShutdownPending = 0;
1079 break;
1080
1081 case RESTART_STATE:
1082 IOLog("System Restart\n");
1083 PEHaltRestart(kPERestartCPU);
1084 break;
1085
1086 case OFF_STATE:
1087 IOLog("System Halt\n");
1088 PEHaltRestart(kPEHaltCPU);
1089 break;
1090 }
1091}
1092
1093
1094// **********************************************************************************
1095// wakeFromDoze
1096//
1097// The Display Wrangler calls here when it switches to its highest state. If the
1098// system is currently dozing, allow it to wake by making sure the parent is
1099// providing power.
1c79356b 1100// **********************************************************************************
0b4e3aa0 1101void IOPMrootDomain::wakeFromDoze( void )
1c79356b 1102{
2d21ac55 1103 if ( getPowerState() == DOZE_STATE )
55e303ae 1104 {
0c530ab8
A
1105 // Reset sleep support till next sleep attempt.
1106 // A machine's support of sleep vs. doze can change over the course of
1107 // a running system, so we recalculate it before every sleep.
1108 setSleepSupported(0);
1109
2d21ac55 1110 changePowerStateToPriv(ON_STATE);
0b4e3aa0 1111 powerOverrideOffPriv();
55e303ae
A
1112
1113 // early wake notification
1114 tellClients(kIOMessageSystemWillPowerOn);
1115
1116 // allow us to wake if children so desire
1117 patriarch->wakeSystem();
1c79356b
A
1118 }
1119}
1120
1121
0c530ab8 1122// *****************************************************************************
d52fe63f
A
1123// publishFeature
1124//
1125// Adds a new feature to the supported features dictionary
1126//
1127//
0c530ab8 1128// *****************************************************************************
d52fe63f
A
1129void IOPMrootDomain::publishFeature( const char * feature )
1130{
0c530ab8
A
1131 publishFeature(feature, kIOPMSupportedOnAC
1132 | kIOPMSupportedOnBatt
1133 | kIOPMSupportedOnUPS,
1134 NULL);
1135 return;
1136}
1137
1138
1139// *****************************************************************************
1140// publishFeature (with supported power source specified)
1141//
1142// Adds a new feature to the supported features dictionary
1143//
1144//
1145// *****************************************************************************
1146void IOPMrootDomain::publishFeature(
1147 const char *feature,
1148 uint32_t supportedWhere,
1149 uint32_t *uniqueFeatureID)
1150{
1151 static uint16_t next_feature_id = 500;
1152
1153 OSNumber *new_feature_data = NULL;
1154 OSNumber *existing_feature = NULL;
1155 OSArray *existing_feature_arr = NULL;
1156 OSObject *osObj = NULL;
1157 uint32_t feature_value = 0;
1158
1159 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
1160
2d21ac55
A
1161// kprintf("IOPMrootDomain::publishFeature [\"%s\":%0x01x]\n", feature, supportedWhere);
1162
0c530ab8
A
1163 if(!supportedWhere) {
1164 // Feature isn't supported anywhere!
1165 return;
1166 }
1167
1168 if(next_feature_id > 5000) {
1169 // Far, far too many features!
1170 return;
1171 }
1172
91447636 1173 if(featuresDictLock) IOLockLock(featuresDictLock);
0c530ab8 1174
91447636
A
1175 OSDictionary *features =
1176 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
1177
0c530ab8
A
1178 // Create new features dict if necessary
1179 if ( features && OSDynamicCast(OSDictionary, features)) {
91447636 1180 features = OSDictionary::withDictionary(features);
0c530ab8 1181 } else {
91447636 1182 features = OSDictionary::withCapacity(1);
0c530ab8
A
1183 }
1184
1185 // Create OSNumber to track new feature
1186
1187 next_feature_id += 1;
1188 if( uniqueFeatureID ) {
1189 // We don't really mind if the calling kext didn't give us a place
1190 // to stash their unique id. Many kexts don't plan to unload, and thus
1191 // have no need to remove themselves later.
1192 *uniqueFeatureID = next_feature_id;
1193 }
1194
1195 feature_value = supportedWhere + (next_feature_id << 16);
1196 new_feature_data = OSNumber::withNumber(
1197 (unsigned long long)feature_value, 32);
1198
1199 // Does features object already exist?
1200 if( (osObj = features->getObject(feature)) )
1201 {
1202 if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
1203 {
1204 // We need to create an OSArray to hold the now 2 elements.
1205 existing_feature_arr = OSArray::withObjects(
1206 (const OSObject **)&existing_feature, 1, 2);
1207 existing_feature_arr->setObject(new_feature_data);
1208 features->setObject(feature, existing_feature_arr);
1209 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
1210 {
1211 // Add object to existing array
1212 existing_feature_arr->setObject(new_feature_data);
1213 }
1214 } else {
1215 // The easy case: no previously existing features listed. We simply
1216 // set the OSNumber at key 'feature' and we're on our way.
1217 features->setObject(feature, new_feature_data);
1218 }
1219
1220 new_feature_data->release();
91447636 1221
91447636 1222 setProperty(kRootDomainSupportedFeatures, features);
0c530ab8 1223
91447636 1224 features->release();
0c530ab8 1225
0c530ab8 1226 if(featuresDictLock) IOLockUnlock(featuresDictLock);
2d21ac55
A
1227
1228 // Notify EnergySaver and all those in user space so they might
1229 // re-populate their feature specific UI
1230 if(pmPowerStateQueue) {
1231 pmPowerStateQueue->featureChangeOccurred(
1232 kIOPMMessageFeatureChange, this);
1233 }
0c530ab8
A
1234}
1235
1236// *****************************************************************************
1237// removePublishedFeature
1238//
1239// Removes previously published feature
1240//
1241//
1242// *****************************************************************************
1243IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
1244{
1245 IOReturn ret = kIOReturnError;
1246 uint32_t feature_value = 0;
1247 uint16_t feature_id = 0;
1248 bool madeAChange = false;
1249
1250 OSSymbol *dictKey = NULL;
1251 OSCollectionIterator *dictIterator = NULL;
1252 OSArray *arrayMember = NULL;
1253 OSNumber *numberMember = NULL;
1254 OSObject *osObj = NULL;
1255 OSNumber *osNum = NULL;
1256
1257 if(featuresDictLock) IOLockLock(featuresDictLock);
1258
1259 OSDictionary *features =
1260 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
1261
1262 if ( features && OSDynamicCast(OSDictionary, features) )
1263 {
1264 // Any modifications to the dictionary are made to the copy to prevent
1265 // races & crashes with userland clients. Dictionary updated
1266 // automically later.
1267 features = OSDictionary::withDictionary(features);
1268 } else {
1269 features = NULL;
1270 ret = kIOReturnNotFound;
1271 goto exit;
1272 }
1273
1274 // We iterate 'features' dictionary looking for an entry tagged
1275 // with 'removeFeatureID'. If found, we remove it from our tracking
1276 // structures and notify the OS via a general interest message.
1277
1278 dictIterator = OSCollectionIterator::withCollection(features);
1279 if(!dictIterator) {
1280 goto exit;
1281 }
1282
1283 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
1284 {
1285 osObj = features->getObject(dictKey);
1286
1287 // Each Feature is either tracked by an OSNumber
1288 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
1289 {
1290 feature_value = numberMember->unsigned32BitValue();
1291 feature_id = (uint16_t)(feature_value >> 16);
1292
1293 if( feature_id == (uint16_t)removeFeatureID )
1294 {
1295 // Remove this node
1296 features->removeObject(dictKey);
1297 madeAChange = true;
1298 break;
1299 }
1300
1301 // Or tracked by an OSArray of OSNumbers
1302 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
1303 {
1304 unsigned int arrayCount = arrayMember->getCount();
1305
1306 for(unsigned int i=0; i<arrayCount; i++)
1307 {
1308 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
1309 if(!osNum) {
1310 continue;
1311 }
1312
1313 feature_value = osNum->unsigned32BitValue();
1314 feature_id = (uint16_t)(feature_value >> 16);
1315
1316 if( feature_id == (uint16_t)removeFeatureID )
1317 {
1318 // Remove this node
1319 if( 1 == arrayCount ) {
1320 // If the array only contains one element, remove
1321 // the whole thing.
1322 features->removeObject(dictKey);
1323 } else {
1324 // Otherwise just remove the element in question.
1325 arrayMember->removeObject(i);
1326 }
1327
1328 madeAChange = true;
1329 break;
1330 }
1331 }
1332 }
1333 }
1334
1335
1336 dictIterator->release();
1337
1338 if( madeAChange )
1339 {
1340 ret = kIOReturnSuccess;
1341
1342 setProperty(kRootDomainSupportedFeatures, features);
1343
1344 // Notify EnergySaver and all those in user space so they might
2d21ac55
A
1345 // re-populate their feature specific UI
1346 if(pmPowerStateQueue) {
1347 pmPowerStateQueue->featureChangeOccurred(
1348 kIOPMMessageFeatureChange, this);
1349 }
0c530ab8
A
1350 } else {
1351 ret = kIOReturnNotFound;
1352 }
1353
1354exit:
1355 if(features) features->release();
1356 if(featuresDictLock) IOLockUnlock(featuresDictLock);
1357 return ret;
5d5c5d0d
A
1358}
1359
5d5c5d0d 1360
0c530ab8
A
1361// **********************************************************************************
1362// unIdleDevice
1363//
1364// Enqueues unidle event to be performed later in a serialized context.
1365//
1366// **********************************************************************************
55e303ae 1367void IOPMrootDomain::unIdleDevice( IOService *theDevice, unsigned long theState )
1c79356b 1368{
55e303ae
A
1369 if(pmPowerStateQueue)
1370 pmPowerStateQueue->unIdleOccurred(theDevice, theState);
1371}
1c79356b 1372
0c530ab8
A
1373// **********************************************************************************
1374// announcePowerSourceChange
1375//
1376// Notifies "interested parties" that the batteries have changed state
1377//
1378// **********************************************************************************
55e303ae
A
1379void IOPMrootDomain::announcePowerSourceChange( void )
1380{
0c530ab8
A
1381 IORegistryEntry *_batteryRegEntry = (IORegistryEntry *) getProperty("BatteryEntry");
1382
1383 // (if possible) re-publish power source state under IOPMrootDomain;
1384 // only do so if the battery controller publishes an IOResource
1385 // defining battery location. Called from ApplePMU battery driver.
483a1d10 1386
483a1d10
A
1387 if(_batteryRegEntry)
1388 {
1389 OSArray *batt_info;
91447636 1390 batt_info = (OSArray *) _batteryRegEntry->getProperty(kIOBatteryInfoKey);
483a1d10
A
1391 if(batt_info)
1392 setProperty(kIOBatteryInfoKey, batt_info);
1393 }
1394
1c79356b
A
1395}
1396
0c530ab8
A
1397
1398// *****************************************************************************
1399// setPMSetting (private)
1400//
1401// Internal helper to relay PM settings changes from user space to individual
1402// drivers. Should be called only by IOPMrootDomain::setProperties.
1403//
1404// *****************************************************************************
1405IOReturn IOPMrootDomain::setPMSetting(
1406 const OSSymbol *type,
1407 OSObject *obj)
e5568f75 1408{
0c530ab8
A
1409 OSArray *arr = NULL;
1410 PMSettingObject *p_obj = NULL;
1411 int count;
1412 int i;
1413
1414 if(NULL == type) return kIOReturnBadArgument;
1415
1416 IORecursiveLockLock(settingsCtrlLock);
6601e61a 1417
0c530ab8
A
1418 fPMSettingsDict->setObject(type, obj);
1419
1420 arr = (OSArray *)settingsCallbacks->getObject(type);
1421 if(NULL == arr) goto exit;
1422 count = arr->getCount();
1423 for(i=0; i<count; i++) {
1424 p_obj = (PMSettingObject *)OSDynamicCast(PMSettingObject, arr->getObject(i));
1425 if(p_obj) p_obj->setPMSetting(type, obj);
1426 }
1427
1428exit:
1429 IORecursiveLockUnlock(settingsCtrlLock);
e5568f75
A
1430 return kIOReturnSuccess;
1431}
1432
0c530ab8
A
1433// *****************************************************************************
1434// copyPMSetting (public)
1435//
1436// Allows kexts to safely read setting values, without being subscribed to
1437// notifications.
1438//
1439// *****************************************************************************
1440OSObject * IOPMrootDomain::copyPMSetting(
1441 OSSymbol *whichSetting)
1442{
1443 OSObject *obj = NULL;
4452a7af 1444
0c530ab8
A
1445 if(!whichSetting) return NULL;
1446
1447 IORecursiveLockLock(settingsCtrlLock);
1448 obj = fPMSettingsDict->getObject(whichSetting);
1449 if(obj) {
1450 obj->retain();
1451 }
1452 IORecursiveLockUnlock(settingsCtrlLock);
1453
1454 return obj;
1455}
1456
1457// *****************************************************************************
1458// registerPMSettingController (public)
1c79356b 1459//
0c530ab8
A
1460// direct wrapper to registerPMSettingController with uint32_t power source arg
1461// *****************************************************************************
1462IOReturn IOPMrootDomain::registerPMSettingController(
1463 const OSSymbol * settings[],
1464 IOPMSettingControllerCallback func,
1465 OSObject *target,
1466 uintptr_t refcon,
1467 OSObject **handle)
1468{
1469 return registerPMSettingController(
1470 settings,
1471 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
1472 func, target, refcon, handle);
1473}
1c79356b 1474
0c530ab8
A
1475// *****************************************************************************
1476// registerPMSettingController (public)
1477//
1478// Kexts may register for notifications when a particular setting is changed.
1479// A list of settings is available in IOPM.h.
1480// Arguments:
1481// * settings - An OSArray containing OSSymbols. Caller should populate this
1482// array with a list of settings caller wants notifications from.
1483// * func - A C function callback of the type IOPMSettingControllerCallback
1484// * target - caller may provide an OSObject *, which PM will pass as an
1485// target to calls to "func"
1486// * refcon - caller may provide an void *, which PM will pass as an
1487// argument to calls to "func"
1488// * handle - This is a return argument. We will populate this pointer upon
1489// call success. Hold onto this and pass this argument to
1490// IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
1491// Returns:
1492// kIOReturnSuccess on success
1493// *****************************************************************************
1494IOReturn IOPMrootDomain::registerPMSettingController(
1495 const OSSymbol * settings[],
1496 uint32_t supportedPowerSources,
1497 IOPMSettingControllerCallback func,
1498 OSObject *target,
1499 uintptr_t refcon,
1500 OSObject **handle)
1c79356b 1501{
0c530ab8
A
1502 PMSettingObject *pmso = NULL;
1503 OSArray *list = NULL;
1504 IOReturn ret = kIOReturnSuccess;
1505 int i;
1506
1507 if( NULL == settings ||
1508 NULL == func ||
1509 NULL == handle)
55e303ae 1510 {
0c530ab8 1511 return kIOReturnBadArgument;
4452a7af 1512 }
0c530ab8 1513
0c530ab8
A
1514 pmso = PMSettingObject::pmSettingObject(
1515 (IOPMrootDomain *)this, func, target,
1516 refcon, supportedPowerSources, settings);
1517
1518 if(!pmso) {
1519 ret = kIOReturnInternalError;
1520 goto bail_no_unlock;
1521 }
1522
1523 IORecursiveLockLock(settingsCtrlLock);
1524 for(i=0; settings[i]; i++)
55e303ae 1525 {
0c530ab8
A
1526 list = (OSArray *)settingsCallbacks->getObject(settings[i]);
1527 if(!list) {
1528 // New array of callbacks for this setting
1529 list = OSArray::withCapacity(1);
1530 settingsCallbacks->setObject(settings[i], list);
1531 list->release();
1532 }
1533
1534 // Add caller to the callback list
1535 list->setObject(pmso);
d52fe63f 1536 }
0c530ab8 1537
2d21ac55
A
1538 IORecursiveLockUnlock(settingsCtrlLock);
1539
0c530ab8
A
1540 ret = kIOReturnSuccess;
1541
1542 // Track this instance by its OSData ptr from now on
1543 *handle = pmso;
0c530ab8
A
1544
1545bail_no_unlock:
1546 if(kIOReturnSuccess != ret)
55e303ae 1547 {
0c530ab8
A
1548 // Error return case
1549 if(pmso) pmso->release();
1550 if(handle) *handle = NULL;
d52fe63f 1551 }
0c530ab8
A
1552 return ret;
1553}
1554
2d21ac55 1555
0c530ab8
A
1556//******************************************************************************
1557// sleepOnClamshellClosed
1558//
1559// contains the logic to determine if the system should sleep when the clamshell
1560// is closed.
1561//******************************************************************************
1562
1563bool IOPMrootDomain::shouldSleepOnClamshellClosed ( void )
1564{
1565 return ( !ignoringClamshell
1566 && !ignoringClamshellDuringWakeup
1567 && !(desktopMode && acAdaptorConnect) );
1568}
1569
1570void IOPMrootDomain::sendClientClamshellNotification ( void )
1571{
1572 /* Only broadcast clamshell alert if clamshell exists. */
1573 if(!clamshellExists)
1574 return;
1575
1576 setProperty(kAppleClamshellStateKey,
1577 clamshellIsClosed ? kOSBooleanTrue : kOSBooleanFalse);
1578
1579 setProperty(kAppleClamshellCausesSleepKey,
1580 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
1581
1582
2d21ac55 1583 /* Argument to message is a bitfiel of
0c530ab8 1584 * ( kClamshellStateBit | kClamshellSleepBit )
0c530ab8 1585 */
2d21ac55
A
1586 messageClients(kIOPMMessageClamshellStateChange,
1587 (void *) ( (clamshellIsClosed ? kClamshellStateBit : 0)
1588 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
0c530ab8
A
1589}
1590
2d21ac55
A
1591//******************************************************************************
1592// informCPUStateChange
1593//
1594// Call into PM CPU code so that CPU power savings may dynamically adjust for
1595// running on battery, with the lid closed, etc.
1596//
1597// informCPUStateChange is a no-op on non x86 systems
1598// only x86 has explicit support in the IntelCPUPowerManagement kext
1599//******************************************************************************
1600
1601void IOPMrootDomain::informCPUStateChange(
1602 uint32_t type,
1603 uint32_t value )
1604{
1605#ifdef __i386__
1606
1607 pmioctlVariableInfo_t varInfoStruct;
1608 int pmCPUret = 0;
1609 const char *varNameStr = NULL;
1610 int32_t *varIndex = NULL;
1611
1612 if (kInformAC == type) {
1613 varNameStr = kIOPMRootDomainBatPowerCString;
1614 varIndex = &idxPMCPULimitedPower;
1615 } else if (kInformLid == type) {
1616 varNameStr = kIOPMRootDomainLidCloseCString;
1617 varIndex = &idxPMCPUClamshell;
1618 } else {
1619 return;
1620 }
1621
1622 // Set the new value!
1623 // pmCPUControl will assign us a new ID if one doesn't exist yet
1624 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
1625 varInfoStruct.varID = *varIndex;
1626 varInfoStruct.varType = vBool;
1627 varInfoStruct.varInitValue = value;
1628 varInfoStruct.varCurValue = value;
1629 strncpy( (char *)varInfoStruct.varName,
1630 (const char *)varNameStr,
1631 strlen(varNameStr) + 1 );
1632
1633 // Set!
1634 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
1635
1636 // pmCPU only assigns numerical id's when a new varName is specified
1637 if ((0 == pmCPUret)
1638 && (*varIndex == kCPUUnknownIndex))
1639 {
1640 // pmCPUControl has assigned us a new variable ID.
1641 // Let's re-read the structure we just SET to learn that ID.
1642 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
1643
1644 if (0 == pmCPUret)
1645 {
1646 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
1647 *varIndex = varInfoStruct.varID;
1648 }
1649 }
1650
1651 return;
1652
1653#endif __i386__
1654}
1655
1656
0c530ab8
A
1657//******************************************************************************
1658// receivePowerNotification
1659//
1660// The power controller is notifying us of a hardware-related power management
1661// event that we must handle. This is a result of an 'environment' interrupt from
1662// the power mgt micro.
1663//******************************************************************************
1664
1665IOReturn IOPMrootDomain::receivePowerNotification (UInt32 msg)
1666{
1667 bool eval_clamshell = false;
1668
1669 /*
1670 * Local (IOPMrootDomain only) eval clamshell command
1671 */
1672 if (msg & kLocalEvalClamshellCommand)
55e303ae 1673 {
0c530ab8 1674 eval_clamshell = true;
d52fe63f 1675 }
0c530ab8
A
1676
1677 /*
1678 * Overtemp
1679 */
1680 if (msg & kIOPMOverTemp)
55e303ae 1681 {
0c530ab8 1682 IOLog("PowerManagement emergency overtemp signal. Going to sleep!");
2d21ac55
A
1683
1684 privateSleepSystem (kIOPMThermalEmergencySleepKey);
d52fe63f
A
1685 }
1686
0c530ab8
A
1687 /*
1688 * PMU Processor Speed Change
1689 */
55e303ae
A
1690 if (msg & kIOPMProcessorSpeedChange)
1691 {
1692 IOService *pmu = waitForService(serviceMatching("ApplePMU"));
1693 pmu->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
2d21ac55 1694 getPlatform()->sleepKernel();
55e303ae 1695 pmu->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
d52fe63f
A
1696 }
1697
0c530ab8
A
1698 /*
1699 * Sleep Now!
1700 */
55e303ae
A
1701 if (msg & kIOPMSleepNow)
1702 {
2d21ac55 1703 privateSleepSystem (kIOPMSoftwareSleepKey);
1c79356b
A
1704 }
1705
0c530ab8
A
1706 /*
1707 * Power Emergency
1708 */
55e303ae
A
1709 if (msg & kIOPMPowerEmergency)
1710 {
2d21ac55 1711 privateSleepSystem (kIOPMLowPowerSleepKey);
1c79356b
A
1712 }
1713
0c530ab8
A
1714
1715 /*
1716 * Clamshell OPEN
1717 */
1718 if (msg & kIOPMClamshellOpened)
1719 {
1720 // Received clamshel open message from clamshell controlling driver
1721 // Update our internal state and tell general interest clients
1722 clamshellIsClosed = false;
1723 clamshellExists = true;
1724
2d21ac55
A
1725 // Tell PMCPU
1726 informCPUStateChange(kInformLid, 0);
1727
1728 // Tell general interest clients
0c530ab8
A
1729 sendClientClamshellNotification();
1730 }
1731
1732 /*
1733 * Clamshell CLOSED
1734 * Send the clamshell interest notification since the lid is closing.
1735 */
1736 if (msg & kIOPMClamshellClosed)
1737 {
1738 // Received clamshel open message from clamshell controlling driver
1739 // Update our internal state and tell general interest clients
1740 clamshellIsClosed = true;
1741 clamshellExists = true;
1742
2d21ac55
A
1743 // Tell PMCPU
1744 informCPUStateChange(kInformLid, 1);
1745
1746 // Tell general interest clients
0c530ab8
A
1747 sendClientClamshellNotification();
1748
1749 // And set eval_clamshell = so we can attempt
1750 eval_clamshell = true;
1751 }
1752
1753 /*
1754 * Set Desktop mode (sent from graphics)
1755 *
1756 * -> reevaluate lid state
1757 */
1758 if (msg & kIOPMSetDesktopMode)
4452a7af 1759 {
0c530ab8
A
1760 desktopMode = (0 != (msg & kIOPMSetValue));
1761 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
1762
1763 sendClientClamshellNotification();
1764
1765 // Re-evaluate the lid state
1766 if( clamshellIsClosed )
4452a7af 1767 {
0c530ab8
A
1768 eval_clamshell = true;
1769 }
1770 }
1771
1772 /*
1773 * AC Adaptor connected
1774 *
1775 * -> reevaluate lid state
1776 */
1777 if (msg & kIOPMSetACAdaptorConnected)
1778 {
1779 acAdaptorConnect = (0 != (msg & kIOPMSetValue));
1780 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
4452a7af 1781
2d21ac55
A
1782 // Tell PMCPU
1783 informCPUStateChange(kInformAC, !acAdaptorConnect);
1784
0c530ab8
A
1785 sendClientClamshellNotification();
1786
1787 // Re-evaluate the lid state
1788 if( clamshellIsClosed )
1789 {
1790 eval_clamshell = true;
4452a7af 1791 }
0c530ab8
A
1792
1793 }
1794
1795 /*
1796 * Enable Clamshell (external display disappear)
1797 *
1798 * -> reevaluate lid state
1799 */
1800 if (msg & kIOPMEnableClamshell)
1801 {
1802 // Re-evaluate the lid state
1803 // System should sleep on external display disappearance
1804 // in lid closed operation.
1805 if( clamshellIsClosed && (true == ignoringClamshell) )
1806 {
1807 eval_clamshell = true;
1808 }
1809
1810 ignoringClamshell = false;
1811
1812 sendClientClamshellNotification();
1813 }
1814
1815 /*
1816 * Disable Clamshell (external display appeared)
1817 * We don't bother re-evaluating clamshell state. If the system is awake,
1818 * the lid is probably open.
1819 */
1820 if (msg & kIOPMDisableClamshell)
1821 {
1822 ignoringClamshell = true;
1823
1824 sendClientClamshellNotification();
1825 }
1826
1827 /*
1828 * Evaluate clamshell and SLEEP if appropiate
1829 */
1830 if ( eval_clamshell && shouldSleepOnClamshellClosed() )
1831 {
1832
1833
1834 // SLEEP!
2d21ac55 1835 privateSleepSystem (kIOPMClamshellSleepKey);
4452a7af
A
1836 }
1837
0c530ab8
A
1838 /*
1839 * Power Button
1840 */
55e303ae 1841 if (msg & kIOPMPowerButton)
2d21ac55 1842 {
55e303ae
A
1843 // toggle state of sleep/wake
1844 // are we dozing?
2d21ac55 1845 if ( getPowerState() == DOZE_STATE )
55e303ae
A
1846 {
1847 // yes, tell the tree we're waking
1848 systemWake();
1849 // wake the Display Wrangler
2d21ac55 1850 reportUserInput();
0b4e3aa0
A
1851 }
1852 else {
0c530ab8 1853 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
55e303ae 1854 // Check that power button sleep is enabled
0c530ab8
A
1855 if( pbs ) {
1856 if( kOSBooleanTrue != getProperty(pbs))
2d21ac55 1857 privateSleepSystem (kIOPMPowerButtonSleepKey);
0c530ab8 1858 }
1c79356b 1859 }
0b4e3aa0
A
1860 }
1861
0c530ab8
A
1862 /*
1863 * Allow Sleep
1864 *
1865 */
55e303ae
A
1866 if ( (msg & kIOPMAllowSleep) && !allowSleep )
1867 {
1868 allowSleep = true;
0b4e3aa0 1869 adjustPowerState();
1c79356b
A
1870 }
1871
0c530ab8
A
1872 /*
1873 * Prevent Sleep
1874 *
1875 */
1c79356b 1876 if (msg & kIOPMPreventSleep) {
55e303ae
A
1877 allowSleep = false;
1878 // are we dozing?
2d21ac55 1879 if ( getPowerState() == DOZE_STATE ) {
55e303ae
A
1880 // yes, tell the tree we're waking
1881 systemWake();
0b4e3aa0 1882 adjustPowerState();
55e303ae
A
1883 // wake the Display Wrangler
1884 reportUserInput();
1885 } else {
0b4e3aa0 1886 adjustPowerState();
55e303ae
A
1887 // make sure we have power to clamp
1888 patriarch->wakeSystem();
0b4e3aa0 1889 }
1c79356b
A
1890 }
1891
1892 return 0;
1893}
1894
1895
1896//*********************************************************************************
1897// sleepSupported
1898//
1899//*********************************************************************************
1900
1901void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
1902{
55e303ae
A
1903 if ( flags & kPCICantSleep )
1904 {
0b4e3aa0 1905 canSleep = false;
55e303ae 1906 } else {
0c530ab8 1907 canSleep = true;
0b4e3aa0
A
1908 platformSleepSupport = flags;
1909 }
1910
0c530ab8
A
1911 setProperty(kIOSleepSupportedKey, canSleep);
1912
0b4e3aa0
A
1913}
1914
1915//*********************************************************************************
1916// requestPowerDomainState
1917//
1918// The root domain intercepts this call to the superclass.
2d21ac55 1919// Called on the PM work loop thread.
0b4e3aa0
A
1920//
1921// If the clamp bit is not set in the desire, then the child doesn't need the power
1922// state it's requesting; it just wants it. The root ignores desires but not needs.
1923// If the clamp bit is not set, the root takes it that the child can tolerate no
1924// power and interprets the request accordingly. If all children can thus tolerate
1925// no power, we are on our way to idle sleep.
1926//*********************************************************************************
1927
2d21ac55
A
1928IOReturn IOPMrootDomain::requestPowerDomainState (
1929 IOPMPowerFlags desiredState,
1930 IOPowerConnection * whichChild,
1931 unsigned long specification )
0b4e3aa0 1932{
2d21ac55
A
1933 OSIterator *iter;
1934 OSObject *next;
1935 IOPowerConnection *connection;
1936 unsigned long powerRequestFlag = 0;
1937 IOPMPowerFlags editedDesire;
1938
1939#if DEBUG
1940 IOService *powerChild;
1941 powerChild = (IOService *) whichChild->getChildEntry(gIOPowerPlane);
1942#endif
55e303ae 1943
2d21ac55
A
1944 DEBUG_LOG("RequestPowerDomainState: flags %lx, child %p [%s], spec %lx\n",
1945 desiredState, powerChild, powerChild ? powerChild->getName() : "?",
1946 specification);
1947
1948 // Force the child's input power requirements to 0 unless the prevent
1949 // idle-sleep flag is set. No input power flags map to our state 0.
1950 // Our power clamp (deviceDesire) keeps the minimum power state at 2.
0b4e3aa0 1951
2d21ac55
A
1952 if (desiredState & kIOPMPreventIdleSleep)
1953 editedDesire = desiredState;
1954 else
1955 editedDesire = 0;
0b4e3aa0 1956
2d21ac55
A
1957 // Recompute sleep supported flag (doze if not supported)
1958 sleepIsSupported = true;
55e303ae 1959
0b4e3aa0 1960 iter = getChildIterator(gIOPowerPlane);
55e303ae
A
1961 if ( iter )
1962 {
1963 while ( (next = iter->getNextObject()) )
1964 {
2d21ac55 1965 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 1966 {
2d21ac55
A
1967 // Ignore child that are in the process of joining.
1968 if (connection->getReadyFlag() == false)
1969 continue;
1970
1971 // Is this connection attached to the child that called
1972 // requestPowerDomainState()?
1973
55e303ae
A
1974 if ( connection == whichChild )
1975 {
2d21ac55
A
1976 // Yes, OR in the child's input power requirements.
1977 powerRequestFlag |= editedDesire;
1978
1979 if ( desiredState & kIOPMPreventSystemSleep )
0b4e3aa0 1980 sleepIsSupported = false;
2d21ac55
A
1981 }
1982 else
1983 {
1984#if DEBUG
1985 powerChild = (IOService *) connection->getChildEntry(gIOPowerPlane);
1986#endif
1987 DEBUG_LOG(" child %p, PState %ld, noIdle %d, noSleep %d, valid %d %s\n",
1988 powerChild,
1989 connection->getDesiredDomainState(),
1990 connection->getPreventIdleSleepFlag(),
1991 connection->getPreventSystemSleepFlag(),
1992 connection->getReadyFlag(),
1993 powerChild ? powerChild->getName() : "?");
1994
1995 // No, OR in the child's desired power domain state.
1996 // Which is our power state desired by this child.
1997 powerRequestFlag |= connection->getDesiredDomainState();
1998
1999 if ( connection->getPreventSystemSleepFlag() )
0b4e3aa0 2000 sleepIsSupported = false;
0b4e3aa0
A
2001 }
2002 }
2003 }
2004 iter->release();
2005 }
9bccf70c 2006
2d21ac55 2007 if ( !powerRequestFlag && !systemBooting )
55e303ae 2008 {
2d21ac55
A
2009 if (!wrangler)
2010 {
2011 sleepASAP = false;
2012 changePowerStateToPriv(ON_STATE);
2013 if (idleSeconds)
2014 {
2015 AbsoluteTime deadline;
2016 // stay awake for at least idleSeconds
2017 clock_interval_to_deadline(idleSeconds, kSecondScale, &deadline);
2018 thread_call_enter_delayed(extraSleepTimer, deadline);
2019 // this gets turned off when we sleep again
2020 idleSleepPending = true;
2021 }
2022 }
2023 else if (extraSleepDelay == 0)
2024 {
2025 sleepASAP = true;
2026 }
1c79356b 2027 }
0b4e3aa0 2028
2d21ac55
A
2029 DEBUG_LOG(" sleepDelay %lx, mergedFlags %lx, sleepASAP %x, booting %x\n",
2030 extraSleepDelay, powerRequestFlag, sleepASAP, systemBooting);
2031
2032 // Drop our power clamp to SLEEP_STATE when all devices become idle.
2033 // Needed when the system sleep and display sleep timeouts are the same.
2034 // Otherwise, the extra sleep timer will also drop our power clamp.
2035
55e303ae 2036 adjustPowerState();
0b4e3aa0 2037
2d21ac55 2038 editedDesire |= (desiredState & kIOPMPreventSystemSleep);
1c79356b 2039
2d21ac55
A
2040 // If our power clamp has already dropped to SLEEP_STATE, and no child
2041 // is keeping us at max power, then this will trigger idle sleep.
2042
2043 return super::requestPowerDomainState(editedDesire, whichChild, specification);
1c79356b
A
2044}
2045
0b4e3aa0 2046
1c79356b
A
2047//*********************************************************************************
2048// getSleepSupported
2049//
2050//*********************************************************************************
2051
2052IOOptionBits IOPMrootDomain::getSleepSupported( void )
2053{
2054 return( platformSleepSupport );
2055}
2056
2057
2d21ac55
A
2058//*********************************************************************************
2059// handlePlatformHaltRestart
2060//
2061//*********************************************************************************
2062
2063struct HaltRestartApplierContext {
2064 IOPMrootDomain * RootDomain;
2065 unsigned long PowerState;
2066 IOPMPowerFlags PowerFlags;
2067 UInt32 MessageType;
2068 UInt32 Counter;
2069};
2070
2071static void
2072platformHaltRestartApplier( OSObject * object, void * context )
2073{
2074 IOPowerStateChangeNotification notify;
2075 HaltRestartApplierContext * ctx;
2076 AbsoluteTime startTime;
2077 UInt32 deltaTime;
2078
2079 ctx = (HaltRestartApplierContext *) context;
2080
2081 memset(&notify, 0, sizeof(notify));
2082 notify.powerRef = (void *)ctx->Counter;
2083 notify.returnValue = 0;
2084 notify.stateNumber = ctx->PowerState;
2085 notify.stateFlags = ctx->PowerFlags;
2086
2087 clock_get_uptime(&startTime);
2088 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
2089 deltaTime = computeDeltaTimeMS(&startTime);
2090
2091 if ((deltaTime > kPMHaltTimeoutMS) || (gIOKitDebug & kIOLogDebugPower))
2092 {
2093 _IOServiceInterestNotifier * notifier;
2094 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
2095
2096 // IOService children of IOPMrootDomain are not instrumented.
2097 // Only IORootParent currently falls under that group.
2098
2099 if (notifier)
2100 {
2101 HaltRestartLog("%s handler %p took %lu ms\n",
2102 (ctx->MessageType == kIOMessageSystemWillPowerOff) ?
2103 "PowerOff" : "Restart",
2104 notifier->handler, deltaTime );
2105 }
2106 }
2107
2108 ctx->Counter++;
2109}
2110
2111void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
2112{
2113 HaltRestartApplierContext ctx;
2114 AbsoluteTime startTime;
2115 UInt32 deltaTime;
2116
2117 memset(&ctx, 0, sizeof(ctx));
2118 ctx.RootDomain = this;
2119
2120 clock_get_uptime(&startTime);
2121 switch (pe_type)
2122 {
2123 case kPEHaltCPU:
2124 ctx.PowerState = OFF_STATE;
2125 ctx.MessageType = kIOMessageSystemWillPowerOff;
2126 break;
2127
2128 case kPERestartCPU:
2129 ctx.PowerState = RESTART_STATE;
2130 ctx.MessageType = kIOMessageSystemWillRestart;
2131 break;
2132
2133 default:
2134 return;
2135 }
2136
2137 // Notify legacy clients
2138 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx);
2139
2140 // Notify in power tree order
2141 notifySystemShutdown(this, ctx.MessageType);
2142
2143 deltaTime = computeDeltaTimeMS(&startTime);
2144 HaltRestartLog("%s all drivers took %lu ms\n",
2145 (ctx.MessageType == kIOMessageSystemWillPowerOff) ?
2146 "PowerOff" : "Restart",
2147 deltaTime );
2148}
2149
2150
1c79356b
A
2151//*********************************************************************************
2152// tellChangeDown
2153//
2154// We override the superclass implementation so we can send a different message
2155// type to the client or application being notified.
2156//*********************************************************************************
2157
2158bool IOPMrootDomain::tellChangeDown ( unsigned long stateNum )
2159{
0b4e3aa0
A
2160 switch ( stateNum ) {
2161 case DOZE_STATE:
2162 case SLEEP_STATE:
0c530ab8
A
2163
2164 // Direct callout into OSMetaClass so it can disable kmod unloads
2165 // during sleep/wake to prevent deadlocks.
2166 OSMetaClassSystemSleepOrWake( kIOMessageSystemWillSleep );
2167
0b4e3aa0 2168 return super::tellClientsWithResponse(kIOMessageSystemWillSleep);
1c79356b 2169 }
55e303ae 2170 return super::tellChangeDown(stateNum);
1c79356b
A
2171}
2172
2173
2174//*********************************************************************************
2175// askChangeDown
2176//
2177// We override the superclass implementation so we can send a different message
2178// type to the client or application being notified.
0b4e3aa0
A
2179//
2180// This must be idle sleep since we don't ask apps during any other power change.
1c79356b
A
2181//*********************************************************************************
2182
0b4e3aa0 2183bool IOPMrootDomain::askChangeDown ( unsigned long )
1c79356b 2184{
0b4e3aa0 2185 return super::tellClientsWithResponse(kIOMessageCanSystemSleep);
1c79356b
A
2186}
2187
2188
2189//*********************************************************************************
2190// tellNoChangeDown
2191//
2192// Notify registered applications and kernel clients that we are not
2193// dropping power.
2194//
2195// We override the superclass implementation so we can send a different message
2196// type to the client or application being notified.
0b4e3aa0
A
2197//
2198// This must be a vetoed idle sleep, since no other power change can be vetoed.
1c79356b
A
2199//*********************************************************************************
2200
2201void IOPMrootDomain::tellNoChangeDown ( unsigned long )
2202{
2d21ac55
A
2203 if (idleSeconds && !wrangler)
2204 {
2205 AbsoluteTime deadline;
2206 sleepASAP = false;
2207 // stay awake for at least idleSeconds
2208 clock_interval_to_deadline(idleSeconds, kSecondScale, &deadline);
2209 thread_call_enter_delayed(extraSleepTimer, deadline);
2210 // this gets turned off when we sleep again
2211 idleSleepPending = true;
2212 }
1c79356b
A
2213 return tellClients(kIOMessageSystemWillNotSleep);
2214}
2215
2216
2217//*********************************************************************************
2218// tellChangeUp
2219//
2220// Notify registered applications and kernel clients that we are raising power.
2221//
2222// We override the superclass implementation so we can send a different message
2223// type to the client or application being notified.
2224//*********************************************************************************
2225
7b1edb79 2226void IOPMrootDomain::tellChangeUp ( unsigned long stateNum)
1c79356b 2227{
55e303ae
A
2228 if ( stateNum == ON_STATE )
2229 {
2d21ac55 2230#if HIBERNATION
0c530ab8
A
2231 // Direct callout into OSMetaClass so it can disable kmod unloads
2232 // during sleep/wake to prevent deadlocks.
2233 OSMetaClassSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
2234
3a60a9f5 2235 IOHibernateSystemPostWake();
2d21ac55 2236#endif
7b1edb79
A
2237 return tellClients(kIOMessageSystemHasPoweredOn);
2238 }
1c79356b
A
2239}
2240
0b4e3aa0
A
2241//*********************************************************************************
2242// reportUserInput
2243//
2244//*********************************************************************************
2245
2246void IOPMrootDomain::reportUserInput ( void )
2247{
2d21ac55 2248#if !NO_KERNEL_HID
0b4e3aa0 2249 OSIterator * iter;
1c79356b 2250
55e303ae
A
2251 if(!wrangler)
2252 {
0b4e3aa0 2253 iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
55e303ae
A
2254 if(iter)
2255 {
0b4e3aa0
A
2256 wrangler = (IOService *) iter->getNextObject();
2257 iter->release();
2258 }
2259 }
2260
2261 if(wrangler)
2262 wrangler->activityTickle(0,0);
2d21ac55 2263#endif
0b4e3aa0
A
2264}
2265
2266//*********************************************************************************
2267// setQuickSpinDownTimeout
1c79356b 2268//
0b4e3aa0
A
2269//*********************************************************************************
2270
2271void IOPMrootDomain::setQuickSpinDownTimeout ( void )
2272{
0b4e3aa0
A
2273 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)1);
2274}
2275
2276//*********************************************************************************
2277// restoreUserSpinDownTimeout
2278//
2279//*********************************************************************************
2280
2281void IOPMrootDomain::restoreUserSpinDownTimeout ( void )
2282{
0b4e3aa0
A
2283 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)user_spindown);
2284}
2285
9bccf70c
A
2286//*********************************************************************************
2287// changePowerStateTo & changePowerStateToPriv
2288//
2289// Override of these methods for logging purposes.
2290//*********************************************************************************
2291
2292IOReturn IOPMrootDomain::changePowerStateTo ( unsigned long ordinal )
2293{
9bccf70c
A
2294 return super::changePowerStateTo(ordinal);
2295}
2296
2297IOReturn IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal )
2298{
0c530ab8
A
2299 IOReturn ret;
2300
2d21ac55
A
2301 DEBUG_LOG("ChangePowerStateToPriv: power state %ld\n", ordinal);
2302
2303 if ( (getPowerState() == DOZE_STATE) && (ordinal != ON_STATE) )
2304 {
2305 return kIOReturnSuccess;
2306 }
2307
2308 if( (userDisabledAllSleep || systemBooting || systemShutdown)
2309 && (ordinal == SLEEP_STATE) )
0c530ab8 2310 {
2d21ac55
A
2311 DEBUG_LOG(" sleep denied: disableAllSleep %d, booting %d, shutdown %d\n",
2312 userDisabledAllSleep, systemBooting, systemShutdown);
0c530ab8
A
2313 super::changePowerStateToPriv(ON_STATE);
2314 }
2315
2316 if( (SLEEP_STATE == ordinal) && sleepSupportedPEFunction )
2317 {
2318
2319 // Determine if the machine supports sleep, or must doze.
2320 ret = getPlatform()->callPlatformFunction(
2321 sleepSupportedPEFunction, false,
2322 NULL, NULL, NULL, NULL);
2323
2324 // If the machine only supports doze, the callPlatformFunction call
2d21ac55 2325 // boils down to IOPMrootDomain::setSleepSupported(kPCICantSleep),
0c530ab8
A
2326 // otherwise nothing.
2327 }
2328
9bccf70c
A
2329 return super::changePowerStateToPriv(ordinal);
2330}
2331
0b4e3aa0
A
2332
2333//*********************************************************************************
2334// sysPowerDownHandler
2335//
2336// Receives a notification when the RootDomain changes state.
2337//
2338// Allows us to take action on system sleep, power down, and restart after
2339// applications have received their power change notifications and replied,
2340// but before drivers have powered down. We perform a vfs sync on power down.
2341//*********************************************************************************
2342
2343IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon,
2344 UInt32 messageType, IOService * service,
2345 void * messageArgument, vm_size_t argSize )
2346{
55e303ae
A
2347 IOReturn ret;
2348 IOPowerStateChangeNotification *params = (IOPowerStateChangeNotification *) messageArgument;
2349 IOPMrootDomain *rootDomain = OSDynamicCast(IOPMrootDomain, service);
0b4e3aa0
A
2350
2351 if(!rootDomain)
2352 return kIOReturnUnsupported;
2353
2354 switch (messageType) {
2355 case kIOMessageSystemWillSleep:
2d21ac55 2356 DEBUG_LOG("SystemWillSleep\n");
0b4e3aa0
A
2357
2358 // Interested applications have been notified of an impending power
2359 // change and have acked (when applicable).
2360 // This is our chance to save whatever state we can before powering
2361 // down.
2362 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2363 // via callout
2364
2365 // We will ack within 20 seconds
2366 params->returnValue = 20 * 1000 * 1000;
2d21ac55 2367#if HIBERNATION
3a60a9f5
A
2368 if (gIOHibernateState)
2369 params->returnValue += gIOHibernateFreeTime * 1000; //add in time we could spend freeing pages
2d21ac55 2370#endif
0b4e3aa0
A
2371
2372 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
2373 {
2374 // Purposely delay the ack and hope that shutdown occurs quickly.
2375 // Another option is not to schedule the thread and wait for
2376 // ack timeout...
2377 AbsoluteTime deadline;
9bccf70c 2378 clock_interval_to_deadline( 30, kSecondScale, &deadline );
0b4e3aa0
A
2379 thread_call_enter1_delayed( rootDomain->diskSyncCalloutEntry,
2380 (thread_call_param_t)params->powerRef,
2381 deadline );
2382 }
2383 else
2384 thread_call_enter1(rootDomain->diskSyncCalloutEntry, (thread_call_param_t)params->powerRef);
2385 ret = kIOReturnSuccess;
2386 break;
fa4905b1
A
2387
2388 case kIOMessageSystemWillPowerOff:
2389 case kIOMessageSystemWillRestart:
d52fe63f 2390 ret = kIOReturnUnsupported;
fa4905b1
A
2391 break;
2392
0b4e3aa0
A
2393 default:
2394 ret = kIOReturnUnsupported;
2395 break;
2396 }
2397 return ret;
2398}
2399
2400//*********************************************************************************
2401// displayWranglerNotification
2402//
2403// Receives a notification when the IODisplayWrangler changes state.
2404//
2405// Allows us to take action on display dim/undim.
2406//
2d21ac55 2407// When the display sleeps we:
0b4e3aa0
A
2408// - Start the idle sleep timer
2409// - set the quick spin down timeout
2410//
2d21ac55 2411// On wake from display sleep:
0b4e3aa0
A
2412// - Cancel the idle sleep timer
2413// - restore the user's chosen spindown timer from the "quick" spin down value
2414//*********************************************************************************
1c79356b 2415
2d21ac55
A
2416IOReturn IOPMrootDomain::displayWranglerNotification(
2417 void * target, void * refCon,
2418 UInt32 messageType, IOService * service,
2419 void * messageArgument, vm_size_t argSize )
1c79356b 2420{
2d21ac55
A
2421#if !NO_KERNEL_HID
2422 IOPMrootDomain * rootDomain = OSDynamicCast(IOPMrootDomain, (IOService *)target);
2423 AbsoluteTime deadline;
2424 static int displayPowerState = 4;
0b4e3aa0 2425
2d21ac55 2426 if (!rootDomain)
0b4e3aa0
A
2427 return kIOReturnUnsupported;
2428
2429 switch (messageType) {
2430 case kIOMessageDeviceWillPowerOff:
2d21ac55
A
2431 DEBUG_LOG("DisplayWranglerWillPowerOff: new p-state %d\n",
2432 displayPowerState - 1);
2433
2434 // The display wrangler has dropped power because of idle display sleep
2435 // or force system sleep. We will receive 4 messages before the display
2436 // wrangler reaches its lowest state. Act only when going to state 2.
2437 //
2438 // 4->3 Display Dim
2439 // 3->2 Display Sleep
2440 // 2->1 Not visible to user
2441 // 1->0 Not visible to user
2442
2443 displayPowerState--;
2444 if ( 2 != displayPowerState )
2445 return kIOReturnUnsupported;
2446
2447 // We start a timer here if the System Sleep timer is greater than the
2448 // Display Sleep timer. We kick off this timer when the display sleeps.
2449 //
2450 // Note that, although Display Dim timings may change adaptively accordingly
2451 // to the user's activity patterns, Display Sleep _always_ occurs at the
2452 // specified interval since last user activity.
2453
2454 if ( rootDomain->extraSleepDelay )
2455 {
2456 clock_interval_to_deadline(rootDomain->extraSleepDelay*60, kSecondScale, &deadline);
0b4e3aa0
A
2457 thread_call_enter_delayed(rootDomain->extraSleepTimer, deadline);
2458 rootDomain->idleSleepPending = true;
2d21ac55
A
2459 DEBUG_LOG(" sleep timer set to expire in %ld min\n",
2460 rootDomain->extraSleepDelay);
0b4e3aa0 2461 } else {
2d21ac55
A
2462 // Accelerate disk spindown if system sleep and display sleep
2463 // sliders are set to the same value (e.g. both set to 5 min),
2464 // and display is about to go dark. Check that spin down timer
2465 // is non-zero (zero = never spin down) and system sleep is
2466 // not set to never sleep.
2467
2468 if ( (0 != rootDomain->user_spindown) && (0 != rootDomain->sleepSlider) )
2469 {
2470 DEBUG_LOG(" accelerate quick disk spindown, was %d min\n",
2471 rootDomain->user_spindown);
0b4e3aa0 2472 rootDomain->setQuickSpinDownTimeout();
2d21ac55 2473 }
0b4e3aa0
A
2474 }
2475
2d21ac55 2476 break;
0b4e3aa0
A
2477
2478 case kIOMessageDeviceHasPoweredOn:
2d21ac55
A
2479 DEBUG_LOG("DisplayWranglerHasPoweredOn: previous p-state %d\n",
2480 displayPowerState);
2481
2482 // The display wrangler has powered on either because of user activity
2483 // or wake from sleep/doze.
0b4e3aa0 2484
2d21ac55 2485 displayPowerState = 4;
0b4e3aa0 2486 rootDomain->adjustPowerState();
0b4e3aa0 2487
2d21ac55
A
2488 // cancel any pending idle sleep timers
2489 if (rootDomain->idleSleepPending)
55e303ae 2490 {
2d21ac55 2491 DEBUG_LOG(" extra-sleep timer stopped\n");
0b4e3aa0
A
2492 thread_call_cancel(rootDomain->extraSleepTimer);
2493 rootDomain->idleSleepPending = false;
2494 }
2495
2d21ac55
A
2496 // Change the spindown value back to the user's selection from our
2497 // accelerated setting.
2498 if (0 != rootDomain->user_spindown)
2499 {
2500 DEBUG_LOG(" restoring disk spindown to %d min\n",
2501 rootDomain->user_spindown);
0b4e3aa0 2502 rootDomain->restoreUserSpinDownTimeout();
2d21ac55 2503 }
0b4e3aa0
A
2504
2505 break;
2506
2507 default:
2508 break;
2509 }
2d21ac55 2510#endif
0b4e3aa0
A
2511 return kIOReturnUnsupported;
2512 }
2513
2514//*********************************************************************************
2515// displayWranglerPublished
2516//
2517// Receives a notification when the IODisplayWrangler is published.
2518// When it's published we install a power state change handler.
2519//
2520//*********************************************************************************
2521
0c530ab8
A
2522bool IOPMrootDomain::displayWranglerPublished(
2523 void * target,
2524 void * refCon,
2525 IOService * newService)
0b4e3aa0 2526{
2d21ac55 2527#if !NO_KERNEL_HID
0c530ab8
A
2528 IOPMrootDomain *rootDomain =
2529 OSDynamicCast(IOPMrootDomain, (IOService *)target);
0b4e3aa0
A
2530
2531 if(!rootDomain)
2532 return false;
2533
55e303ae
A
2534 rootDomain->wrangler = newService;
2535
2536 // we found the display wrangler, now install a handler
0c530ab8
A
2537 if( !rootDomain->wrangler->registerInterest( gIOGeneralInterest,
2538 &displayWranglerNotification, target, 0) )
2539 {
55e303ae
A
2540 return false;
2541 }
2d21ac55 2542#endif
55e303ae 2543 return true;
1c79356b
A
2544}
2545
483a1d10 2546//*********************************************************************************
0c530ab8 2547// batteryPublished
483a1d10 2548//
0c530ab8 2549// Notification on battery class IOPowerSource appearance
483a1d10 2550//
0c530ab8
A
2551//******************************************************************************
2552
2553bool IOPMrootDomain::batteryPublished(
2554 void * target,
2555 void * root_domain,
2556 IOService * resourceService )
2557{
2558 // rdar://2936060&4435589
91447636
A
2559 // All laptops have dimmable LCD displays
2560 // All laptops have batteries
2561 // So if this machine has a battery, publish the fact that the backlight
2562 // supports dimming.
2563 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
0c530ab8 2564
483a1d10
A
2565 return (true);
2566}
2567
0b4e3aa0
A
2568//*********************************************************************************
2569// adjustPowerState
2570//
2571// Some condition that affects our wake/sleep/doze decision has changed.
2572//
2573// If the sleep slider is in the off position, we cannot sleep or doze.
2574// If the enclosure is open, we cannot sleep or doze.
2575// If the system is still booting, we cannot sleep or doze.
2576//
2577// In those circumstances, we prevent sleep and doze by holding power on with
2578// changePowerStateToPriv(ON).
2579//
2580// If the above conditions do not exist, and also the sleep timer has expired, we
2581// allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
2582// changePowerStateToPriv(DOZE) depending on whether or not we already know the
2583// platform cannot sleep.
2584//
2585// In this case, sleep or doze will either occur immediately or at the next time
2586// that no children are holding the system out of idle sleep via the
2587// kIOPMPreventIdleSleep flag in their power state arrays.
2588//*********************************************************************************
2589
2590void IOPMrootDomain::adjustPowerState( void )
2591{
0c530ab8
A
2592 if ( (sleepSlider == 0)
2593 || !allowSleep
2594 || systemBooting
2d21ac55
A
2595 || systemShutdown
2596 || userDisabledAllSleep )
0c530ab8 2597 {
2d21ac55
A
2598 DEBUG_LOG("AdjustPowerState %ld -> ON: slider %ld, allowSleep %d, "
2599 "booting %d, shutdown %d, userDisabled %d\n",
2600 getPowerState(), sleepSlider, allowSleep, systemBooting,
2601 systemShutdown, userDisabledAllSleep);
2602
0b4e3aa0 2603 changePowerStateToPriv(ON_STATE);
55e303ae
A
2604 } else {
2605 if ( sleepASAP )
2606 {
2d21ac55
A
2607 DEBUG_LOG("AdjustPowerState SLEEP\n");
2608
2609 /* Convenient place to run any code at idle sleep time
2610 * IOPMrootDomain initiates an idle sleep here
2611 *
2612 * Set last sleep cause accordingly.
2613 */
2614 setProperty(kRootDomainSleepReasonKey, kIOPMIdleSleepKey);
2615
0b4e3aa0 2616 sleepASAP = false;
2d21ac55
A
2617 if ( !sleepIsSupported )
2618 {
0c530ab8 2619 setSleepSupported( kPCICantSleep );
2d21ac55
A
2620 kprintf("Sleep prevented by kIOPMPreventSystemSleep flag\n");
2621 }
0c530ab8
A
2622 changePowerStateToPriv(SLEEP_STATE);
2623 }
2624 }
2625}
2626
2d21ac55
A
2627//*********************************************************************************
2628// PMHaltWorker Class
2629//
2630//*********************************************************************************
2631
2632static unsigned int gPMHaltBusyCount;
2633static unsigned int gPMHaltIdleCount;
2634static int gPMHaltDepth;
2635static unsigned long gPMHaltEvent;
2636static IOLock * gPMHaltLock = 0;
2637static OSArray * gPMHaltArray = 0;
2638static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
2639
2640PMHaltWorker * PMHaltWorker::worker( void )
2641{
2642 PMHaltWorker * me;
2643 IOThread thread;
2644
2645 do {
2646 me = OSTypeAlloc( PMHaltWorker );
2647 if (!me || !me->init())
2648 break;
2649
2650 me->lock = IOLockAlloc();
2651 if (!me->lock)
2652 break;
2653
2654 DEBUG_LOG("PMHaltWorker %p\n", me);
2655 me->retain(); // thread holds extra retain
2656 thread = IOCreateThread( &PMHaltWorker::main, me );
2657 if (!thread)
2658 {
2659 me->release();
2660 break;
2661 }
2662 return me;
2663
2664 } while (false);
2665
2666 if (me) me->release();
2667 return 0;
2668}
2669
2670void PMHaltWorker::free( void )
2671{
2672 DEBUG_LOG("PMHaltWorker free %p\n", this);
2673 if (lock)
2674 {
2675 IOLockFree(lock);
2676 lock = 0;
2677 }
2678 return OSObject::free();
2679}
2680
2681void PMHaltWorker::main( void * arg )
2682{
2683 PMHaltWorker * me = (PMHaltWorker *) arg;
2684
2685 IOLockLock( gPMHaltLock );
2686 gPMHaltBusyCount++;
2687 me->depth = gPMHaltDepth;
2688 IOLockUnlock( gPMHaltLock );
2689
2690 while (me->depth >= 0)
2691 {
2692 PMHaltWorker::work( me );
2693
2694 IOLockLock( gPMHaltLock );
2695 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
2696 {
2697 // This is the last thread to finish work on this level,
2698 // inform everyone to start working on next lower level.
2699 gPMHaltDepth--;
2700 me->depth = gPMHaltDepth;
2701 gPMHaltIdleCount = 0;
2702 thread_wakeup((event_t) &gPMHaltIdleCount);
2703 }
2704 else
2705 {
2706 // One or more threads are still working on this level,
2707 // this thread must wait.
2708 me->depth = gPMHaltDepth - 1;
2709 do {
2710 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
2711 } while (me->depth != gPMHaltDepth);
2712 }
2713 IOLockUnlock( gPMHaltLock );
2714 }
2715
2716 // No more work to do, terminate thread
2717 DEBUG_LOG("All done for worker: %p (visits = %u)\n", me, me->visits);
2718 thread_wakeup( &gPMHaltDepth );
2719 me->release();
2720}
2721
2722void PMHaltWorker::work( PMHaltWorker * me )
2723{
2724 IOService * service;
2725 OSSet * inner;
2726 AbsoluteTime startTime;
2727 UInt32 deltaTime;
2728 bool timeout;
2729
2730 while (true)
2731 {
2732 service = 0;
2733 timeout = false;
2734
2735 // Claim an unit of work from the shared pool
2736 IOLockLock( gPMHaltLock );
2737 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
2738 if (inner)
2739 {
2740 service = (IOService *)inner->getAnyObject();
2741 if (service)
2742 {
2743 service->retain();
2744 inner->removeObject(service);
2745 }
2746 }
2747 IOLockUnlock( gPMHaltLock );
2748 if (!service)
2749 break; // no more work at this depth
2750
2751 clock_get_uptime(&startTime);
2752
2753 if (!service->isInactive() &&
2754 service->setProperty(gPMHaltClientAcknowledgeKey, me))
2755 {
2756 IOLockLock(me->lock);
2757 me->startTime = startTime;
2758 me->service = service;
2759 me->timeout = false;
2760 IOLockUnlock(me->lock);
2761
2762 service->systemWillShutdown( gPMHaltEvent );
2763
2764 // Wait for driver acknowledgement
2765 IOLockLock(me->lock);
2766 while (service->getProperty(gPMHaltClientAcknowledgeKey))
2767 {
2768 IOLockSleep(me->lock, me, THREAD_UNINT);
2769 }
2770 me->service = 0;
2771 timeout = me->timeout;
2772 IOLockUnlock(me->lock);
2773 }
2774
2775 deltaTime = computeDeltaTimeMS(&startTime);
2776 if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
2777 (gIOKitDebug & kIOLogDebugPower))
2778 {
2779 HaltRestartLog("%s driver %s (%p) took %lu ms\n",
2780 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
2781 "PowerOff" : "Restart",
2782 service->getName(), service,
2783 deltaTime );
2784 }
2785
2786 service->release();
2787 me->visits++;
2788 }
2789}
2790
2791void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
2792{
2793 UInt64 nano;
2794 AbsoluteTime startTime;
2795 AbsoluteTime endTime;
2796
2797 endTime = *now;
2798
2799 IOLockLock(me->lock);
2800 if (me->service && !me->timeout)
2801 {
2802 startTime = me->startTime;
2803 nano = 0;
2804 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
2805 {
2806 SUB_ABSOLUTETIME(&endTime, &startTime);
2807 absolutetime_to_nanoseconds(endTime, &nano);
2808 }
2809 if (nano > 3000000000ULL)
2810 {
2811 me->timeout = true;
2812 HaltRestartLog("%s still waiting on %s\n",
2813 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
2814 "PowerOff" : "Restart",
2815 me->service->getName());
2816 }
2817 }
2818 IOLockUnlock(me->lock);
2819}
2820
2821//*********************************************************************************
2822// acknowledgeSystemWillShutdown
2823//
2824// Acknowledgement from drivers that they have prepared for shutdown/restart.
2825//*********************************************************************************
2826
2827void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
2828{
2829 PMHaltWorker * worker;
2830 OSObject * prop;
2831
2832 if (!from)
2833 return;
2834
2835 //DEBUG_LOG("%s acknowledged\n", from->getName());
2836 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
2837 if (prop)
2838 {
2839 worker = (PMHaltWorker *) prop;
2840 IOLockLock(worker->lock);
2841 from->removeProperty( gPMHaltClientAcknowledgeKey );
2842 thread_wakeup((event_t) worker);
2843 IOLockUnlock(worker->lock);
2844 worker->release();
2845 }
2846 else
2847 {
2848 DEBUG_LOG("%s acknowledged without worker property\n",
2849 from->getName());
2850 }
2851}
2852
2853//*********************************************************************************
2854// notifySystemShutdown
2855//
2856// Notify all objects in PM tree that system will shutdown or restart
2857//*********************************************************************************
2858
2859static void
2860notifySystemShutdown( IOService * root, unsigned long event )
2861{
2862#define PLACEHOLDER ((OSSet *)gPMHaltArray)
2863 IORegistryIterator * iter;
2864 IORegistryEntry * entry;
2865 IOService * node;
2866 OSSet * inner;
2867 PMHaltWorker * workers[kPMHaltMaxWorkers];
2868 AbsoluteTime deadline;
2869 unsigned int totalNodes = 0;
2870 unsigned int depth;
2871 unsigned int rootDepth;
2872 unsigned int numWorkers;
2873 unsigned int count;
2874 int waitResult;
2875 void * baseFunc;
2876 bool ok;
2877
2878 DEBUG_LOG("%s event = %lx\n", __FUNCTION__, event);
2879
2880 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
2881
2882 // Iterate the entire PM tree starting from root
2883
2884 rootDepth = root->getDepth( gIOPowerPlane );
2885 if (!rootDepth) goto done;
2886
2887 // debug - for repeated test runs
2888 while (PMHaltWorker::metaClass->getInstanceCount())
2889 IOSleep(1);
2890
2891 if (!gPMHaltArray)
2892 {
2893 gPMHaltArray = OSArray::withCapacity(40);
2894 if (!gPMHaltArray) goto done;
2895 }
2896 else // debug
2897 gPMHaltArray->flushCollection();
2898
2899 if (!gPMHaltLock)
2900 {
2901 gPMHaltLock = IOLockAlloc();
2902 if (!gPMHaltLock) goto done;
2903 }
2904
2905 if (!gPMHaltClientAcknowledgeKey)
2906 {
2907 gPMHaltClientAcknowledgeKey =
2908 OSSymbol::withCStringNoCopy("PMShutdown");
2909 if (!gPMHaltClientAcknowledgeKey) goto done;
2910 }
2911
2912 gPMHaltEvent = event;
2913
2914 // Depth-first walk of PM plane
2915
2916 iter = IORegistryIterator::iterateOver(
2917 root, gIOPowerPlane, kIORegistryIterateRecursively);
2918
2919 if (iter)
2920 {
2921 while ((entry = iter->getNextObject()))
2922 {
2923 node = OSDynamicCast(IOService, entry);
2924 if (!node)
2925 continue;
2926
2927 if (baseFunc ==
2928 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
2929 continue;
2930
2931 depth = node->getDepth( gIOPowerPlane );
2932 if (depth <= rootDepth)
2933 continue;
2934
2935 ok = false;
2936
2937 // adjust to zero based depth
2938 depth -= (rootDepth + 1);
2939
2940 // gPMHaltArray is an array of containers, each container
2941 // refers to nodes with the same depth.
2942
2943 count = gPMHaltArray->getCount();
2944 while (depth >= count)
2945 {
2946 // expand array and insert placeholders
2947 gPMHaltArray->setObject(PLACEHOLDER);
2948 count++;
2949 }
2950 count = gPMHaltArray->getCount();
2951 if (depth < count)
2952 {
2953 inner = (OSSet *)gPMHaltArray->getObject(depth);
2954 if (inner == PLACEHOLDER)
2955 {
2956 inner = OSSet::withCapacity(40);
2957 if (inner)
2958 {
2959 gPMHaltArray->replaceObject(depth, inner);
2960 inner->release();
2961 }
2962 }
2963
2964 // PM nodes that appear more than once in the tree will have
2965 // the same depth, OSSet will refuse to add the node twice.
2966 if (inner)
2967 ok = inner->setObject(node);
2968 }
2969 if (!ok)
2970 DEBUG_LOG("Skipped PM node %s\n", node->getName());
2971 }
2972 iter->release();
2973 }
2974
2975 // debug only
2976 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
2977 {
2978 count = 0;
2979 if (inner != PLACEHOLDER)
2980 count = inner->getCount();
2981 DEBUG_LOG("Nodes at depth %u = %u\n", i, count);
2982 }
2983
2984 // strip placeholders (not all depths are populated)
2985 numWorkers = 0;
2986 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
2987 {
2988 if (inner == PLACEHOLDER)
2989 {
2990 gPMHaltArray->removeObject(i);
2991 continue;
2992 }
2993 count = inner->getCount();
2994 if (count > numWorkers)
2995 numWorkers = count;
2996 totalNodes += count;
2997 i++;
2998 }
2999
3000 if (gPMHaltArray->getCount() == 0 || !numWorkers)
3001 goto done;
3002
3003 gPMHaltBusyCount = 0;
3004 gPMHaltIdleCount = 0;
3005 gPMHaltDepth = gPMHaltArray->getCount() - 1;
3006
3007 // Create multiple workers (and threads)
3008
3009 if (numWorkers > kPMHaltMaxWorkers)
3010 numWorkers = kPMHaltMaxWorkers;
3011
3012 DEBUG_LOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
3013 totalNodes, gPMHaltArray->getCount(), numWorkers);
3014
3015 for (unsigned int i = 0; i < numWorkers; i++)
3016 workers[i] = PMHaltWorker::worker();
3017
3018 // Wait for workers to exhaust all available work
3019
3020 IOLockLock(gPMHaltLock);
3021 while (gPMHaltDepth >= 0)
3022 {
3023 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
3024
3025 waitResult = IOLockSleepDeadline(
3026 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
3027 if (THREAD_TIMED_OUT == waitResult)
3028 {
3029 AbsoluteTime now;
3030 clock_get_uptime(&now);
3031
3032 IOLockUnlock(gPMHaltLock);
3033 for (unsigned int i = 0 ; i < numWorkers; i++)
3034 {
3035 if (workers[i])
3036 PMHaltWorker::checkTimeout(workers[i], &now);
3037 }
3038 IOLockLock(gPMHaltLock);
3039 }
3040 }
3041 IOLockUnlock(gPMHaltLock);
3042
3043 // Release all workers
3044
3045 for (unsigned int i = 0; i < numWorkers; i++)
3046 {
3047 if (workers[i])
3048 workers[i]->release();
3049 // worker also retained by it's own thread
3050 }
3051
3052done:
3053 DEBUG_LOG("%s done\n", __FUNCTION__);
3054 return;
3055}
3056
3057#if DEBUG_TEST
3058// debug - exercise notifySystemShutdown()
3059bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
3060{
3061 IOPMrootDomain * root = (IOPMrootDomain *) this;
3062 notifySystemShutdown( root, kIOMessageSystemWillPowerOff );
3063 return( super::serializeProperties(s) );
3064}
3065#endif
3066
0c530ab8
A
3067/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3068
3069
3070
3071#undef super
3072#define super OSObject
3073OSDefineMetaClassAndStructors(PMSettingObject, OSObject)
3074
3075void PMSettingObject::setPMSetting(const OSSymbol *type, OSObject *obj)
3076{
3077 (*func)(target, type, obj, refcon);
3078}
3079
3080/*
3081 * Static constructor/initializer for PMSettingObject
3082 */
3083PMSettingObject *PMSettingObject::pmSettingObject(
3084 IOPMrootDomain *parent_arg,
3085 IOPMSettingControllerCallback handler_arg,
3086 OSObject *target_arg,
3087 uintptr_t refcon_arg,
3088 uint32_t supportedPowerSources,
3089 const OSSymbol * settings[])
3090{
3091 uint32_t objCount = 0;
3092 PMSettingObject *pmso;
3093
3094 if( !parent_arg || !handler_arg || !settings ) return NULL;
3095
3096 // count OSSymbol entries in NULL terminated settings array
3097 while( settings[objCount] ) {
3098 objCount++;
3099 }
3100 if(0 == objCount) return NULL;
3101
3102 pmso = new PMSettingObject;
3103 if(!pmso || !pmso->init()) return NULL;
3104
3105 pmso->parent = parent_arg;
3106 pmso->func = handler_arg;
3107 pmso->target = target_arg;
3108 pmso->refcon = refcon_arg;
3109 pmso->releaseAtCount = objCount + 1; // release when it has count+1 retains
3110
3111 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount);
3112 if(pmso->publishedFeatureID) {
3113 for(unsigned int i=0; i<objCount; i++) {
3114 // Since there is now at least one listener to this setting, publish
3115 // PM root domain support for it.
3116 parent_arg->publishFeature( settings[i]->getCStringNoCopy(),
3117 supportedPowerSources, &pmso->publishedFeatureID[i] );
3118 }
3119 }
3120
3121 return pmso;
3122}
3123
3124void PMSettingObject::free(void)
3125{
3126 OSCollectionIterator *settings_iter;
3127 OSSymbol *sym;
3128 OSArray *arr;
3129 int arr_idx;
3130 int i;
3131 int objCount = releaseAtCount - 1;
3132
3133 if(publishedFeatureID) {
3134 for(i=0; i<objCount; i++) {
3135 if(0 != publishedFeatureID[i]) {
3136 parent->removePublishedFeature( publishedFeatureID[i] );
0b4e3aa0
A
3137 }
3138 }
0c530ab8
A
3139
3140 IOFree(publishedFeatureID, sizeof(uint32_t) * objCount);
0b4e3aa0 3141 }
0c530ab8
A
3142
3143 IORecursiveLockLock(parent->settingsCtrlLock);
3144
3145 // Search each PM settings array in the kernel.
3146 settings_iter = OSCollectionIterator::withCollection(parent->settingsCallbacks);
3147 if(settings_iter)
3148 {
3149 while(( sym = OSDynamicCast(OSSymbol, settings_iter->getNextObject()) ))
3150 {
3151 arr = (OSArray *)parent->settingsCallbacks->getObject(sym);
3152 arr_idx = arr->getNextIndexOfObject(this, 0);
3153 if(-1 != arr_idx) {
3154 // 'this' was found in the array; remove it
3155 arr->removeObject(arr_idx);
3156 }
3157 }
3158
3159 settings_iter->release();
3160 }
3161
3162 IORecursiveLockUnlock(parent->settingsCtrlLock);
3163
3164 super::free();
3165}
3166
3167void PMSettingObject::taggedRelease(const void *tag, const int when) const
3168{
3169 // We have n+1 retains - 1 per array that this PMSettingObject is a member
3170 // of, and 1 retain to ourself. When we get a release with n+1 retains
3171 // remaining, we go ahead and free ourselves, cleaning up array pointers
3172 // in free();
3173
3174 super::taggedRelease(tag, releaseAtCount);
0b4e3aa0 3175}
1c79356b
A
3176
3177
0c530ab8 3178
1c79356b
A
3179/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3180
3181#undef super
3182#define super IOService
3183
3184OSDefineMetaClassAndStructors(IORootParent, IOService)
3185
0b4e3aa0
A
3186// This array exactly parallels the state array for the root domain.
3187// Power state changes initiated by a device can be vetoed by a client of the device, and
3188// power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
3189// so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
3190// its parent to make the change. That is the reason for this complexity.
1c79356b 3191
0b4e3aa0 3192static IOPMPowerState patriarchPowerStates[number_of_power_states] = {
1c79356b 3193 {1,0,0,0,0,0,0,0,0,0,0,0}, // off
0b4e3aa0 3194 {1,0,RESTART_POWER,0,0,0,0,0,0,0,0,0}, // reset
1c79356b 3195 {1,0,SLEEP_POWER,0,0,0,0,0,0,0,0,0}, // sleep
0b4e3aa0 3196 {1,0,DOZE_POWER,0,0,0,0,0,0,0,0,0}, // doze
1c79356b
A
3197 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0} // running
3198};
3199
1c79356b
A
3200bool IORootParent::start ( IOService * nub )
3201{
0b4e3aa0 3202 mostRecentChange = ON_STATE;
1c79356b
A
3203 super::start(nub);
3204 PMinit();
2d21ac55 3205 youAreRoot();
0b4e3aa0 3206 registerPowerDriver(this,patriarchPowerStates,number_of_power_states);
2d21ac55
A
3207 wakeSystem();
3208 powerOverrideOnPriv();
1c79356b
A
3209 return true;
3210}
3211
3212
3213void IORootParent::shutDownSystem ( void )
3214{
0b4e3aa0
A
3215 mostRecentChange = OFF_STATE;
3216 changePowerStateToPriv(OFF_STATE);
3217}
3218
3219
3220void IORootParent::restartSystem ( void )
3221{
3222 mostRecentChange = RESTART_STATE;
3223 changePowerStateToPriv(RESTART_STATE);
1c79356b
A
3224}
3225
3226
3227void IORootParent::sleepSystem ( void )
3228{
0b4e3aa0
A
3229 mostRecentChange = SLEEP_STATE;
3230 changePowerStateToPriv(SLEEP_STATE);
3231}
3232
3233
3234void IORootParent::dozeSystem ( void )
3235{
3236 mostRecentChange = DOZE_STATE;
3237 changePowerStateToPriv(DOZE_STATE);
3238}
3239
3240// Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
3241// This brings the parent to doze, which allows the root to step up from sleep to doze.
3242
3243// In idle sleep, do nothing because the parent is still on and the root can freely change state.
3244
3245void IORootParent::sleepToDoze ( void )
3246{
3247 if ( mostRecentChange == SLEEP_STATE ) {
3248 changePowerStateToPriv(DOZE_STATE);
3249 }
1c79356b
A
3250}
3251
3252
3253void IORootParent::wakeSystem ( void )
3254{
0b4e3aa0
A
3255 mostRecentChange = ON_STATE;
3256 changePowerStateToPriv(ON_STATE);
1c79356b
A
3257}
3258
0c530ab8
A
3259IOReturn IORootParent::changePowerStateToPriv ( unsigned long ordinal )
3260{
3261 IOReturn ret;
3262
3263 if( (SLEEP_STATE == ordinal) && sleepSupportedPEFunction )
3264 {
3265
3266 // Determine if the machine supports sleep, or must doze.
3267 ret = getPlatform()->callPlatformFunction(
3268 sleepSupportedPEFunction, false,
3269 NULL, NULL, NULL, NULL);
3270
3271 // If the machine only supports doze, the callPlatformFunction call
3272 // boils down toIOPMrootDomain::setSleepSupported(kPCICantSleep),
3273 // otherwise nothing.
3274 }
3275
3276 return super::changePowerStateToPriv(ordinal);
3277}
3278