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