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