]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOPMrootDomain.cpp
xnu-792.13.8.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
CommitLineData
91447636 1/*
3a60a9f5 2 * Copyright (c) 1998-2005 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
1c79356b 5 *
8ad349bb
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
1c79356b
A
29 */
30#include <IOKit/IOWorkLoop.h>
9bccf70c 31#include <IOKit/IOCommandGate.h>
1c79356b
A
32#include <IOKit/IOTimerEventSource.h>
33#include <IOKit/IOPlatformExpert.h>
9bccf70c
A
34#include <IOKit/IOKitDebug.h>
35#include <IOKit/IOTimeStamp.h>
1c79356b 36#include <IOKit/pwr_mgt/RootDomain.h>
d52fe63f 37#include <IOKit/pwr_mgt/IOPMPrivate.h>
91447636 38#include <IOKit/IODeviceTreeSupport.h>
1c79356b 39#include <IOKit/IOMessage.h>
5d5c5d0d 40#include <IOKit/IOReturn.h>
1c79356b 41#include "RootDomainUserClient.h"
0b4e3aa0 42#include "IOKit/pwr_mgt/IOPowerConnection.h"
55e303ae 43#include "IOPMPowerStateQueue.h"
91447636 44#include <IOKit/IOCatalogue.h>
3a60a9f5 45#include <IOKit/IOHibernatePrivate.h>
5d5c5d0d 46#include "IOPMWorkArbiter.h"
91447636 47
3a60a9f5
A
48#ifdef __ppc__
49#include <ppc/pms.h>
50#endif
1c79356b 51
5d5c5d0d
A
52extern "C" {
53IOReturn OSMetaClassSystemSleepOrWake( UInt32 );
54}
1c79356b
A
55
56extern const IORegistryPlane * gIOPowerPlane;
57
9bccf70c 58IOReturn broadcast_aggressiveness ( OSObject *, void *, void *, void *, void * );
0b4e3aa0 59static void sleepTimerExpired(thread_call_param_t);
d52fe63f 60static void wakeupClamshellTimerExpired ( thread_call_param_t us);
1c79356b 61
5d5c5d0d
A
62// "IOPMSetSleepSupported" callPlatformFunction name
63static const OSSymbol *sleepSupportedPEFunction = NULL;
64
65#define kIOSleepSupportedKey "IOSleepSupported"
66
67#define kRD_AllPowerSources (kIOPMSupportedOnAC \
68 | kIOPMSupportedOnBatt \
69 | kIOPMSupportedOnUPS)
1c79356b 70
0b4e3aa0 71#define number_of_power_states 5
1c79356b 72#define OFF_STATE 0
0b4e3aa0
A
73#define RESTART_STATE 1
74#define SLEEP_STATE 2
75#define DOZE_STATE 3
76#define ON_STATE 4
1c79356b 77
0b4e3aa0
A
78#define ON_POWER kIOPMPowerOn
79#define RESTART_POWER kIOPMRestart
80#define SLEEP_POWER kIOPMAuxPowerOn
81#define DOZE_POWER kIOPMDoze
1c79356b 82
5d5c5d0d
A
83#define kLocalEvalClamshellCommand (1 << 15)
84
1c79356b 85static IOPMPowerState ourPowerStates[number_of_power_states] = {
5d5c5d0d
A
86 // state 0, off
87 {1,0, 0, 0,0,0,0,0,0,0,0,0},
88 // state 1, restart
89 {1,kIOPMRestartCapability, kIOPMRestart, RESTART_POWER,0,0,0,0,0,0,0,0},
90 // state 2, sleep
91 {1,kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER,0,0,0,0,0,0,0,0},
92 // state 3, doze
93 {1,kIOPMDoze, kIOPMDoze, DOZE_POWER,0,0,0,0,0,0,0,0},
94 // state 4, on
95 {1,kIOPMPowerOn, kIOPMPowerOn, ON_POWER,0,0,0,0,0,0,0,0},
1c79356b
A
96};
97
8ad349bb
A
98static IOPMrootDomain * gRootDomain;
99static UInt32 gSleepOrShutdownPending = 0;
c0fea474
A
100
101
5d5c5d0d
A
102class PMSettingObject : public OSObject
103{
104 OSDeclareDefaultStructors(PMSettingObject)
105private:
106 IOPMrootDomain *parent;
107 IOPMSettingControllerCallback func;
108 OSObject *target;
109 uintptr_t refcon;
110 uint32_t *publishedFeatureID;
111 int releaseAtCount;
112public:
113 static PMSettingObject *pmSettingObject(
114 IOPMrootDomain *parent_arg,
115 IOPMSettingControllerCallback handler_arg,
116 OSObject *target_arg,
117 uintptr_t refcon_arg,
118 uint32_t supportedPowerSources,
119 const OSSymbol *settings[]);
120
121 void setPMSetting(const OSSymbol *type, OSObject *obj);
122
123 void taggedRelease(const void *tag, const int when) const;
124 void free(void);
125};
126
127
128
1c79356b
A
129#define super IOService
130OSDefineMetaClassAndStructors(IOPMrootDomain,IOService)
131
132extern "C"
133{
91447636 134 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
1c79356b
A
135 {
136 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
137 }
138
91447636 139 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
0b4e3aa0
A
140 {
141 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
142 }
143
1c79356b
A
144 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
145 {
146 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
147 }
148
0b4e3aa0
A
149 IOReturn vetoSleepWakeNotification(void * PMrefcon)
150 {
151 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
152 }
153
154 IOReturn rootDomainRestart ( void )
155 {
156 return gRootDomain->restartSystem();
157 }
158
159 IOReturn rootDomainShutdown ( void )
160 {
161 return gRootDomain->shutdownSystem();
162 }
163
164 void IOSystemShutdownNotification ( void )
165 {
91447636 166 IOCatalogue::disableExternalLinker();
0b4e3aa0
A
167 for ( int i = 0; i < 100; i++ )
168 {
169 if ( OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) ) break;
170 IOSleep( 100 );
171 }
172 }
173
174 int sync_internal(void);
1c79356b
A
175}
176
0b4e3aa0
A
177/*
178A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain
179children it has, but within the constraint of the power state provided by its parent. The driver expresses its desire by
180calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children
181express their desires by calling requestPowerDomainState().
182
183The Root Power Domain owns the policy for idle and demand sleep and doze for the system. It is a power-managed IOService just
184like the others in the system. It implements several power states which correspond to what we see as Sleep, Doze, etc.
185
186The sleep/doze policy is as follows:
187Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards.
188Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero.
189The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep.
190
191These three conditions are enforced using the "driver clamp" by calling changePowerStateTo(). For example, if the case is
192opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or
193the state of the other clamp.
194
195Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item.
196In this case the root's parent actually initiates the power state change so that the root has no choice and does not give
197applications the opportunity to veto the change.
198
199Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep. When this is true, the root's
200children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE)
201to hold itself on until the sleep timer expires. This timer is set for the difference between the sleep timeout slider and
202the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel. For example, if
203the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes,
204when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root
205sets its timer for 25 minutes (30 - 5). When the timer expires, it releases its clamp and now nothing is holding it awake,
206so it falls asleep.
207
208Demand sleep is prevented when the system is booting. When preferences are transmitted by the loginwindow at the end of
209boot, a flag is cleared, and this allows subsequent Demand Sleep.
210
211The 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
212a clamp, but sets a flag which is noticed before actually sleeping the kernel. If the flag is set, the root steps up
213one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and
214ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler
215to be tickled)).
216*/
5d5c5d0d 217
0b4e3aa0
A
218// **********************************************************************************
219
220IOPMrootDomain * IOPMrootDomain::construct( void )
221{
55e303ae 222 IOPMrootDomain *root;
0b4e3aa0
A
223
224 root = new IOPMrootDomain;
225 if( root)
226 root->init();
227
228 return( root );
229}
230
231// **********************************************************************************
232
233static void disk_sync_callout(thread_call_param_t p0, thread_call_param_t p1)
234{
55e303ae
A
235 IOService *rootDomain = (IOService *) p0;
236 unsigned long pmRef = (unsigned long) p1;
0b4e3aa0 237
3a60a9f5 238 IOHibernateSystemSleep();
0b4e3aa0
A
239 sync_internal();
240 rootDomain->allowPowerChange(pmRef);
241}
1c79356b 242
5d5c5d0d
A
243// **********************************************************************************
244IOPMWorkArbiter *IOPMrootDomain::getPMArbiter(void)
245{
246 return pmArbiter;
247}
248
249
1c79356b
A
250// **********************************************************************************
251// start
252//
253// We don't do much here. The real initialization occurs when the platform
254// expert informs us we are the root.
255// **********************************************************************************
0b4e3aa0 256
5d5c5d0d 257#define kRootDomainSettingsCount 12
0b4e3aa0 258
1c79356b
A
259bool IOPMrootDomain::start ( IOService * nub )
260{
5d5c5d0d
A
261 OSIterator *psIterator;
262 OSDictionary *tmpDict;
263 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
264 {
265 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
266 OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey),
267 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
268 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey),
269 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
270 OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey),
271 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
272 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
273 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
274 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
275 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
276 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey)
277 };
278
55e303ae
A
279
280 pmPowerStateQueue = 0;
d52fe63f 281
e5568f75
A
282 _reserved = (ExpansionData *)IOMalloc(sizeof(ExpansionData));
283 if(!_reserved) return false;
284
1c79356b
A
285 super::start(nub);
286
287 gRootDomain = this;
288
289 PMinit();
5d5c5d0d
A
290
291 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
292 canSleep = true;
293 setProperty(kIOSleepSupportedKey,true);
91447636 294
1c79356b 295 allowSleep = true;
0b4e3aa0 296 sleepIsSupported = true;
1c79356b 297 systemBooting = true;
0b4e3aa0
A
298 sleepSlider = 0;
299 idleSleepPending = false;
0b4e3aa0
A
300 wrangler = NULL;
301 sleepASAP = false;
5d5c5d0d
A
302 clamshellIsClosed = false;
303 clamshellExists = false;
304 ignoringClamshell = true;
d52fe63f 305 ignoringClamshellDuringWakeup = false;
5d5c5d0d 306 acAdaptorConnect = true;
0b4e3aa0 307
d52fe63f
A
308 tmpDict = OSDictionary::withCapacity(1);
309 setProperty(kRootDomainSupportedFeatures, tmpDict);
310 tmpDict->release();
91447636 311
5d5c5d0d
A
312 settingsCallbacks = OSDictionary::withCapacity(1);
313
314 // Create a list of the valid PM settings that we'll relay to
315 // interested clients in setProperties() => setPMSetting()
316 allowedPMSettings = OSArray::withObjects(
317 (const OSObject **)settingsArr,
318 kRootDomainSettingsCount,
319 0);
320
321 fPMSettingsDict = OSDictionary::withCapacity(5);
322
55e303ae
A
323 pm_vars->PMworkloop = IOWorkLoop::workLoop();
324 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(this);
325 pm_vars->PMworkloop->addEventSource(pmPowerStateQueue);
326
5d5c5d0d
A
327 /* Initialize PM arbiter */
328 pmArbiter = IOPMWorkArbiter::pmWorkArbiter(this);
329 arbiterWorkLoop = IOWorkLoop::workLoop();
330 arbiterWorkLoop->addEventSource(pmArbiter);
331
91447636 332 featuresDictLock = IOLockAlloc();
5d5c5d0d 333 settingsCtrlLock = IORecursiveLockAlloc();
91447636 334
5d5c5d0d
A
335 extraSleepTimer = thread_call_allocate(
336 (thread_call_func_t)sleepTimerExpired,
337 (thread_call_param_t) this);
338 clamshellWakeupIgnore = thread_call_allocate(
339 (thread_call_func_t)wakeupClamshellTimerExpired,
340 (thread_call_param_t) this);
341 diskSyncCalloutEntry = thread_call_allocate(
342 &disk_sync_callout,
343 (thread_call_param_t) this);
1c79356b 344
55e303ae
A
345 // create our parent
346 patriarch = new IORootParent;
1c79356b
A
347 patriarch->init();
348 patriarch->attach(this);
349 patriarch->start(this);
350 patriarch->youAreRoot();
351 patriarch->wakeSystem();
352 patriarch->addPowerChild(this);
e5568f75 353
1c79356b
A
354 registerPowerDriver(this,ourPowerStates,number_of_power_states);
355
0b4e3aa0 356 setPMRootDomain(this);
55e303ae
A
357 // set a clamp until we sleep
358 changePowerStateToPriv(ON_STATE);
0b4e3aa0 359
55e303ae
A
360 // install power change handler
361 registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
0b4e3aa0
A
362
363 // Register for a notification when IODisplayWrangler is published
5d5c5d0d
A
364 _displayWranglerNotifier = addNotification(
365 gIOPublishNotification, serviceMatching("IODisplayWrangler"),
366 &displayWranglerPublished, this, 0);
483a1d10 367
5d5c5d0d
A
368 // Battery location published - ApplePMU support only
369 _batteryPublishNotifier = addNotification(
370 gIOPublishNotification, serviceMatching("IOPMPowerSource"),
371 &batteryPublished, this, this);
372
1c79356b 373
55e303ae 374 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
91447636 375 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
55e303ae
A
376 ucClassName->release();
377
5d5c5d0d
A
378 // IOBacklightDisplay can take a long time to load at boot, or it may
379 // not load at all if you're booting with clamshell closed. We publish
380 // 'DisplayDims' here redundantly to get it published early and at all.
381 psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") );
382 if( psIterator && psIterator->getNextObject() )
91447636 383 {
5d5c5d0d
A
384 // There's at least one battery on the system, so we publish
385 // 'DisplayDims' support for the LCD.
91447636 386 publishFeature("DisplayDims");
5d5c5d0d
A
387 }
388 if(psIterator) {
389 psIterator->release();
91447636
A
390 }
391
3a60a9f5 392 IOHibernateSystemInit(this);
91447636 393
1c79356b
A
394 registerService(); // let clients find us
395
396 return true;
397}
398
9bccf70c
A
399// **********************************************************************************
400// setProperties
401//
402// Receive a setProperty call
403// The "System Boot" property means the system is completely booted.
404// **********************************************************************************
405IOReturn IOPMrootDomain::setProperties ( OSObject *props_obj)
406{
5d5c5d0d
A
407 IOReturn return_value = kIOReturnSuccess;
408 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
409 OSBoolean *b;
410 OSNumber *n;
411 OSString *str;
412 OSSymbol *type;
413 OSObject *obj;
414 unsigned int i;
415
416 const OSSymbol *boot_complete_string =
417 OSSymbol::withCString("System Boot Complete");
418 const OSSymbol *stall_halt_string =
419 OSSymbol::withCString("StallSystemAtHalt");
420 const OSSymbol *hibernatemode_string =
421 OSSymbol::withCString(kIOHibernateModeKey);
422 const OSSymbol *hibernatefile_string =
423 OSSymbol::withCString(kIOHibernateFileKey);
424 const OSSymbol *hibernatefreeratio_string =
425 OSSymbol::withCString(kIOHibernateFreeRatioKey);
426 const OSSymbol *hibernatefreetime_string =
427 OSSymbol::withCString(kIOHibernateFreeTimeKey);
9bccf70c 428
e5568f75
A
429 if(!dict)
430 {
431 return_value = kIOReturnBadArgument;
432 goto exit;
433 }
4a249263 434
e5568f75
A
435 if( systemBooting
436 && boot_complete_string
437 && dict->getObject(boot_complete_string))
55e303ae 438 {
9bccf70c 439 systemBooting = false;
9bccf70c 440 adjustPowerState();
5d5c5d0d
A
441
442 // If lid is closed, re-send lid closed notification
443 // now that booting is complete.
444 if( clamshellIsClosed )
445 {
446 this->receivePowerNotification(kLocalEvalClamshellCommand);
447 }
9bccf70c
A
448 }
449
e5568f75
A
450 if( stall_halt_string
451 && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) )
55e303ae 452 {
4a249263 453 setProperty(stall_halt_string, b);
55e303ae 454 }
91447636 455
3a60a9f5 456 if ( hibernatemode_string
5d5c5d0d 457 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string))))
3a60a9f5 458 {
5d5c5d0d 459 setProperty(hibernatemode_string, n);
3a60a9f5
A
460 }
461 if ( hibernatefreeratio_string
5d5c5d0d 462 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string))))
3a60a9f5 463 {
5d5c5d0d 464 setProperty(hibernatefreeratio_string, n);
3a60a9f5
A
465 }
466 if ( hibernatefreetime_string
5d5c5d0d 467 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string))))
3a60a9f5 468 {
5d5c5d0d 469 setProperty(hibernatefreetime_string, n);
3a60a9f5
A
470 }
471 if ( hibernatefile_string
5d5c5d0d 472 && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string))))
8ad349bb 473 {
5d5c5d0d 474 setProperty(hibernatefile_string, str);
8ad349bb 475 }
e5568f75 476
5d5c5d0d
A
477 // Relay our allowed PM settings onto our registered PM clients
478 for(i = 0; i < allowedPMSettings->getCount(); i++) {
8ad349bb 479
5d5c5d0d
A
480 type = (OSSymbol *)allowedPMSettings->getObject(i);
481 if(!type) continue;
8ad349bb 482
5d5c5d0d
A
483 obj = dict->getObject(type);
484 if(!obj) continue;
485
486 return_value = setPMSetting(type, obj);
487
8ad349bb
A
488 if(kIOReturnSuccess != return_value) goto exit;
489 }
490
e5568f75 491 exit:
4a249263 492 if(boot_complete_string) boot_complete_string->release();
4a249263 493 if(stall_halt_string) stall_halt_string->release();
e5568f75 494 return return_value;
9bccf70c
A
495}
496
1c79356b
A
497
498//*********************************************************************************
499// youAreRoot
500//
501// Power Managment is informing us that we are the root power domain.
502// We know we are not the root however, since we have just instantiated a parent
503// for ourselves and made it the root. We override this method so it will have
504// no effect
505//*********************************************************************************
506IOReturn IOPMrootDomain::youAreRoot ( void )
507{
508 return IOPMNoErr;
509}
510
1c79356b
A
511// **********************************************************************************
512// command_received
513//
9bccf70c 514// No longer used
1c79356b 515// **********************************************************************************
9bccf70c 516void IOPMrootDomain::command_received ( void * w, void * x, void * y, void * z )
1c79356b 517{
9bccf70c
A
518 super::command_received(w,x,y,z);
519}
0b4e3aa0 520
0b4e3aa0 521
9bccf70c
A
522// **********************************************************************************
523// broadcast_aggressiveness
524//
525// **********************************************************************************
526IOReturn broadcast_aggressiveness ( OSObject * root, void * x, void * y, void *, void * )
527{
528 ((IOPMrootDomain *)root)->broadcast_it((unsigned long)x,(unsigned long)y);
529 return IOPMNoErr;
530}
0b4e3aa0
A
531
532
9bccf70c
A
533// **********************************************************************************
534// broadcast_it
535//
536// We are behind the command gate to broadcast an aggressiveness factor. We let the
537// superclass do it, but we need to snoop on factors that affect idle sleep.
538// **********************************************************************************
539void IOPMrootDomain::broadcast_it (unsigned long type, unsigned long value)
540{
541 super::setAggressiveness(type,value);
542
543 // Save user's spin down timer to restore after we replace it for idle sleep
544 if( type == kPMMinutesToSpinDown ) user_spindown = value;
545
546 // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer
547 longestNonSleepSlider = pm_vars->current_aggressiveness_values[kPMMinutesToDim];
548
549
550 if ( type == kPMMinutesToSleep ) {
551 if ( (sleepSlider == 0) && (value != 0) ) {
552 sleepSlider = value;
55e303ae
A
553 // idle sleep is now enabled, maybe sleep now
554 adjustPowerState();
9bccf70c
A
555 }
556 sleepSlider = value;
557 if ( sleepSlider == 0 ) {
55e303ae
A
558 // idle sleep is now disabled
559 adjustPowerState();
560 // make sure we're powered
561 patriarch->wakeSystem();
9bccf70c
A
562 }
563 }
564 if ( sleepSlider > longestNonSleepSlider ) {
565 extraSleepDelay = sleepSlider - longestNonSleepSlider ;
566 }
567 else {
568 extraSleepDelay = 0;
1c79356b
A
569 }
570}
571
572
0b4e3aa0
A
573// **********************************************************************************
574// sleepTimerExpired
575//
576// **********************************************************************************
577static void sleepTimerExpired ( thread_call_param_t us)
578{
579 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
580 }
581
d52fe63f
A
582
583static void wakeupClamshellTimerExpired ( thread_call_param_t us)
584{
585 ((IOPMrootDomain *)us)->stopIgnoringClamshellEventsDuringWakeup();
586}
587
0b4e3aa0
A
588
589// **********************************************************************************
590// handleSleepTimerExpiration
591//
592// The time between the sleep idle timeout and the next longest one has elapsed.
593// It's time to sleep. Start that by removing the clamp that's holding us awake.
594// **********************************************************************************
595void IOPMrootDomain::handleSleepTimerExpiration ( void )
596{
597 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
598 if(0 != user_spindown)
599 setQuickSpinDownTimeout();
600
601 sleepASAP = true;
602 adjustPowerState();
603}
604
605
d52fe63f
A
606void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void)
607{
d52fe63f
A
608 // Allow clamshell-induced sleep now
609 ignoringClamshellDuringWakeup = false;
610
5d5c5d0d
A
611 // Re-send clamshell event, in case it causes a sleep
612 if(clamshellIsClosed)
613 this->receivePowerNotification( kLocalEvalClamshellCommand );
d52fe63f
A
614}
615
1c79356b
A
616//*********************************************************************************
617// setAggressiveness
618//
9bccf70c 619// Some aggressiveness factor has changed. We broadcast it to the hierarchy while on
1c79356b
A
620// the Power Mangement workloop thread. This enables objects in the
621// hierarchy to successfully alter their idle timers, which are all on the
622// same thread.
623//*********************************************************************************
624
3a60a9f5
A
625static int pmsallsetup = 0;
626
1c79356b
A
627IOReturn IOPMrootDomain::setAggressiveness ( unsigned long type, unsigned long newLevel )
628{
3a60a9f5
A
629#ifdef __ppc__
630 if(pmsExperimental & 3) kprintf("setAggressiveness: type = %08X, newlevel = %08X\n", type, newLevel);
631 if(pmsExperimental & 1) { /* Is experimental mode enabled? */
632 if(pmsInstalled && (type == kPMSetProcessorSpeed)) { /* We want to look at all processor speed changes if stepper is installed */
633 if(pmsallsetup) return kIOReturnSuccess; /* If already running, just eat this */
634 kprintf("setAggressiveness: starting stepper...\n");
635 pmsallsetup = 1; /* Remember we did this */
636 pmsPark();
637 pmsStart(); /* Get it all started up... */
638 return kIOReturnSuccess; /* Leave now... */
639 }
640 }
641#endif
642
9bccf70c
A
643 if ( pm_vars->PMcommandGate ) {
644 pm_vars->PMcommandGate->runAction(broadcast_aggressiveness,(void *)type,(void *)newLevel);
0b4e3aa0 645 }
1c79356b
A
646
647 return kIOReturnSuccess;
648}
649
650
651// **********************************************************************************
652// sleepSystem
653//
654// **********************************************************************************
655IOReturn IOPMrootDomain::sleepSystem ( void )
656{
1c79356b
A
657 if ( !systemBooting && allowSleep && sleepIsSupported ) {
658 patriarch->sleepSystem();
91447636 659
0b4e3aa0 660 return kIOReturnSuccess;
1c79356b 661 }
0b4e3aa0
A
662 if ( !systemBooting && allowSleep && !sleepIsSupported ) {
663 patriarch->dozeSystem();
664 return kIOReturnSuccess;
665 }
666 return kIOReturnSuccess;
667}
668
669
670// **********************************************************************************
671// shutdownSystem
672//
673// **********************************************************************************
674IOReturn IOPMrootDomain::shutdownSystem ( void )
675{
55e303ae
A
676 //patriarch->shutDownSystem();
677 return kIOReturnUnsupported;
0b4e3aa0
A
678}
679
680
681// **********************************************************************************
682// restartSystem
683//
684// **********************************************************************************
685IOReturn IOPMrootDomain::restartSystem ( void )
686{
55e303ae
A
687 //patriarch->restartSystem();
688 return kIOReturnUnsupported;
1c79356b
A
689}
690
691
692// **********************************************************************************
693// powerChangeDone
694//
695// This overrides powerChangeDone in IOService.
0b4e3aa0
A
696//
697// Finder sleep and idle sleep move us from the ON state to the SLEEP_STATE.
698// In this case:
699// If we just finished going to the SLEEP_STATE, and the platform is capable of true sleep,
700// sleep the kernel. Otherwise switch up to the DOZE_STATE which will keep almost
701// everything as off as it can get.
702//
703// **********************************************************************************
704void IOPMrootDomain::powerChangeDone ( unsigned long previousState )
705{
706 OSNumber * propertyPtr;
707 unsigned short theProperty;
708 AbsoluteTime deadline;
709
710 switch ( pm_vars->myCurrentState ) {
711 case SLEEP_STATE:
55e303ae
A
712 if ( canSleep && sleepIsSupported )
713 {
714 // re-enable this timer for next sleep
715 idleSleepPending = false;
91447636 716
3a60a9f5
A
717 IOLog("System %sSleep\n", gIOHibernateState ? "Safe" : "");
718
719 IOHibernateSystemHasSlept();
720
55e303ae 721 pm_vars->thePlatform->sleepKernel();
9bccf70c 722
55e303ae 723 // The CPU(s) are off at this point. When they're awakened by CPU interrupt,
91447636
A
724 // code will resume execution here.
725
55e303ae 726 // Now we're waking...
5d5c5d0d 727 IOHibernateSystemWake();
9bccf70c 728
55e303ae
A
729 // stay awake for at least 30 seconds
730 clock_interval_to_deadline(30, kSecondScale, &deadline);
0b4e3aa0 731 thread_call_enter_delayed(extraSleepTimer, deadline);
55e303ae
A
732 // this gets turned off when we sleep again
733 idleSleepPending = true;
d52fe63f
A
734
735 // Ignore closed clamshell during wakeup and for a few seconds
736 // after wakeup is complete
737 ignoringClamshellDuringWakeup = true;
738
55e303ae
A
739 // sleep transition complete
740 gSleepOrShutdownPending = 0;
741
742 // trip the reset of the calendar clock
743 clock_wakeup_calendar();
744
745 // get us some power
746 patriarch->wakeSystem();
0b4e3aa0 747
55e303ae
A
748 // early stage wake notification
749 tellClients(kIOMessageSystemWillPowerOn);
750
751 // tell the tree we're waking
3a60a9f5 752 IOLog("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
55e303ae 753 systemWake();
d52fe63f
A
754
755 // Allow drivers to request extra processing time before clamshell
756 // sleep if kIOREMSleepEnabledKey is present.
757 // Ignore clamshell events for at least 5 seconds
758 if(getProperty(kIOREMSleepEnabledKey)) {
759 // clamshellWakeupIgnore callout clears ignoreClamshellDuringWakeup bit
760 clock_interval_to_deadline(5, kSecondScale, &deadline);
5d5c5d0d
A
761 if(clamshellWakeupIgnore) {
762 thread_call_enter_delayed(clamshellWakeupIgnore, deadline);
763 }
d52fe63f 764 } else ignoringClamshellDuringWakeup = false;
55e303ae
A
765
766 // Find out what woke us
0b4e3aa0 767 propertyPtr = OSDynamicCast(OSNumber,getProperty("WakeEvent"));
55e303ae 768 if ( propertyPtr ) {
0b4e3aa0
A
769 theProperty = propertyPtr->unsigned16BitValue();
770 IOLog("Wake event %04x\n",theProperty);
43866e37
A
771 if ( (theProperty & 0x0008) || //lid
772 (theProperty & 0x0800) || // front panel button
773 (theProperty & 0x0020) || // external keyboard
774 (theProperty & 0x0001) ) { // internal keyboard
55e303ae
A
775 // We've identified the wakeup event as UI driven
776 reportUserInput();
0b4e3aa0 777 }
55e303ae
A
778 } else {
779 // Since we can't identify the wakeup event, treat it as UI activity
780 reportUserInput();
0b4e3aa0 781 }
55e303ae
A
782
783 // Wake for thirty seconds
784 changePowerStateToPriv(ON_STATE);
0b4e3aa0 785 powerOverrideOffPriv();
55e303ae
A
786 } else {
787 // allow us to step up a power state
788 patriarch->sleepToDoze();
789 // and do it
790 changePowerStateToPriv(DOZE_STATE);
0b4e3aa0
A
791 }
792 break;
793
794 case DOZE_STATE:
55e303ae
A
795 if ( previousState != DOZE_STATE )
796 {
0b4e3aa0
A
797 IOLog("System Doze\n");
798 }
55e303ae
A
799 // re-enable this timer for next sleep
800 idleSleepPending = false;
0b4e3aa0
A
801 gSleepOrShutdownPending = 0;
802 break;
803
804 case RESTART_STATE:
805 IOLog("System Restart\n");
806 PEHaltRestart(kPERestartCPU);
807 break;
808
809 case OFF_STATE:
810 IOLog("System Halt\n");
811 PEHaltRestart(kPEHaltCPU);
812 break;
813 }
814}
815
816
817// **********************************************************************************
818// wakeFromDoze
819//
820// The Display Wrangler calls here when it switches to its highest state. If the
821// system is currently dozing, allow it to wake by making sure the parent is
822// providing power.
1c79356b 823// **********************************************************************************
0b4e3aa0 824void IOPMrootDomain::wakeFromDoze( void )
1c79356b 825{
55e303ae
A
826 if ( pm_vars->myCurrentState == DOZE_STATE )
827 {
5d5c5d0d
A
828 // Reset sleep support till next sleep attempt.
829 // A machine's support of sleep vs. doze can change over the course of
830 // a running system, so we recalculate it before every sleep.
831 setSleepSupported(0);
832
0b4e3aa0 833 powerOverrideOffPriv();
55e303ae
A
834
835 // early wake notification
836 tellClients(kIOMessageSystemWillPowerOn);
837
838 // allow us to wake if children so desire
839 patriarch->wakeSystem();
1c79356b
A
840 }
841}
842
843
5d5c5d0d 844// *****************************************************************************
d52fe63f
A
845// publishFeature
846//
847// Adds a new feature to the supported features dictionary
848//
849//
5d5c5d0d 850// *****************************************************************************
d52fe63f
A
851void IOPMrootDomain::publishFeature( const char * feature )
852{
5d5c5d0d
A
853 publishFeature(feature, kIOPMSupportedOnAC
854 | kIOPMSupportedOnBatt
855 | kIOPMSupportedOnUPS,
856 NULL);
857 return;
858}
859
860
861// *****************************************************************************
862// publishFeature (with supported power source specified)
863//
864// Adds a new feature to the supported features dictionary
865//
866//
867// *****************************************************************************
868void IOPMrootDomain::publishFeature(
869 const char *feature,
870 uint32_t supportedWhere,
871 uint32_t *uniqueFeatureID)
872{
873 static uint16_t next_feature_id = 500;
874
875 OSNumber *new_feature_data = NULL;
876 OSNumber *existing_feature = NULL;
877 OSArray *existing_feature_arr = NULL;
878 OSObject *osObj = NULL;
879 uint32_t feature_value = 0;
880
881 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
882
883 if(!supportedWhere) {
884 // Feature isn't supported anywhere!
885 return;
886 }
887
888 if(next_feature_id > 5000) {
889 // Far, far too many features!
890 return;
891 }
892
91447636 893 if(featuresDictLock) IOLockLock(featuresDictLock);
5d5c5d0d 894
91447636
A
895 OSDictionary *features =
896 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
897
5d5c5d0d
A
898 // Create new features dict if necessary
899 if ( features && OSDynamicCast(OSDictionary, features)) {
91447636 900 features = OSDictionary::withDictionary(features);
5d5c5d0d 901 } else {
91447636 902 features = OSDictionary::withCapacity(1);
5d5c5d0d
A
903 }
904
905 // Create OSNumber to track new feature
906
907 next_feature_id += 1;
908 if( uniqueFeatureID ) {
909 // We don't really mind if the calling kext didn't give us a place
910 // to stash their unique id. Many kexts don't plan to unload, and thus
911 // have no need to remove themselves later.
912 *uniqueFeatureID = next_feature_id;
913 }
914
915 feature_value = supportedWhere + (next_feature_id << 16);
916 new_feature_data = OSNumber::withNumber(
917 (unsigned long long)feature_value, 32);
918
919 // Does features object already exist?
920 if( (osObj = features->getObject(feature)) )
921 {
922 if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
923 {
924 // We need to create an OSArray to hold the now 2 elements.
925 existing_feature_arr = OSArray::withObjects(
926 (const OSObject **)&existing_feature, 1, 2);
927 existing_feature_arr->setObject(new_feature_data);
928 features->setObject(feature, existing_feature_arr);
929 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
930 {
931 // Add object to existing array
932 existing_feature_arr->setObject(new_feature_data);
933 }
934 } else {
935 // The easy case: no previously existing features listed. We simply
936 // set the OSNumber at key 'feature' and we're on our way.
937 features->setObject(feature, new_feature_data);
938 }
939
940 new_feature_data->release();
91447636 941
91447636 942 setProperty(kRootDomainSupportedFeatures, features);
5d5c5d0d 943
91447636 944 features->release();
5d5c5d0d
A
945
946 // Notify EnergySaver and all those in user space so they might
947 // re-populate their feature specific UI
948 messageClients(kIOPMMessageFeatureChange, this);
949
950 if(featuresDictLock) IOLockUnlock(featuresDictLock);
951}
952
953// *****************************************************************************
954// removePublishedFeature
955//
956// Removes previously published feature
957//
958//
959// *****************************************************************************
960IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
961{
962 IOReturn ret = kIOReturnError;
963 uint32_t feature_value = 0;
964 uint16_t feature_id = 0;
965 bool madeAChange = false;
966
967 OSSymbol *dictKey = NULL;
968 OSCollectionIterator *dictIterator = NULL;
969 OSArray *arrayMember = NULL;
970 OSNumber *numberMember = NULL;
971 OSObject *osObj = NULL;
972 OSNumber *osNum = NULL;
973
974 if(featuresDictLock) IOLockLock(featuresDictLock);
975
976 OSDictionary *features =
977 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
978
979 if ( features && OSDynamicCast(OSDictionary, features) )
980 {
981 // Any modifications to the dictionary are made to the copy to prevent
982 // races & crashes with userland clients. Dictionary updated
983 // automically later.
984 features = OSDictionary::withDictionary(features);
985 } else {
986 features = NULL;
987 ret = kIOReturnNotFound;
988 goto exit;
989 }
990
991 // We iterate 'features' dictionary looking for an entry tagged
992 // with 'removeFeatureID'. If found, we remove it from our tracking
993 // structures and notify the OS via a general interest message.
994
995 dictIterator = OSCollectionIterator::withCollection(features);
996 if(!dictIterator) {
997 goto exit;
998 }
999
1000 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
1001 {
1002 osObj = features->getObject(dictKey);
1003
1004 // Each Feature is either tracked by an OSNumber
1005 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
1006 {
1007 feature_value = numberMember->unsigned32BitValue();
1008 feature_id = (uint16_t)(feature_value >> 16);
1009
1010 if( feature_id == (uint16_t)removeFeatureID )
1011 {
1012 // Remove this node
1013 features->removeObject(dictKey);
1014 madeAChange = true;
1015 break;
1016 }
1017
1018 // Or tracked by an OSArray of OSNumbers
1019 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
1020 {
1021 unsigned int arrayCount = arrayMember->getCount();
1022
1023 for(unsigned int i=0; i<arrayCount; i++)
1024 {
1025 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
1026 if(!osNum) {
1027 continue;
1028 }
1029
1030 feature_value = osNum->unsigned32BitValue();
1031 feature_id = (uint16_t)(feature_value >> 16);
1032
1033 if( feature_id == (uint16_t)removeFeatureID )
1034 {
1035 // Remove this node
1036 if( 1 == arrayCount ) {
1037 // If the array only contains one element, remove
1038 // the whole thing.
1039 features->removeObject(dictKey);
1040 } else {
1041 // Otherwise just remove the element in question.
1042 arrayMember->removeObject(i);
1043 }
1044
1045 madeAChange = true;
1046 break;
1047 }
1048 }
1049 }
1050 }
1051
1052
1053 dictIterator->release();
1054
1055 if( madeAChange )
1056 {
1057 ret = kIOReturnSuccess;
1058
1059 setProperty(kRootDomainSupportedFeatures, features);
1060
1061 // Notify EnergySaver and all those in user space so they might
1062 // re-populate their feature specific UI
1063 messageClients(kIOPMMessageFeatureChange, this);
1064 } else {
1065 ret = kIOReturnNotFound;
1066 }
1067
1068exit:
1069 if(features) features->release();
1070 if(featuresDictLock) IOLockUnlock(featuresDictLock);
1071 return ret;
c0fea474
A
1072}
1073
c0fea474 1074
5d5c5d0d
A
1075// **********************************************************************************
1076// unIdleDevice
1077//
1078// Enqueues unidle event to be performed later in a serialized context.
1079//
1080// **********************************************************************************
55e303ae 1081void IOPMrootDomain::unIdleDevice( IOService *theDevice, unsigned long theState )
1c79356b 1082{
55e303ae
A
1083 if(pmPowerStateQueue)
1084 pmPowerStateQueue->unIdleOccurred(theDevice, theState);
1085}
1c79356b 1086
5d5c5d0d
A
1087// **********************************************************************************
1088// announcePowerSourceChange
1089//
1090// Notifies "interested parties" that the batteries have changed state
1091//
1092// **********************************************************************************
55e303ae
A
1093void IOPMrootDomain::announcePowerSourceChange( void )
1094{
5d5c5d0d
A
1095 IORegistryEntry *_batteryRegEntry = (IORegistryEntry *) getProperty("BatteryEntry");
1096
1097 // (if possible) re-publish power source state under IOPMrootDomain;
1098 // only do so if the battery controller publishes an IOResource
1099 // defining battery location. Called from ApplePMU battery driver.
483a1d10 1100
483a1d10
A
1101 if(_batteryRegEntry)
1102 {
1103 OSArray *batt_info;
91447636 1104 batt_info = (OSArray *) _batteryRegEntry->getProperty(kIOBatteryInfoKey);
483a1d10
A
1105 if(batt_info)
1106 setProperty(kIOBatteryInfoKey, batt_info);
1107 }
1108
1c79356b
A
1109}
1110
5d5c5d0d
A
1111
1112// *****************************************************************************
1113// setPMSetting (private)
1114//
1115// Internal helper to relay PM settings changes from user space to individual
1116// drivers. Should be called only by IOPMrootDomain::setProperties.
1117//
1118// *****************************************************************************
1119IOReturn IOPMrootDomain::setPMSetting(
1120 const OSSymbol *type,
1121 OSObject *obj)
e5568f75 1122{
5d5c5d0d
A
1123 OSArray *arr = NULL;
1124 PMSettingObject *p_obj = NULL;
1125 int count;
1126 int i;
1127
1128 if(NULL == type) return kIOReturnBadArgument;
1129
1130 IORecursiveLockLock(settingsCtrlLock);
8ad349bb 1131
5d5c5d0d
A
1132 fPMSettingsDict->setObject(type, obj);
1133
1134 arr = (OSArray *)settingsCallbacks->getObject(type);
1135 if(NULL == arr) goto exit;
1136 count = arr->getCount();
1137 for(i=0; i<count; i++) {
1138 p_obj = (PMSettingObject *)OSDynamicCast(PMSettingObject, arr->getObject(i));
1139 if(p_obj) p_obj->setPMSetting(type, obj);
1140 }
1141
1142exit:
1143 IORecursiveLockUnlock(settingsCtrlLock);
e5568f75
A
1144 return kIOReturnSuccess;
1145}
1146
5d5c5d0d
A
1147// *****************************************************************************
1148// copyPMSetting (public)
1149//
1150// Allows kexts to safely read setting values, without being subscribed to
1151// notifications.
1152//
1153// *****************************************************************************
1154OSObject * IOPMrootDomain::copyPMSetting(
1155 OSSymbol *whichSetting)
1156{
1157 OSObject *obj = NULL;
e5568f75 1158
5d5c5d0d
A
1159 if(!whichSetting) return NULL;
1160
1161 IORecursiveLockLock(settingsCtrlLock);
1162 obj = fPMSettingsDict->getObject(whichSetting);
1163 if(obj) {
1164 obj->retain();
1165 }
1166 IORecursiveLockUnlock(settingsCtrlLock);
1167
1168 return obj;
1169}
1170
1171// *****************************************************************************
1172// registerPMSettingController (public)
1c79356b 1173//
5d5c5d0d
A
1174// direct wrapper to registerPMSettingController with uint32_t power source arg
1175// *****************************************************************************
1176IOReturn IOPMrootDomain::registerPMSettingController(
1177 const OSSymbol * settings[],
1178 IOPMSettingControllerCallback func,
1179 OSObject *target,
1180 uintptr_t refcon,
1181 OSObject **handle)
1182{
1183 return registerPMSettingController(
1184 settings,
1185 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
1186 func, target, refcon, handle);
1187}
1c79356b 1188
5d5c5d0d
A
1189// *****************************************************************************
1190// registerPMSettingController (public)
1191//
1192// Kexts may register for notifications when a particular setting is changed.
1193// A list of settings is available in IOPM.h.
1194// Arguments:
1195// * settings - An OSArray containing OSSymbols. Caller should populate this
1196// array with a list of settings caller wants notifications from.
1197// * func - A C function callback of the type IOPMSettingControllerCallback
1198// * target - caller may provide an OSObject *, which PM will pass as an
1199// target to calls to "func"
1200// * refcon - caller may provide an void *, which PM will pass as an
1201// argument to calls to "func"
1202// * handle - This is a return argument. We will populate this pointer upon
1203// call success. Hold onto this and pass this argument to
1204// IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
1205// Returns:
1206// kIOReturnSuccess on success
1207// *****************************************************************************
1208IOReturn IOPMrootDomain::registerPMSettingController(
1209 const OSSymbol * settings[],
1210 uint32_t supportedPowerSources,
1211 IOPMSettingControllerCallback func,
1212 OSObject *target,
1213 uintptr_t refcon,
1214 OSObject **handle)
1c79356b 1215{
5d5c5d0d
A
1216 PMSettingObject *pmso = NULL;
1217 OSArray *list = NULL;
1218 IOReturn ret = kIOReturnSuccess;
1219 int i;
1220
1221 if( NULL == settings ||
1222 NULL == func ||
1223 NULL == handle)
55e303ae 1224 {
5d5c5d0d 1225 return kIOReturnBadArgument;
c0fea474 1226 }
5d5c5d0d
A
1227
1228
1229 pmso = PMSettingObject::pmSettingObject(
1230 (IOPMrootDomain *)this, func, target,
1231 refcon, supportedPowerSources, settings);
1232
1233 if(!pmso) {
1234 ret = kIOReturnInternalError;
1235 goto bail_no_unlock;
1236 }
1237
1238 IORecursiveLockLock(settingsCtrlLock);
1239 for(i=0; settings[i]; i++)
55e303ae 1240 {
5d5c5d0d
A
1241 list = (OSArray *)settingsCallbacks->getObject(settings[i]);
1242 if(!list) {
1243 // New array of callbacks for this setting
1244 list = OSArray::withCapacity(1);
1245 settingsCallbacks->setObject(settings[i], list);
1246 list->release();
1247 }
1248
1249 // Add caller to the callback list
1250 list->setObject(pmso);
d52fe63f 1251 }
5d5c5d0d
A
1252
1253 ret = kIOReturnSuccess;
1254
1255 // Track this instance by its OSData ptr from now on
1256 *handle = pmso;
1257
1258 IORecursiveLockUnlock(settingsCtrlLock);
1259
1260bail_no_unlock:
1261 if(kIOReturnSuccess != ret)
55e303ae 1262 {
5d5c5d0d
A
1263 // Error return case
1264 if(pmso) pmso->release();
1265 if(handle) *handle = NULL;
d52fe63f 1266 }
5d5c5d0d
A
1267 return ret;
1268}
1269
1270//******************************************************************************
1271// sleepOnClamshellClosed
1272//
1273// contains the logic to determine if the system should sleep when the clamshell
1274// is closed.
1275//******************************************************************************
1276
1277bool IOPMrootDomain::shouldSleepOnClamshellClosed ( void )
1278{
1279 return ( !ignoringClamshell
1280 && !ignoringClamshellDuringWakeup
1281 && !(desktopMode && acAdaptorConnect) );
1282}
1283
1284void IOPMrootDomain::sendClientClamshellNotification ( void )
1285{
1286 /* Only broadcast clamshell alert if clamshell exists. */
1287 if(!clamshellExists)
1288 return;
1289
1290 setProperty(kAppleClamshellStateKey,
1291 clamshellIsClosed ? kOSBooleanTrue : kOSBooleanFalse);
1292
1293 setProperty(kAppleClamshellCausesSleepKey,
1294 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
1295
1296
1297 /* Argument to message is a bitfield of
1298 * ( kClamshellStateBit | kClamshellSleepBit )
1299 * Carry on the clamshell state change notification from an
1300 * independent thread.
1301 */
1302 pmArbiter->clamshellStateChangeOccurred(
1303 (uint32_t) ( (clamshellIsClosed ? kClamshellStateBit : 0)
1304 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)));
1305}
1306
1307//******************************************************************************
1308// receivePowerNotification
1309//
1310// The power controller is notifying us of a hardware-related power management
1311// event that we must handle. This is a result of an 'environment' interrupt from
1312// the power mgt micro.
1313//******************************************************************************
1314
1315IOReturn IOPMrootDomain::receivePowerNotification (UInt32 msg)
1316{
1317 bool eval_clamshell = false;
1318
1319 /*
1320 * Local (IOPMrootDomain only) eval clamshell command
1321 */
1322 if (msg & kLocalEvalClamshellCommand)
55e303ae 1323 {
5d5c5d0d 1324 eval_clamshell = true;
d52fe63f 1325 }
5d5c5d0d
A
1326
1327 /*
1328 * Overtemp
1329 */
1330 if (msg & kIOPMOverTemp)
55e303ae 1331 {
5d5c5d0d
A
1332 IOLog("PowerManagement emergency overtemp signal. Going to sleep!");
1333 (void) sleepSystem ();
d52fe63f
A
1334 }
1335
5d5c5d0d
A
1336 /*
1337 * PMU Processor Speed Change
1338 */
55e303ae
A
1339 if (msg & kIOPMProcessorSpeedChange)
1340 {
1341 IOService *pmu = waitForService(serviceMatching("ApplePMU"));
1342 pmu->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
d52fe63f 1343 pm_vars->thePlatform->sleepKernel();
55e303ae 1344 pmu->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
d52fe63f
A
1345 }
1346
5d5c5d0d
A
1347 /*
1348 * Sleep Now!
1349 */
55e303ae
A
1350 if (msg & kIOPMSleepNow)
1351 {
1c79356b
A
1352 (void) sleepSystem ();
1353 }
1354
5d5c5d0d
A
1355 /*
1356 * Power Emergency
1357 */
55e303ae
A
1358 if (msg & kIOPMPowerEmergency)
1359 {
1c79356b
A
1360 (void) sleepSystem ();
1361 }
1362
5d5c5d0d
A
1363
1364 /*
1365 * Clamshell OPEN
1366 */
1367 if (msg & kIOPMClamshellOpened)
1368 {
1369 // Received clamshel open message from clamshell controlling driver
1370 // Update our internal state and tell general interest clients
1371 clamshellIsClosed = false;
1372 clamshellExists = true;
1373
1374 sendClientClamshellNotification();
1375 }
1376
1377 /*
1378 * Clamshell CLOSED
1379 * Send the clamshell interest notification since the lid is closing.
1380 */
1381 if (msg & kIOPMClamshellClosed)
55e303ae 1382 {
5d5c5d0d
A
1383 // Received clamshel open message from clamshell controlling driver
1384 // Update our internal state and tell general interest clients
1385 clamshellIsClosed = true;
1386 clamshellExists = true;
1387
1388 sendClientClamshellNotification();
1389
1390 // And set eval_clamshell = so we can attempt
1391 eval_clamshell = true;
1392 }
1393
1394 /*
1395 * Set Desktop mode (sent from graphics)
1396 *
1397 * -> reevaluate lid state
1398 */
1399 if (msg & kIOPMSetDesktopMode)
1400 {
1401 desktopMode = (0 != (msg & kIOPMSetValue));
1402 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
1403
1404 sendClientClamshellNotification();
1405
1406 // Re-evaluate the lid state
1407 if( clamshellIsClosed )
1408 {
1409 eval_clamshell = true;
1410 }
1411 }
1412
1413 /*
1414 * AC Adaptor connected
1415 *
1416 * -> reevaluate lid state
1417 */
1418 if (msg & kIOPMSetACAdaptorConnected)
1419 {
1420 acAdaptorConnect = (0 != (msg & kIOPMSetValue));
1421 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
1422
1423 sendClientClamshellNotification();
1424
1425 // Re-evaluate the lid state
1426 if( clamshellIsClosed )
55e303ae 1427 {
5d5c5d0d
A
1428 eval_clamshell = true;
1429 }
d52fe63f 1430
5d5c5d0d
A
1431 }
1432
1433 /*
1434 * Enable Clamshell (external display disappear)
1435 *
1436 * -> reevaluate lid state
1437 */
1438 if (msg & kIOPMEnableClamshell)
1439 {
1440 // Re-evaluate the lid state
1441 // System should sleep on external display disappearance
1442 // in lid closed operation.
1443 if( clamshellIsClosed && (true == ignoringClamshell) )
1444 {
1445 eval_clamshell = true;
d52fe63f 1446 }
5d5c5d0d
A
1447
1448 ignoringClamshell = false;
1449
1450 sendClientClamshellNotification();
1451 }
1452
1453 /*
1454 * Disable Clamshell (external display appeared)
1455 * We don't bother re-evaluating clamshell state. If the system is awake,
1456 * the lid is probably open.
1457 */
1458 if (msg & kIOPMDisableClamshell)
1459 {
1460 ignoringClamshell = true;
1461
1462 sendClientClamshellNotification();
1c79356b
A
1463 }
1464
5d5c5d0d
A
1465 /*
1466 * Evaluate clamshell and SLEEP if appropiate
1467 */
1468 if ( eval_clamshell && shouldSleepOnClamshellClosed() )
1469 {
1470
1471
1472 // SLEEP!
1473 sleepSystem();
1474 }
1475
1476 /*
1477 * Power Button
1478 */
55e303ae
A
1479 if (msg & kIOPMPowerButton)
1480 {
1481 // toggle state of sleep/wake
1482 // are we dozing?
1483 if ( pm_vars->myCurrentState == DOZE_STATE )
1484 {
1485 // yes, tell the tree we're waking
1486 systemWake();
1487 // wake the Display Wrangler
1488 reportUserInput();
0b4e3aa0
A
1489 }
1490 else {
5d5c5d0d 1491 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
55e303ae 1492 // Check that power button sleep is enabled
5d5c5d0d
A
1493 if( pbs ) {
1494 if( kOSBooleanTrue != getProperty(pbs))
55e303ae 1495 sleepSystem();
5d5c5d0d 1496 }
1c79356b 1497 }
0b4e3aa0
A
1498 }
1499
5d5c5d0d
A
1500 /*
1501 * Allow Sleep
1502 *
1503 */
55e303ae
A
1504 if ( (msg & kIOPMAllowSleep) && !allowSleep )
1505 {
1506 allowSleep = true;
0b4e3aa0 1507 adjustPowerState();
1c79356b
A
1508 }
1509
5d5c5d0d
A
1510 /*
1511 * Prevent Sleep
1512 *
1513 */
1c79356b 1514 if (msg & kIOPMPreventSleep) {
55e303ae
A
1515 allowSleep = false;
1516 // are we dozing?
1517 if ( pm_vars->myCurrentState == DOZE_STATE ) {
1518 // yes, tell the tree we're waking
1519 systemWake();
0b4e3aa0 1520 adjustPowerState();
55e303ae
A
1521 // wake the Display Wrangler
1522 reportUserInput();
1523 } else {
0b4e3aa0 1524 adjustPowerState();
55e303ae
A
1525 // make sure we have power to clamp
1526 patriarch->wakeSystem();
0b4e3aa0 1527 }
1c79356b
A
1528 }
1529
1530 return 0;
1531}
1532
1533
1534//*********************************************************************************
1535// sleepSupported
1536//
1537//*********************************************************************************
1538
1539void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
1540{
55e303ae
A
1541 if ( flags & kPCICantSleep )
1542 {
0b4e3aa0 1543 canSleep = false;
55e303ae 1544 } else {
5d5c5d0d 1545 canSleep = true;
0b4e3aa0
A
1546 platformSleepSupport = flags;
1547 }
1548
5d5c5d0d
A
1549 setProperty(kIOSleepSupportedKey, canSleep);
1550
0b4e3aa0
A
1551}
1552
1553//*********************************************************************************
1554// requestPowerDomainState
1555//
1556// The root domain intercepts this call to the superclass.
1557//
1558// If the clamp bit is not set in the desire, then the child doesn't need the power
1559// state it's requesting; it just wants it. The root ignores desires but not needs.
1560// If the clamp bit is not set, the root takes it that the child can tolerate no
1561// power and interprets the request accordingly. If all children can thus tolerate
1562// no power, we are on our way to idle sleep.
1563//*********************************************************************************
1564
1565IOReturn IOPMrootDomain::requestPowerDomainState ( IOPMPowerFlags desiredState, IOPowerConnection * whichChild, unsigned long specification )
1566{
55e303ae
A
1567 OSIterator *iter;
1568 OSObject *next;
1569 IOPowerConnection *connection;
1570 unsigned long powerRequestFlag = 0;
1571 IOPMPowerFlags editedDesire = desiredState;
1572
1573 // if they don't really need it, they don't get it
1574 if ( !(desiredState & kIOPMPreventIdleSleep) ) {
0b4e3aa0
A
1575 editedDesire = 0;
1576 }
1577
1578
55e303ae
A
1579 IOLockLock(pm_vars->childLock);
1580
1581 // recompute sleepIsSupported and see if all children are asleep
0b4e3aa0
A
1582 iter = getChildIterator(gIOPowerPlane);
1583 sleepIsSupported = true;
55e303ae
A
1584 if ( iter )
1585 {
1586 while ( (next = iter->getNextObject()) )
1587 {
1588 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
1589 {
1590 if ( connection == whichChild )
1591 {
0b4e3aa0 1592 powerRequestFlag += editedDesire;
55e303ae
A
1593 if ( desiredState & kIOPMPreventSystemSleep )
1594 {
0b4e3aa0
A
1595 sleepIsSupported = false;
1596 }
55e303ae 1597 } else {
0b4e3aa0 1598 powerRequestFlag += connection->getDesiredDomainState();
55e303ae
A
1599 if ( connection->getPreventSystemSleepFlag() )
1600 {
0b4e3aa0
A
1601 sleepIsSupported = false;
1602 }
1603 }
1604 }
1605 }
1606 iter->release();
1607 }
9bccf70c 1608
55e303ae
A
1609 if ( (extraSleepDelay == 0) && (powerRequestFlag == 0) )
1610 {
0b4e3aa0 1611 sleepASAP = true;
1c79356b 1612 }
0b4e3aa0 1613
55e303ae
A
1614 // this may put the system to sleep
1615 adjustPowerState();
0b4e3aa0
A
1616
1617 IOLockUnlock(pm_vars->childLock);
1618
1619 editedDesire |= desiredState & kIOPMPreventSystemSleep;
1c79356b 1620
0b4e3aa0 1621 return super::requestPowerDomainState(editedDesire,whichChild,specification);
1c79356b
A
1622}
1623
0b4e3aa0 1624
1c79356b
A
1625//*********************************************************************************
1626// getSleepSupported
1627//
1628//*********************************************************************************
1629
1630IOOptionBits IOPMrootDomain::getSleepSupported( void )
1631{
1632 return( platformSleepSupport );
1633}
1634
1635
1636//*********************************************************************************
1637// tellChangeDown
1638//
1639// We override the superclass implementation so we can send a different message
1640// type to the client or application being notified.
1641//*********************************************************************************
1642
1643bool IOPMrootDomain::tellChangeDown ( unsigned long stateNum )
1644{
0b4e3aa0
A
1645 switch ( stateNum ) {
1646 case DOZE_STATE:
1647 case SLEEP_STATE:
5d5c5d0d
A
1648
1649 // Direct callout into OSMetaClass so it can disable kmod unloads
1650 // during sleep/wake to prevent deadlocks.
1651 OSMetaClassSystemSleepOrWake( kIOMessageSystemWillSleep );
1652
0b4e3aa0
A
1653 return super::tellClientsWithResponse(kIOMessageSystemWillSleep);
1654 case RESTART_STATE:
5d5c5d0d
A
1655 // Unsupported shutdown ordering hack on RESTART only
1656 // For Bluetooth and USB (4368327)
1657 super::tellClients(iokit_common_msg(0x759));
1658
0b4e3aa0
A
1659 return super::tellClientsWithResponse(kIOMessageSystemWillRestart);
1660 case OFF_STATE:
5d5c5d0d
A
1661 // Unsupported shutdown ordering hack on SHUTDOWN only
1662 // For Bluetooth and USB (4554440)
1663 super::tellClients(iokit_common_msg(0x749));
1664
0b4e3aa0 1665 return super::tellClientsWithResponse(kIOMessageSystemWillPowerOff);
1c79356b 1666 }
55e303ae
A
1667 // this shouldn't execute
1668 return super::tellChangeDown(stateNum);
1c79356b
A
1669}
1670
1671
1672//*********************************************************************************
1673// askChangeDown
1674//
1675// We override the superclass implementation so we can send a different message
1676// type to the client or application being notified.
0b4e3aa0
A
1677//
1678// This must be idle sleep since we don't ask apps during any other power change.
1c79356b
A
1679//*********************************************************************************
1680
0b4e3aa0 1681bool IOPMrootDomain::askChangeDown ( unsigned long )
1c79356b 1682{
0b4e3aa0 1683 return super::tellClientsWithResponse(kIOMessageCanSystemSleep);
1c79356b
A
1684}
1685
1686
1687//*********************************************************************************
1688// tellNoChangeDown
1689//
1690// Notify registered applications and kernel clients that we are not
1691// dropping power.
1692//
1693// We override the superclass implementation so we can send a different message
1694// type to the client or application being notified.
0b4e3aa0
A
1695//
1696// This must be a vetoed idle sleep, since no other power change can be vetoed.
1c79356b
A
1697//*********************************************************************************
1698
1699void IOPMrootDomain::tellNoChangeDown ( unsigned long )
1700{
1701 return tellClients(kIOMessageSystemWillNotSleep);
1702}
1703
1704
1705//*********************************************************************************
1706// tellChangeUp
1707//
1708// Notify registered applications and kernel clients that we are raising power.
1709//
1710// We override the superclass implementation so we can send a different message
1711// type to the client or application being notified.
1712//*********************************************************************************
1713
7b1edb79 1714void IOPMrootDomain::tellChangeUp ( unsigned long stateNum)
1c79356b 1715{
55e303ae
A
1716 if ( stateNum == ON_STATE )
1717 {
5d5c5d0d
A
1718 // Direct callout into OSMetaClass so it can disable kmod unloads
1719 // during sleep/wake to prevent deadlocks.
1720 OSMetaClassSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
1721
3a60a9f5 1722 IOHibernateSystemPostWake();
7b1edb79
A
1723 return tellClients(kIOMessageSystemHasPoweredOn);
1724 }
1c79356b
A
1725}
1726
0b4e3aa0
A
1727//*********************************************************************************
1728// reportUserInput
1729//
1730//*********************************************************************************
1731
1732void IOPMrootDomain::reportUserInput ( void )
1733{
1734 OSIterator * iter;
1c79356b 1735
55e303ae
A
1736 if(!wrangler)
1737 {
0b4e3aa0 1738 iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
55e303ae
A
1739 if(iter)
1740 {
0b4e3aa0
A
1741 wrangler = (IOService *) iter->getNextObject();
1742 iter->release();
1743 }
1744 }
1745
1746 if(wrangler)
1747 wrangler->activityTickle(0,0);
1748}
1749
1750//*********************************************************************************
1751// setQuickSpinDownTimeout
1c79356b 1752//
0b4e3aa0
A
1753//*********************************************************************************
1754
1755void IOPMrootDomain::setQuickSpinDownTimeout ( void )
1756{
0b4e3aa0
A
1757 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)1);
1758}
1759
1760//*********************************************************************************
1761// restoreUserSpinDownTimeout
1762//
1763//*********************************************************************************
1764
1765void IOPMrootDomain::restoreUserSpinDownTimeout ( void )
1766{
0b4e3aa0
A
1767 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)user_spindown);
1768}
1769
9bccf70c
A
1770//*********************************************************************************
1771// changePowerStateTo & changePowerStateToPriv
1772//
1773// Override of these methods for logging purposes.
1774//*********************************************************************************
1775
1776IOReturn IOPMrootDomain::changePowerStateTo ( unsigned long ordinal )
1777{
9bccf70c
A
1778 return super::changePowerStateTo(ordinal);
1779}
1780
1781IOReturn IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal )
1782{
5d5c5d0d
A
1783 IOReturn ret;
1784
1785 if( SLEEP_STATE == ordinal && sleepSupportedPEFunction )
1786 {
1787
1788 // Determine if the machine supports sleep, or must doze.
1789 ret = getPlatform()->callPlatformFunction(
1790 sleepSupportedPEFunction, false,
1791 NULL, NULL, NULL, NULL);
1792
1793 // If the machine only supports doze, the callPlatformFunction call
1794 // boils down toIOPMrootDomain::setSleepSupported(kPCICantSleep),
1795 // otherwise nothing.
1796 }
1797
9bccf70c
A
1798 return super::changePowerStateToPriv(ordinal);
1799}
1800
0b4e3aa0
A
1801
1802//*********************************************************************************
1803// sysPowerDownHandler
1804//
1805// Receives a notification when the RootDomain changes state.
1806//
1807// Allows us to take action on system sleep, power down, and restart after
1808// applications have received their power change notifications and replied,
1809// but before drivers have powered down. We perform a vfs sync on power down.
1810//*********************************************************************************
1811
1812IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon,
1813 UInt32 messageType, IOService * service,
1814 void * messageArgument, vm_size_t argSize )
1815{
55e303ae
A
1816 IOReturn ret;
1817 IOPowerStateChangeNotification *params = (IOPowerStateChangeNotification *) messageArgument;
1818 IOPMrootDomain *rootDomain = OSDynamicCast(IOPMrootDomain, service);
0b4e3aa0
A
1819
1820 if(!rootDomain)
1821 return kIOReturnUnsupported;
1822
1823 switch (messageType) {
1824 case kIOMessageSystemWillSleep:
1825 rootDomain->powerOverrideOnPriv(); // start ignoring children's requests
1826 // (fall through to other cases)
0b4e3aa0
A
1827
1828 // Interested applications have been notified of an impending power
1829 // change and have acked (when applicable).
1830 // This is our chance to save whatever state we can before powering
1831 // down.
1832 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
1833 // via callout
1834
1835 // We will ack within 20 seconds
1836 params->returnValue = 20 * 1000 * 1000;
3a60a9f5
A
1837 if (gIOHibernateState)
1838 params->returnValue += gIOHibernateFreeTime * 1000; //add in time we could spend freeing pages
0b4e3aa0
A
1839
1840 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
1841 {
1842 // Purposely delay the ack and hope that shutdown occurs quickly.
1843 // Another option is not to schedule the thread and wait for
1844 // ack timeout...
1845 AbsoluteTime deadline;
9bccf70c 1846 clock_interval_to_deadline( 30, kSecondScale, &deadline );
0b4e3aa0
A
1847 thread_call_enter1_delayed( rootDomain->diskSyncCalloutEntry,
1848 (thread_call_param_t)params->powerRef,
1849 deadline );
1850 }
1851 else
1852 thread_call_enter1(rootDomain->diskSyncCalloutEntry, (thread_call_param_t)params->powerRef);
1853 ret = kIOReturnSuccess;
1854 break;
fa4905b1
A
1855
1856 case kIOMessageSystemWillPowerOff:
1857 case kIOMessageSystemWillRestart:
d52fe63f 1858 ret = kIOReturnUnsupported;
fa4905b1
A
1859 break;
1860
0b4e3aa0
A
1861 default:
1862 ret = kIOReturnUnsupported;
1863 break;
1864 }
1865 return ret;
1866}
1867
1868//*********************************************************************************
1869// displayWranglerNotification
1870//
1871// Receives a notification when the IODisplayWrangler changes state.
1872//
1873// Allows us to take action on display dim/undim.
1874//
1875// When the display goes dim we:
1876// - Start the idle sleep timer
1877// - set the quick spin down timeout
1878//
1879// On wake from display dim:
1880// - Cancel the idle sleep timer
1881// - restore the user's chosen spindown timer from the "quick" spin down value
1882//*********************************************************************************
1c79356b 1883
0b4e3aa0
A
1884IOReturn IOPMrootDomain::displayWranglerNotification( void * target, void * refCon,
1885 UInt32 messageType, IOService * service,
1886 void * messageArgument, vm_size_t argSize )
1c79356b 1887{
0b4e3aa0
A
1888 IOPMrootDomain * rootDomain = OSDynamicCast(IOPMrootDomain, (IOService *)target);
1889 AbsoluteTime deadline;
1890 static bool deviceAlreadyPoweredOff = false;
1891
1892 if(!rootDomain)
1893 return kIOReturnUnsupported;
1894
1895 switch (messageType) {
1896 case kIOMessageDeviceWillPowerOff:
1897 // The IODisplayWrangler has powered off either because of idle display sleep
1898 // or force system sleep.
1899
1900 // The display wrangler will send the DeviceWillPowerOff message 4 times until
1901 // it gets into its lowest state. We only want to act on the first of those 4.
1902 if( deviceAlreadyPoweredOff ) return kIOReturnUnsupported;
1903
1904 deviceAlreadyPoweredOff = true;
1905
55e303ae
A
1906 if( rootDomain->extraSleepDelay )
1907 {
0b4e3aa0
A
1908 // start the extra sleep timer
1909 clock_interval_to_deadline(rootDomain->extraSleepDelay*60, kSecondScale, &deadline );
1910 thread_call_enter_delayed(rootDomain->extraSleepTimer, deadline);
1911 rootDomain->idleSleepPending = true;
0b4e3aa0 1912 } else {
0b4e3aa0 1913 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
9bccf70c
A
1914 // and if system sleep is non-Never
1915 if( (0 != rootDomain->user_spindown) && (0 != rootDomain->sleepSlider) )
0b4e3aa0
A
1916 rootDomain->setQuickSpinDownTimeout();
1917 }
1918
1919 break;
1920
1921 case kIOMessageDeviceHasPoweredOn:
1922
1923 // The display has powered on either because of UI activity or wake from sleep/doze
1924 deviceAlreadyPoweredOff = false;
1925 rootDomain->adjustPowerState();
1926
1927
1928 // cancel any pending idle sleep
55e303ae
A
1929 if(rootDomain->idleSleepPending)
1930 {
0b4e3aa0
A
1931 thread_call_cancel(rootDomain->extraSleepTimer);
1932 rootDomain->idleSleepPending = false;
1933 }
1934
1935 // Change the spindown value back to the user's selection from our accelerated setting
1936 if(0 != rootDomain->user_spindown)
1937 rootDomain->restoreUserSpinDownTimeout();
1938
1939 // Put on the policy maker's on clamp.
1940
1941 break;
1942
1943 default:
1944 break;
1945 }
1946 return kIOReturnUnsupported;
1947 }
1948
1949//*********************************************************************************
1950// displayWranglerPublished
1951//
1952// Receives a notification when the IODisplayWrangler is published.
1953// When it's published we install a power state change handler.
1954//
1955//*********************************************************************************
1956
5d5c5d0d
A
1957bool IOPMrootDomain::displayWranglerPublished(
1958 void * target,
1959 void * refCon,
1960 IOService * newService)
0b4e3aa0 1961{
5d5c5d0d
A
1962 IOPMrootDomain *rootDomain =
1963 OSDynamicCast(IOPMrootDomain, (IOService *)target);
0b4e3aa0
A
1964
1965 if(!rootDomain)
1966 return false;
1967
55e303ae
A
1968 rootDomain->wrangler = newService;
1969
1970 // we found the display wrangler, now install a handler
5d5c5d0d
A
1971 if( !rootDomain->wrangler->registerInterest( gIOGeneralInterest,
1972 &displayWranglerNotification, target, 0) )
1973 {
55e303ae
A
1974 return false;
1975 }
1976
1977 return true;
1c79356b
A
1978}
1979
5d5c5d0d 1980
483a1d10 1981//*********************************************************************************
5d5c5d0d 1982// batteryPublished
483a1d10 1983//
5d5c5d0d 1984// Notification on battery class IOPowerSource appearance
483a1d10 1985//
5d5c5d0d
A
1986//******************************************************************************
1987
1988bool IOPMrootDomain::batteryPublished(
1989 void * target,
1990 void * root_domain,
1991 IOService * resourceService )
1992{
1993 // rdar://2936060&4435589
91447636
A
1994 // All laptops have dimmable LCD displays
1995 // All laptops have batteries
1996 // So if this machine has a battery, publish the fact that the backlight
1997 // supports dimming.
1998 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
5d5c5d0d 1999
483a1d10
A
2000 return (true);
2001}
2002
2003
1c79356b 2004
0b4e3aa0
A
2005//*********************************************************************************
2006// adjustPowerState
2007//
2008// Some condition that affects our wake/sleep/doze decision has changed.
2009//
2010// If the sleep slider is in the off position, we cannot sleep or doze.
2011// If the enclosure is open, we cannot sleep or doze.
2012// If the system is still booting, we cannot sleep or doze.
2013//
2014// In those circumstances, we prevent sleep and doze by holding power on with
2015// changePowerStateToPriv(ON).
2016//
2017// If the above conditions do not exist, and also the sleep timer has expired, we
2018// allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
2019// changePowerStateToPriv(DOZE) depending on whether or not we already know the
2020// platform cannot sleep.
2021//
2022// In this case, sleep or doze will either occur immediately or at the next time
2023// that no children are holding the system out of idle sleep via the
2024// kIOPMPreventIdleSleep flag in their power state arrays.
2025//*********************************************************************************
2026
2027void IOPMrootDomain::adjustPowerState( void )
2028{
2029 if ( (sleepSlider == 0) ||
2030 ! allowSleep ||
2031 systemBooting ) {
2032 changePowerStateToPriv(ON_STATE);
55e303ae
A
2033 } else {
2034 if ( sleepASAP )
2035 {
0b4e3aa0 2036 sleepASAP = false;
55e303ae
A
2037 if ( sleepIsSupported )
2038 {
0b4e3aa0 2039 changePowerStateToPriv(SLEEP_STATE);
55e303ae 2040 } else {
0b4e3aa0
A
2041 changePowerStateToPriv(DOZE_STATE);
2042 }
2043 }
2044 }
2045}
1c79356b 2046
5d5c5d0d
A
2047/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2048
2049
2050
2051#undef super
2052#define super OSObject
2053OSDefineMetaClassAndStructors(PMSettingObject, OSObject)
2054
2055void PMSettingObject::setPMSetting(const OSSymbol *type, OSObject *obj)
2056{
2057 (*func)(target, type, obj, refcon);
2058}
2059
2060/*
2061 * Static constructor/initializer for PMSettingObject
2062 */
2063PMSettingObject *PMSettingObject::pmSettingObject(
2064 IOPMrootDomain *parent_arg,
2065 IOPMSettingControllerCallback handler_arg,
2066 OSObject *target_arg,
2067 uintptr_t refcon_arg,
2068 uint32_t supportedPowerSources,
2069 const OSSymbol * settings[])
2070{
2071 uint32_t objCount = 0;
2072 PMSettingObject *pmso;
2073
2074 if( !parent_arg || !handler_arg || !settings ) return NULL;
2075
2076 // count OSSymbol entries in NULL terminated settings array
2077 while( settings[objCount] ) {
2078 objCount++;
2079 }
2080 if(0 == objCount) return NULL;
2081
2082 pmso = new PMSettingObject;
2083 if(!pmso || !pmso->init()) return NULL;
2084
2085 pmso->parent = parent_arg;
2086 pmso->func = handler_arg;
2087 pmso->target = target_arg;
2088 pmso->refcon = refcon_arg;
2089 pmso->releaseAtCount = objCount + 1; // release when it has count+1 retains
2090
2091 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount);
2092 if(pmso->publishedFeatureID) {
2093 for(unsigned int i=0; i<objCount; i++) {
2094 // Since there is now at least one listener to this setting, publish
2095 // PM root domain support for it.
2096 parent_arg->publishFeature( settings[i]->getCStringNoCopy(),
2097 supportedPowerSources, &pmso->publishedFeatureID[i] );
2098 }
2099 }
2100
2101 return pmso;
2102}
2103
2104void PMSettingObject::free(void)
2105{
2106 OSCollectionIterator *settings_iter;
2107 OSSymbol *sym;
2108 OSArray *arr;
2109 int arr_idx;
2110 int i;
2111 int objCount = releaseAtCount - 1;
2112
2113 if(publishedFeatureID) {
2114 for(i=0; i<objCount; i++) {
2115 if(0 != publishedFeatureID[i]) {
2116 parent->removePublishedFeature( publishedFeatureID[i] );
2117 }
2118 }
2119
2120 IOFree(publishedFeatureID, sizeof(uint32_t) * objCount);
2121 }
2122
2123 IORecursiveLockLock(parent->settingsCtrlLock);
2124
2125 // Search each PM settings array in the kernel.
2126 settings_iter = OSCollectionIterator::withCollection(parent->settingsCallbacks);
2127 if(settings_iter)
2128 {
2129 while(( sym = OSDynamicCast(OSSymbol, settings_iter->getNextObject()) ))
2130 {
2131 arr = (OSArray *)parent->settingsCallbacks->getObject(sym);
2132 arr_idx = arr->getNextIndexOfObject(this, 0);
2133 if(-1 != arr_idx) {
2134 // 'this' was found in the array; remove it
2135 arr->removeObject(arr_idx);
2136 }
2137 }
2138
2139 settings_iter->release();
2140 }
2141
2142 IORecursiveLockUnlock(parent->settingsCtrlLock);
2143
2144 super::free();
2145}
2146
2147void PMSettingObject::taggedRelease(const void *tag, const int when) const
2148{
2149 // We have n+1 retains - 1 per array that this PMSettingObject is a member
2150 // of, and 1 retain to ourself. When we get a release with n+1 retains
2151 // remaining, we go ahead and free ourselves, cleaning up array pointers
2152 // in free();
2153
2154 super::taggedRelease(tag, releaseAtCount);
2155}
2156
2157
1c79356b
A
2158
2159/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2160
2161#undef super
2162#define super IOService
2163
2164OSDefineMetaClassAndStructors(IORootParent, IOService)
2165
0b4e3aa0
A
2166// This array exactly parallels the state array for the root domain.
2167// Power state changes initiated by a device can be vetoed by a client of the device, and
2168// power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
2169// so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
2170// its parent to make the change. That is the reason for this complexity.
1c79356b 2171
0b4e3aa0 2172static IOPMPowerState patriarchPowerStates[number_of_power_states] = {
1c79356b 2173 {1,0,0,0,0,0,0,0,0,0,0,0}, // off
0b4e3aa0 2174 {1,0,RESTART_POWER,0,0,0,0,0,0,0,0,0}, // reset
1c79356b 2175 {1,0,SLEEP_POWER,0,0,0,0,0,0,0,0,0}, // sleep
0b4e3aa0 2176 {1,0,DOZE_POWER,0,0,0,0,0,0,0,0,0}, // doze
1c79356b
A
2177 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0} // running
2178};
2179
1c79356b
A
2180bool IORootParent::start ( IOService * nub )
2181{
0b4e3aa0 2182 mostRecentChange = ON_STATE;
1c79356b
A
2183 super::start(nub);
2184 PMinit();
0b4e3aa0 2185 registerPowerDriver(this,patriarchPowerStates,number_of_power_states);
1c79356b
A
2186 powerOverrideOnPriv();
2187 return true;
2188}
2189
2190
2191void IORootParent::shutDownSystem ( void )
2192{
0b4e3aa0
A
2193 mostRecentChange = OFF_STATE;
2194 changePowerStateToPriv(OFF_STATE);
2195}
2196
2197
2198void IORootParent::restartSystem ( void )
2199{
2200 mostRecentChange = RESTART_STATE;
2201 changePowerStateToPriv(RESTART_STATE);
1c79356b
A
2202}
2203
2204
2205void IORootParent::sleepSystem ( void )
2206{
0b4e3aa0
A
2207 mostRecentChange = SLEEP_STATE;
2208 changePowerStateToPriv(SLEEP_STATE);
2209}
2210
2211
2212void IORootParent::dozeSystem ( void )
2213{
2214 mostRecentChange = DOZE_STATE;
2215 changePowerStateToPriv(DOZE_STATE);
2216}
2217
2218// Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
2219// This brings the parent to doze, which allows the root to step up from sleep to doze.
2220
2221// In idle sleep, do nothing because the parent is still on and the root can freely change state.
2222
2223void IORootParent::sleepToDoze ( void )
2224{
2225 if ( mostRecentChange == SLEEP_STATE ) {
2226 changePowerStateToPriv(DOZE_STATE);
2227 }
1c79356b
A
2228}
2229
2230
2231void IORootParent::wakeSystem ( void )
2232{
0b4e3aa0
A
2233 mostRecentChange = ON_STATE;
2234 changePowerStateToPriv(ON_STATE);
1c79356b
A
2235}
2236
5d5c5d0d
A
2237IOReturn IORootParent::changePowerStateToPriv ( unsigned long ordinal )
2238{
2239 IOReturn ret;
2240
2241 if( SLEEP_STATE == ordinal && sleepSupportedPEFunction )
2242 {
2243
2244 // Determine if the machine supports sleep, or must doze.
2245 ret = getPlatform()->callPlatformFunction(
2246 sleepSupportedPEFunction, false,
2247 NULL, NULL, NULL, NULL);
2248
2249 // If the machine only supports doze, the callPlatformFunction call
2250 // boils down toIOPMrootDomain::setSleepSupported(kPCICantSleep),
2251 // otherwise nothing.
2252 }
2253
2254 return super::changePowerStateToPriv(ordinal);
2255}
2256