]> git.saurik.com Git - apple/xnu.git/blame_incremental - iokit/Kernel/IOPMrootDomain.cpp
xnu-792.13.8.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
... / ...
CommitLineData
1/*
2 * Copyright (c) 1998-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
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@
29 */
30#include <IOKit/IOWorkLoop.h>
31#include <IOKit/IOCommandGate.h>
32#include <IOKit/IOTimerEventSource.h>
33#include <IOKit/IOPlatformExpert.h>
34#include <IOKit/IOKitDebug.h>
35#include <IOKit/IOTimeStamp.h>
36#include <IOKit/pwr_mgt/RootDomain.h>
37#include <IOKit/pwr_mgt/IOPMPrivate.h>
38#include <IOKit/IODeviceTreeSupport.h>
39#include <IOKit/IOMessage.h>
40#include <IOKit/IOReturn.h>
41#include "RootDomainUserClient.h"
42#include "IOKit/pwr_mgt/IOPowerConnection.h"
43#include "IOPMPowerStateQueue.h"
44#include <IOKit/IOCatalogue.h>
45#include <IOKit/IOHibernatePrivate.h>
46#include "IOPMWorkArbiter.h"
47
48#ifdef __ppc__
49#include <ppc/pms.h>
50#endif
51
52extern "C" {
53IOReturn OSMetaClassSystemSleepOrWake( UInt32 );
54}
55
56extern const IORegistryPlane * gIOPowerPlane;
57
58IOReturn broadcast_aggressiveness ( OSObject *, void *, void *, void *, void * );
59static void sleepTimerExpired(thread_call_param_t);
60static void wakeupClamshellTimerExpired ( thread_call_param_t us);
61
62// "IOPMSetSleepSupported" callPlatformFunction name
63static const OSSymbol *sleepSupportedPEFunction = NULL;
64
65#define kIOSleepSupportedKey "IOSleepSupported"
66
67#define kRD_AllPowerSources (kIOPMSupportedOnAC \
68 | kIOPMSupportedOnBatt \
69 | kIOPMSupportedOnUPS)
70
71#define number_of_power_states 5
72#define OFF_STATE 0
73#define RESTART_STATE 1
74#define SLEEP_STATE 2
75#define DOZE_STATE 3
76#define ON_STATE 4
77
78#define ON_POWER kIOPMPowerOn
79#define RESTART_POWER kIOPMRestart
80#define SLEEP_POWER kIOPMAuxPowerOn
81#define DOZE_POWER kIOPMDoze
82
83#define kLocalEvalClamshellCommand (1 << 15)
84
85static IOPMPowerState ourPowerStates[number_of_power_states] = {
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},
96};
97
98static IOPMrootDomain * gRootDomain;
99static UInt32 gSleepOrShutdownPending = 0;
100
101
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
129#define super IOService
130OSDefineMetaClassAndStructors(IOPMrootDomain,IOService)
131
132extern "C"
133{
134 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
135 {
136 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
137 }
138
139 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
140 {
141 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
142 }
143
144 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
145 {
146 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
147 }
148
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 {
166 IOCatalogue::disableExternalLinker();
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);
175}
176
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*/
217
218// **********************************************************************************
219
220IOPMrootDomain * IOPMrootDomain::construct( void )
221{
222 IOPMrootDomain *root;
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{
235 IOService *rootDomain = (IOService *) p0;
236 unsigned long pmRef = (unsigned long) p1;
237
238 IOHibernateSystemSleep();
239 sync_internal();
240 rootDomain->allowPowerChange(pmRef);
241}
242
243// **********************************************************************************
244IOPMWorkArbiter *IOPMrootDomain::getPMArbiter(void)
245{
246 return pmArbiter;
247}
248
249
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// **********************************************************************************
256
257#define kRootDomainSettingsCount 12
258
259bool IOPMrootDomain::start ( IOService * nub )
260{
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
279
280 pmPowerStateQueue = 0;
281
282 _reserved = (ExpansionData *)IOMalloc(sizeof(ExpansionData));
283 if(!_reserved) return false;
284
285 super::start(nub);
286
287 gRootDomain = this;
288
289 PMinit();
290
291 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
292 canSleep = true;
293 setProperty(kIOSleepSupportedKey,true);
294
295 allowSleep = true;
296 sleepIsSupported = true;
297 systemBooting = true;
298 sleepSlider = 0;
299 idleSleepPending = false;
300 wrangler = NULL;
301 sleepASAP = false;
302 clamshellIsClosed = false;
303 clamshellExists = false;
304 ignoringClamshell = true;
305 ignoringClamshellDuringWakeup = false;
306 acAdaptorConnect = true;
307
308 tmpDict = OSDictionary::withCapacity(1);
309 setProperty(kRootDomainSupportedFeatures, tmpDict);
310 tmpDict->release();
311
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
323 pm_vars->PMworkloop = IOWorkLoop::workLoop();
324 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(this);
325 pm_vars->PMworkloop->addEventSource(pmPowerStateQueue);
326
327 /* Initialize PM arbiter */
328 pmArbiter = IOPMWorkArbiter::pmWorkArbiter(this);
329 arbiterWorkLoop = IOWorkLoop::workLoop();
330 arbiterWorkLoop->addEventSource(pmArbiter);
331
332 featuresDictLock = IOLockAlloc();
333 settingsCtrlLock = IORecursiveLockAlloc();
334
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);
344
345 // create our parent
346 patriarch = new IORootParent;
347 patriarch->init();
348 patriarch->attach(this);
349 patriarch->start(this);
350 patriarch->youAreRoot();
351 patriarch->wakeSystem();
352 patriarch->addPowerChild(this);
353
354 registerPowerDriver(this,ourPowerStates,number_of_power_states);
355
356 setPMRootDomain(this);
357 // set a clamp until we sleep
358 changePowerStateToPriv(ON_STATE);
359
360 // install power change handler
361 registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
362
363 // Register for a notification when IODisplayWrangler is published
364 _displayWranglerNotifier = addNotification(
365 gIOPublishNotification, serviceMatching("IODisplayWrangler"),
366 &displayWranglerPublished, this, 0);
367
368 // Battery location published - ApplePMU support only
369 _batteryPublishNotifier = addNotification(
370 gIOPublishNotification, serviceMatching("IOPMPowerSource"),
371 &batteryPublished, this, this);
372
373
374 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
375 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
376 ucClassName->release();
377
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() )
383 {
384 // There's at least one battery on the system, so we publish
385 // 'DisplayDims' support for the LCD.
386 publishFeature("DisplayDims");
387 }
388 if(psIterator) {
389 psIterator->release();
390 }
391
392 IOHibernateSystemInit(this);
393
394 registerService(); // let clients find us
395
396 return true;
397}
398
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{
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);
428
429 if(!dict)
430 {
431 return_value = kIOReturnBadArgument;
432 goto exit;
433 }
434
435 if( systemBooting
436 && boot_complete_string
437 && dict->getObject(boot_complete_string))
438 {
439 systemBooting = false;
440 adjustPowerState();
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 }
448 }
449
450 if( stall_halt_string
451 && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) )
452 {
453 setProperty(stall_halt_string, b);
454 }
455
456 if ( hibernatemode_string
457 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string))))
458 {
459 setProperty(hibernatemode_string, n);
460 }
461 if ( hibernatefreeratio_string
462 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string))))
463 {
464 setProperty(hibernatefreeratio_string, n);
465 }
466 if ( hibernatefreetime_string
467 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string))))
468 {
469 setProperty(hibernatefreetime_string, n);
470 }
471 if ( hibernatefile_string
472 && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string))))
473 {
474 setProperty(hibernatefile_string, str);
475 }
476
477 // Relay our allowed PM settings onto our registered PM clients
478 for(i = 0; i < allowedPMSettings->getCount(); i++) {
479
480 type = (OSSymbol *)allowedPMSettings->getObject(i);
481 if(!type) continue;
482
483 obj = dict->getObject(type);
484 if(!obj) continue;
485
486 return_value = setPMSetting(type, obj);
487
488 if(kIOReturnSuccess != return_value) goto exit;
489 }
490
491 exit:
492 if(boot_complete_string) boot_complete_string->release();
493 if(stall_halt_string) stall_halt_string->release();
494 return return_value;
495}
496
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
511// **********************************************************************************
512// command_received
513//
514// No longer used
515// **********************************************************************************
516void IOPMrootDomain::command_received ( void * w, void * x, void * y, void * z )
517{
518 super::command_received(w,x,y,z);
519}
520
521
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}
531
532
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;
553 // idle sleep is now enabled, maybe sleep now
554 adjustPowerState();
555 }
556 sleepSlider = value;
557 if ( sleepSlider == 0 ) {
558 // idle sleep is now disabled
559 adjustPowerState();
560 // make sure we're powered
561 patriarch->wakeSystem();
562 }
563 }
564 if ( sleepSlider > longestNonSleepSlider ) {
565 extraSleepDelay = sleepSlider - longestNonSleepSlider ;
566 }
567 else {
568 extraSleepDelay = 0;
569 }
570}
571
572
573// **********************************************************************************
574// sleepTimerExpired
575//
576// **********************************************************************************
577static void sleepTimerExpired ( thread_call_param_t us)
578{
579 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
580 }
581
582
583static void wakeupClamshellTimerExpired ( thread_call_param_t us)
584{
585 ((IOPMrootDomain *)us)->stopIgnoringClamshellEventsDuringWakeup();
586}
587
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
606void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void)
607{
608 // Allow clamshell-induced sleep now
609 ignoringClamshellDuringWakeup = false;
610
611 // Re-send clamshell event, in case it causes a sleep
612 if(clamshellIsClosed)
613 this->receivePowerNotification( kLocalEvalClamshellCommand );
614}
615
616//*********************************************************************************
617// setAggressiveness
618//
619// Some aggressiveness factor has changed. We broadcast it to the hierarchy while on
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
625static int pmsallsetup = 0;
626
627IOReturn IOPMrootDomain::setAggressiveness ( unsigned long type, unsigned long newLevel )
628{
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
643 if ( pm_vars->PMcommandGate ) {
644 pm_vars->PMcommandGate->runAction(broadcast_aggressiveness,(void *)type,(void *)newLevel);
645 }
646
647 return kIOReturnSuccess;
648}
649
650
651// **********************************************************************************
652// sleepSystem
653//
654// **********************************************************************************
655IOReturn IOPMrootDomain::sleepSystem ( void )
656{
657 if ( !systemBooting && allowSleep && sleepIsSupported ) {
658 patriarch->sleepSystem();
659
660 return kIOReturnSuccess;
661 }
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{
676 //patriarch->shutDownSystem();
677 return kIOReturnUnsupported;
678}
679
680
681// **********************************************************************************
682// restartSystem
683//
684// **********************************************************************************
685IOReturn IOPMrootDomain::restartSystem ( void )
686{
687 //patriarch->restartSystem();
688 return kIOReturnUnsupported;
689}
690
691
692// **********************************************************************************
693// powerChangeDone
694//
695// This overrides powerChangeDone in IOService.
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:
712 if ( canSleep && sleepIsSupported )
713 {
714 // re-enable this timer for next sleep
715 idleSleepPending = false;
716
717 IOLog("System %sSleep\n", gIOHibernateState ? "Safe" : "");
718
719 IOHibernateSystemHasSlept();
720
721 pm_vars->thePlatform->sleepKernel();
722
723 // The CPU(s) are off at this point. When they're awakened by CPU interrupt,
724 // code will resume execution here.
725
726 // Now we're waking...
727 IOHibernateSystemWake();
728
729 // stay awake for at least 30 seconds
730 clock_interval_to_deadline(30, kSecondScale, &deadline);
731 thread_call_enter_delayed(extraSleepTimer, deadline);
732 // this gets turned off when we sleep again
733 idleSleepPending = true;
734
735 // Ignore closed clamshell during wakeup and for a few seconds
736 // after wakeup is complete
737 ignoringClamshellDuringWakeup = true;
738
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();
747
748 // early stage wake notification
749 tellClients(kIOMessageSystemWillPowerOn);
750
751 // tell the tree we're waking
752 IOLog("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
753 systemWake();
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);
761 if(clamshellWakeupIgnore) {
762 thread_call_enter_delayed(clamshellWakeupIgnore, deadline);
763 }
764 } else ignoringClamshellDuringWakeup = false;
765
766 // Find out what woke us
767 propertyPtr = OSDynamicCast(OSNumber,getProperty("WakeEvent"));
768 if ( propertyPtr ) {
769 theProperty = propertyPtr->unsigned16BitValue();
770 IOLog("Wake event %04x\n",theProperty);
771 if ( (theProperty & 0x0008) || //lid
772 (theProperty & 0x0800) || // front panel button
773 (theProperty & 0x0020) || // external keyboard
774 (theProperty & 0x0001) ) { // internal keyboard
775 // We've identified the wakeup event as UI driven
776 reportUserInput();
777 }
778 } else {
779 // Since we can't identify the wakeup event, treat it as UI activity
780 reportUserInput();
781 }
782
783 // Wake for thirty seconds
784 changePowerStateToPriv(ON_STATE);
785 powerOverrideOffPriv();
786 } else {
787 // allow us to step up a power state
788 patriarch->sleepToDoze();
789 // and do it
790 changePowerStateToPriv(DOZE_STATE);
791 }
792 break;
793
794 case DOZE_STATE:
795 if ( previousState != DOZE_STATE )
796 {
797 IOLog("System Doze\n");
798 }
799 // re-enable this timer for next sleep
800 idleSleepPending = false;
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.
823// **********************************************************************************
824void IOPMrootDomain::wakeFromDoze( void )
825{
826 if ( pm_vars->myCurrentState == DOZE_STATE )
827 {
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
833 powerOverrideOffPriv();
834
835 // early wake notification
836 tellClients(kIOMessageSystemWillPowerOn);
837
838 // allow us to wake if children so desire
839 patriarch->wakeSystem();
840 }
841}
842
843
844// *****************************************************************************
845// publishFeature
846//
847// Adds a new feature to the supported features dictionary
848//
849//
850// *****************************************************************************
851void IOPMrootDomain::publishFeature( const char * feature )
852{
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
893 if(featuresDictLock) IOLockLock(featuresDictLock);
894
895 OSDictionary *features =
896 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
897
898 // Create new features dict if necessary
899 if ( features && OSDynamicCast(OSDictionary, features)) {
900 features = OSDictionary::withDictionary(features);
901 } else {
902 features = OSDictionary::withCapacity(1);
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();
941
942 setProperty(kRootDomainSupportedFeatures, features);
943
944 features->release();
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;
1072}
1073
1074
1075// **********************************************************************************
1076// unIdleDevice
1077//
1078// Enqueues unidle event to be performed later in a serialized context.
1079//
1080// **********************************************************************************
1081void IOPMrootDomain::unIdleDevice( IOService *theDevice, unsigned long theState )
1082{
1083 if(pmPowerStateQueue)
1084 pmPowerStateQueue->unIdleOccurred(theDevice, theState);
1085}
1086
1087// **********************************************************************************
1088// announcePowerSourceChange
1089//
1090// Notifies "interested parties" that the batteries have changed state
1091//
1092// **********************************************************************************
1093void IOPMrootDomain::announcePowerSourceChange( void )
1094{
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.
1100
1101 if(_batteryRegEntry)
1102 {
1103 OSArray *batt_info;
1104 batt_info = (OSArray *) _batteryRegEntry->getProperty(kIOBatteryInfoKey);
1105 if(batt_info)
1106 setProperty(kIOBatteryInfoKey, batt_info);
1107 }
1108
1109}
1110
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)
1122{
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);
1131
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);
1144 return kIOReturnSuccess;
1145}
1146
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;
1158
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)
1173//
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}
1188
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)
1215{
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)
1224 {
1225 return kIOReturnBadArgument;
1226 }
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++)
1240 {
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);
1251 }
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)
1262 {
1263 // Error return case
1264 if(pmso) pmso->release();
1265 if(handle) *handle = NULL;
1266 }
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)
1323 {
1324 eval_clamshell = true;
1325 }
1326
1327 /*
1328 * Overtemp
1329 */
1330 if (msg & kIOPMOverTemp)
1331 {
1332 IOLog("PowerManagement emergency overtemp signal. Going to sleep!");
1333 (void) sleepSystem ();
1334 }
1335
1336 /*
1337 * PMU Processor Speed Change
1338 */
1339 if (msg & kIOPMProcessorSpeedChange)
1340 {
1341 IOService *pmu = waitForService(serviceMatching("ApplePMU"));
1342 pmu->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
1343 pm_vars->thePlatform->sleepKernel();
1344 pmu->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
1345 }
1346
1347 /*
1348 * Sleep Now!
1349 */
1350 if (msg & kIOPMSleepNow)
1351 {
1352 (void) sleepSystem ();
1353 }
1354
1355 /*
1356 * Power Emergency
1357 */
1358 if (msg & kIOPMPowerEmergency)
1359 {
1360 (void) sleepSystem ();
1361 }
1362
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)
1382 {
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 )
1427 {
1428 eval_clamshell = true;
1429 }
1430
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;
1446 }
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();
1463 }
1464
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 */
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();
1489 }
1490 else {
1491 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
1492 // Check that power button sleep is enabled
1493 if( pbs ) {
1494 if( kOSBooleanTrue != getProperty(pbs))
1495 sleepSystem();
1496 }
1497 }
1498 }
1499
1500 /*
1501 * Allow Sleep
1502 *
1503 */
1504 if ( (msg & kIOPMAllowSleep) && !allowSleep )
1505 {
1506 allowSleep = true;
1507 adjustPowerState();
1508 }
1509
1510 /*
1511 * Prevent Sleep
1512 *
1513 */
1514 if (msg & kIOPMPreventSleep) {
1515 allowSleep = false;
1516 // are we dozing?
1517 if ( pm_vars->myCurrentState == DOZE_STATE ) {
1518 // yes, tell the tree we're waking
1519 systemWake();
1520 adjustPowerState();
1521 // wake the Display Wrangler
1522 reportUserInput();
1523 } else {
1524 adjustPowerState();
1525 // make sure we have power to clamp
1526 patriarch->wakeSystem();
1527 }
1528 }
1529
1530 return 0;
1531}
1532
1533
1534//*********************************************************************************
1535// sleepSupported
1536//
1537//*********************************************************************************
1538
1539void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
1540{
1541 if ( flags & kPCICantSleep )
1542 {
1543 canSleep = false;
1544 } else {
1545 canSleep = true;
1546 platformSleepSupport = flags;
1547 }
1548
1549 setProperty(kIOSleepSupportedKey, canSleep);
1550
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{
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) ) {
1575 editedDesire = 0;
1576 }
1577
1578
1579 IOLockLock(pm_vars->childLock);
1580
1581 // recompute sleepIsSupported and see if all children are asleep
1582 iter = getChildIterator(gIOPowerPlane);
1583 sleepIsSupported = true;
1584 if ( iter )
1585 {
1586 while ( (next = iter->getNextObject()) )
1587 {
1588 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
1589 {
1590 if ( connection == whichChild )
1591 {
1592 powerRequestFlag += editedDesire;
1593 if ( desiredState & kIOPMPreventSystemSleep )
1594 {
1595 sleepIsSupported = false;
1596 }
1597 } else {
1598 powerRequestFlag += connection->getDesiredDomainState();
1599 if ( connection->getPreventSystemSleepFlag() )
1600 {
1601 sleepIsSupported = false;
1602 }
1603 }
1604 }
1605 }
1606 iter->release();
1607 }
1608
1609 if ( (extraSleepDelay == 0) && (powerRequestFlag == 0) )
1610 {
1611 sleepASAP = true;
1612 }
1613
1614 // this may put the system to sleep
1615 adjustPowerState();
1616
1617 IOLockUnlock(pm_vars->childLock);
1618
1619 editedDesire |= desiredState & kIOPMPreventSystemSleep;
1620
1621 return super::requestPowerDomainState(editedDesire,whichChild,specification);
1622}
1623
1624
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{
1645 switch ( stateNum ) {
1646 case DOZE_STATE:
1647 case SLEEP_STATE:
1648
1649 // Direct callout into OSMetaClass so it can disable kmod unloads
1650 // during sleep/wake to prevent deadlocks.
1651 OSMetaClassSystemSleepOrWake( kIOMessageSystemWillSleep );
1652
1653 return super::tellClientsWithResponse(kIOMessageSystemWillSleep);
1654 case RESTART_STATE:
1655 // Unsupported shutdown ordering hack on RESTART only
1656 // For Bluetooth and USB (4368327)
1657 super::tellClients(iokit_common_msg(0x759));
1658
1659 return super::tellClientsWithResponse(kIOMessageSystemWillRestart);
1660 case OFF_STATE:
1661 // Unsupported shutdown ordering hack on SHUTDOWN only
1662 // For Bluetooth and USB (4554440)
1663 super::tellClients(iokit_common_msg(0x749));
1664
1665 return super::tellClientsWithResponse(kIOMessageSystemWillPowerOff);
1666 }
1667 // this shouldn't execute
1668 return super::tellChangeDown(stateNum);
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.
1677//
1678// This must be idle sleep since we don't ask apps during any other power change.
1679//*********************************************************************************
1680
1681bool IOPMrootDomain::askChangeDown ( unsigned long )
1682{
1683 return super::tellClientsWithResponse(kIOMessageCanSystemSleep);
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.
1695//
1696// This must be a vetoed idle sleep, since no other power change can be vetoed.
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
1714void IOPMrootDomain::tellChangeUp ( unsigned long stateNum)
1715{
1716 if ( stateNum == ON_STATE )
1717 {
1718 // Direct callout into OSMetaClass so it can disable kmod unloads
1719 // during sleep/wake to prevent deadlocks.
1720 OSMetaClassSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
1721
1722 IOHibernateSystemPostWake();
1723 return tellClients(kIOMessageSystemHasPoweredOn);
1724 }
1725}
1726
1727//*********************************************************************************
1728// reportUserInput
1729//
1730//*********************************************************************************
1731
1732void IOPMrootDomain::reportUserInput ( void )
1733{
1734 OSIterator * iter;
1735
1736 if(!wrangler)
1737 {
1738 iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
1739 if(iter)
1740 {
1741 wrangler = (IOService *) iter->getNextObject();
1742 iter->release();
1743 }
1744 }
1745
1746 if(wrangler)
1747 wrangler->activityTickle(0,0);
1748}
1749
1750//*********************************************************************************
1751// setQuickSpinDownTimeout
1752//
1753//*********************************************************************************
1754
1755void IOPMrootDomain::setQuickSpinDownTimeout ( void )
1756{
1757 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)1);
1758}
1759
1760//*********************************************************************************
1761// restoreUserSpinDownTimeout
1762//
1763//*********************************************************************************
1764
1765void IOPMrootDomain::restoreUserSpinDownTimeout ( void )
1766{
1767 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)user_spindown);
1768}
1769
1770//*********************************************************************************
1771// changePowerStateTo & changePowerStateToPriv
1772//
1773// Override of these methods for logging purposes.
1774//*********************************************************************************
1775
1776IOReturn IOPMrootDomain::changePowerStateTo ( unsigned long ordinal )
1777{
1778 return super::changePowerStateTo(ordinal);
1779}
1780
1781IOReturn IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal )
1782{
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
1798 return super::changePowerStateToPriv(ordinal);
1799}
1800
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{
1816 IOReturn ret;
1817 IOPowerStateChangeNotification *params = (IOPowerStateChangeNotification *) messageArgument;
1818 IOPMrootDomain *rootDomain = OSDynamicCast(IOPMrootDomain, service);
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)
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;
1837 if (gIOHibernateState)
1838 params->returnValue += gIOHibernateFreeTime * 1000; //add in time we could spend freeing pages
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;
1846 clock_interval_to_deadline( 30, kSecondScale, &deadline );
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;
1855
1856 case kIOMessageSystemWillPowerOff:
1857 case kIOMessageSystemWillRestart:
1858 ret = kIOReturnUnsupported;
1859 break;
1860
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//*********************************************************************************
1883
1884IOReturn IOPMrootDomain::displayWranglerNotification( void * target, void * refCon,
1885 UInt32 messageType, IOService * service,
1886 void * messageArgument, vm_size_t argSize )
1887{
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
1906 if( rootDomain->extraSleepDelay )
1907 {
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;
1912 } else {
1913 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
1914 // and if system sleep is non-Never
1915 if( (0 != rootDomain->user_spindown) && (0 != rootDomain->sleepSlider) )
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
1929 if(rootDomain->idleSleepPending)
1930 {
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
1957bool IOPMrootDomain::displayWranglerPublished(
1958 void * target,
1959 void * refCon,
1960 IOService * newService)
1961{
1962 IOPMrootDomain *rootDomain =
1963 OSDynamicCast(IOPMrootDomain, (IOService *)target);
1964
1965 if(!rootDomain)
1966 return false;
1967
1968 rootDomain->wrangler = newService;
1969
1970 // we found the display wrangler, now install a handler
1971 if( !rootDomain->wrangler->registerInterest( gIOGeneralInterest,
1972 &displayWranglerNotification, target, 0) )
1973 {
1974 return false;
1975 }
1976
1977 return true;
1978}
1979
1980
1981//*********************************************************************************
1982// batteryPublished
1983//
1984// Notification on battery class IOPowerSource appearance
1985//
1986//******************************************************************************
1987
1988bool IOPMrootDomain::batteryPublished(
1989 void * target,
1990 void * root_domain,
1991 IOService * resourceService )
1992{
1993 // rdar://2936060&4435589
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");
1999
2000 return (true);
2001}
2002
2003
2004
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);
2033 } else {
2034 if ( sleepASAP )
2035 {
2036 sleepASAP = false;
2037 if ( sleepIsSupported )
2038 {
2039 changePowerStateToPriv(SLEEP_STATE);
2040 } else {
2041 changePowerStateToPriv(DOZE_STATE);
2042 }
2043 }
2044 }
2045}
2046
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
2158
2159/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2160
2161#undef super
2162#define super IOService
2163
2164OSDefineMetaClassAndStructors(IORootParent, IOService)
2165
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.
2171
2172static IOPMPowerState patriarchPowerStates[number_of_power_states] = {
2173 {1,0,0,0,0,0,0,0,0,0,0,0}, // off
2174 {1,0,RESTART_POWER,0,0,0,0,0,0,0,0,0}, // reset
2175 {1,0,SLEEP_POWER,0,0,0,0,0,0,0,0,0}, // sleep
2176 {1,0,DOZE_POWER,0,0,0,0,0,0,0,0,0}, // doze
2177 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0} // running
2178};
2179
2180bool IORootParent::start ( IOService * nub )
2181{
2182 mostRecentChange = ON_STATE;
2183 super::start(nub);
2184 PMinit();
2185 registerPowerDriver(this,patriarchPowerStates,number_of_power_states);
2186 powerOverrideOnPriv();
2187 return true;
2188}
2189
2190
2191void IORootParent::shutDownSystem ( void )
2192{
2193 mostRecentChange = OFF_STATE;
2194 changePowerStateToPriv(OFF_STATE);
2195}
2196
2197
2198void IORootParent::restartSystem ( void )
2199{
2200 mostRecentChange = RESTART_STATE;
2201 changePowerStateToPriv(RESTART_STATE);
2202}
2203
2204
2205void IORootParent::sleepSystem ( void )
2206{
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 }
2228}
2229
2230
2231void IORootParent::wakeSystem ( void )
2232{
2233 mostRecentChange = ON_STATE;
2234 changePowerStateToPriv(ON_STATE);
2235}
2236
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