]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPMrootDomain.cpp
17132892c39c93c3a872fbb487d08975e95faa67
[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 * 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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 #include <IOKit/IOWorkLoop.h>
24 #include <IOKit/IOCommandGate.h>
25 #include <IOKit/IOTimerEventSource.h>
26 #include <IOKit/IOPlatformExpert.h>
27 #include <IOKit/IOKitDebug.h>
28 #include <IOKit/IOTimeStamp.h>
29 #include <IOKit/pwr_mgt/RootDomain.h>
30 #include <IOKit/pwr_mgt/IOPMPrivate.h>
31 #include <IOKit/IODeviceTreeSupport.h>
32 #include <IOKit/IOMessage.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" void kprintf(const char *, ...);
44
45 extern const IORegistryPlane * gIOPowerPlane;
46
47 IOReturn broadcast_aggressiveness ( OSObject *, void *, void *, void *, void * );
48 static void sleepTimerExpired(thread_call_param_t);
49 static void wakeupClamshellTimerExpired ( thread_call_param_t us);
50
51
52 #define number_of_power_states 5
53 #define OFF_STATE 0
54 #define RESTART_STATE 1
55 #define SLEEP_STATE 2
56 #define DOZE_STATE 3
57 #define ON_STATE 4
58
59 #define ON_POWER kIOPMPowerOn
60 #define RESTART_POWER kIOPMRestart
61 #define SLEEP_POWER kIOPMAuxPowerOn
62 #define DOZE_POWER kIOPMDoze
63
64 static IOPMPowerState ourPowerStates[number_of_power_states] = {
65 {1,0, 0, 0,0,0,0,0,0,0,0,0}, // state 0, off
66 {1,kIOPMRestartCapability, kIOPMRestart, RESTART_POWER,0,0,0,0,0,0,0,0}, // state 1, restart
67 {1,kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER,0,0,0,0,0,0,0,0}, // state 2, sleep
68 {1,kIOPMDoze, kIOPMDoze, DOZE_POWER,0,0,0,0,0,0,0,0}, // state 3, doze
69 {1,kIOPMPowerOn, kIOPMPowerOn, ON_POWER,0,0,0,0,0,0,0,0}, // state 4, on
70 };
71
72 // RESERVED IOPMrootDomain class variables
73 #define diskSyncCalloutEntry _reserved->diskSyncCalloutEntry
74 #define _settingController _reserved->_settingController
75 #define _batteryLocationNotifier _reserved->_batteryLocationNotifier
76 #define _displayWranglerNotifier _reserved->_displayWranglerNotifier
77
78
79 static IOPMrootDomain * gRootDomain;
80 static UInt32 gSleepOrShutdownPending = 0;
81
82
83 #define super IOService
84 OSDefineMetaClassAndStructors(IOPMrootDomain,IOService)
85
86 extern "C"
87 {
88 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
89 {
90 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
91 }
92
93 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
94 {
95 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
96 }
97
98 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
99 {
100 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
101 }
102
103 IOReturn vetoSleepWakeNotification(void * PMrefcon)
104 {
105 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
106 }
107
108 IOReturn rootDomainRestart ( void )
109 {
110 return gRootDomain->restartSystem();
111 }
112
113 IOReturn rootDomainShutdown ( void )
114 {
115 return gRootDomain->shutdownSystem();
116 }
117
118 void IOSystemShutdownNotification ( void )
119 {
120 IOCatalogue::disableExternalLinker();
121 for ( int i = 0; i < 100; i++ )
122 {
123 if ( OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) ) break;
124 IOSleep( 100 );
125 }
126 }
127
128 int sync_internal(void);
129 }
130
131 /*
132 A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain
133 children it has, but within the constraint of the power state provided by its parent. The driver expresses its desire by
134 calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children
135 express their desires by calling requestPowerDomainState().
136
137 The Root Power Domain owns the policy for idle and demand sleep and doze for the system. It is a power-managed IOService just
138 like the others in the system. It implements several power states which correspond to what we see as Sleep, Doze, etc.
139
140 The sleep/doze policy is as follows:
141 Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards.
142 Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero.
143 The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep.
144
145 These three conditions are enforced using the "driver clamp" by calling changePowerStateTo(). For example, if the case is
146 opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or
147 the state of the other clamp.
148
149 Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item.
150 In this case the root's parent actually initiates the power state change so that the root has no choice and does not give
151 applications the opportunity to veto the change.
152
153 Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep. When this is true, the root's
154 children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE)
155 to hold itself on until the sleep timer expires. This timer is set for the difference between the sleep timeout slider and
156 the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel. For example, if
157 the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes,
158 when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root
159 sets its timer for 25 minutes (30 - 5). When the timer expires, it releases its clamp and now nothing is holding it awake,
160 so it falls asleep.
161
162 Demand sleep is prevented when the system is booting. When preferences are transmitted by the loginwindow at the end of
163 boot, a flag is cleared, and this allows subsequent Demand Sleep.
164
165 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
166 a clamp, but sets a flag which is noticed before actually sleeping the kernel. If the flag is set, the root steps up
167 one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and
168 ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler
169 to be tickled)).
170 */
171
172 // **********************************************************************************
173
174 IOPMrootDomain * IOPMrootDomain::construct( void )
175 {
176 IOPMrootDomain *root;
177
178 root = new IOPMrootDomain;
179 if( root)
180 root->init();
181
182 return( root );
183 }
184
185 // **********************************************************************************
186
187 static void disk_sync_callout(thread_call_param_t p0, thread_call_param_t p1)
188 {
189 IOService *rootDomain = (IOService *) p0;
190 unsigned long pmRef = (unsigned long) p1;
191
192 IOHibernateSystemSleep();
193 sync_internal();
194 rootDomain->allowPowerChange(pmRef);
195 }
196
197 // **********************************************************************************
198 // start
199 //
200 // We don't do much here. The real initialization occurs when the platform
201 // expert informs us we are the root.
202 // **********************************************************************************
203
204
205 bool IOPMrootDomain::start ( IOService * nub )
206 {
207 OSDictionary *tmpDict;
208
209 pmPowerStateQueue = 0;
210
211 _reserved = (ExpansionData *)IOMalloc(sizeof(ExpansionData));
212 if(!_reserved) return false;
213
214 super::start(nub);
215
216 gRootDomain = this;
217
218 PMinit();
219 setProperty("IOSleepSupported","");
220
221 allowSleep = true;
222 sleepIsSupported = true;
223 systemBooting = true;
224 ignoringClamshell = true;
225 sleepSlider = 0;
226 idleSleepPending = false;
227 canSleep = true;
228 wrangler = NULL;
229 sleepASAP = false;
230 _settingController = NULL;
231 ignoringClamshellDuringWakeup = false;
232
233 tmpDict = OSDictionary::withCapacity(1);
234 setProperty(kRootDomainSupportedFeatures, tmpDict);
235 tmpDict->release();
236
237 pm_vars->PMworkloop = IOWorkLoop::workLoop();
238 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(this);
239 pm_vars->PMworkloop->addEventSource(pmPowerStateQueue);
240
241 featuresDictLock = IOLockAlloc();
242
243 extraSleepTimer = thread_call_allocate((thread_call_func_t)sleepTimerExpired, (thread_call_param_t) this);
244 clamshellWakeupIgnore = thread_call_allocate((thread_call_func_t)wakeupClamshellTimerExpired, (thread_call_param_t) this);
245 diskSyncCalloutEntry = thread_call_allocate(&disk_sync_callout, (thread_call_param_t) this);
246
247 // create our parent
248 patriarch = new IORootParent;
249 patriarch->init();
250 patriarch->attach(this);
251 patriarch->start(this);
252 patriarch->youAreRoot();
253 patriarch->wakeSystem();
254 patriarch->addPowerChild(this);
255
256 registerPowerDriver(this,ourPowerStates,number_of_power_states);
257
258 setPMRootDomain(this);
259 // set a clamp until we sleep
260 changePowerStateToPriv(ON_STATE);
261
262 // install power change handler
263 registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
264
265 // Register for a notification when IODisplayWrangler is published
266 _displayWranglerNotifier = addNotification( gIOPublishNotification,
267 serviceMatching("IODisplayWrangler"),
268 &displayWranglerPublished, this, 0);
269
270 _batteryLocationNotifier = addNotification( gIOPublishNotification,
271 resourceMatching("battery"),
272 &batteryLocationPublished, this, this);
273
274 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
275 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
276 ucClassName->release();
277
278 IORegistryEntry *temp_entry = NULL;
279 if( (temp_entry = IORegistryEntry::fromPath("mac-io/battery", gIODTPlane)) ||
280 (temp_entry = IORegistryEntry::fromPath("mac-io/via-pmu/battery", gIODTPlane)))
281 {
282 // If this machine has a battery, publish the fact that the backlight
283 // supports dimming.
284 // Notice similar call in IOPMrootDomain::batteryLocationPublished() to
285 // detect batteries on SMU machines.
286 publishFeature("DisplayDims");
287 temp_entry->release();
288 }
289
290 IOHibernateSystemInit(this);
291
292 registerService(); // let clients find us
293
294 return true;
295 }
296
297 IOReturn IOPMrootDomain::setPMSetting(int type, OSNumber *n)
298 {
299 if(_settingController && _settingController->func) {
300 int seconds;
301 seconds = n->unsigned32BitValue();
302 return (*(_settingController->func))(type, seconds, _settingController->refcon);
303 } else {
304 return kIOReturnNoDevice;
305 }
306 }
307
308 // **********************************************************************************
309 // setProperties
310 //
311 // Receive a setProperty call
312 // The "System Boot" property means the system is completely booted.
313 // **********************************************************************************
314 IOReturn IOPMrootDomain::setProperties ( OSObject *props_obj)
315 {
316 IOReturn return_value = kIOReturnSuccess;
317 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
318 OSBoolean *b;
319 OSNumber *n;
320 OSString *str;
321 const OSSymbol *boot_complete_string = OSSymbol::withCString("System Boot Complete");
322 const OSSymbol *power_button_string = OSSymbol::withCString("DisablePowerButtonSleep");
323 const OSSymbol *stall_halt_string = OSSymbol::withCString("StallSystemAtHalt");
324 const OSSymbol *auto_wake_string = OSSymbol::withCString("wake");
325 const OSSymbol *auto_power_string = OSSymbol::withCString("poweron");
326 const OSSymbol *wakeonring_string = OSSymbol::withCString("WakeOnRing");
327 const OSSymbol *fileserver_string = OSSymbol::withCString("AutoRestartOnPowerLoss");
328 const OSSymbol *wakeonlid_string = OSSymbol::withCString("WakeOnLid");
329 const OSSymbol *wakeonac_string = OSSymbol::withCString("WakeOnACChange");
330 const OSSymbol *hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey);
331 const OSSymbol *hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey);
332 const OSSymbol *hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey);
333 const OSSymbol *hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey);
334 const OSSymbol *timezone_string = OSSymbol::withCString("TimeZoneOffsetSeconds");
335
336 if(!dict)
337 {
338 return_value = kIOReturnBadArgument;
339 goto exit;
340 }
341
342 if( systemBooting
343 && boot_complete_string
344 && dict->getObject(boot_complete_string))
345 {
346 systemBooting = false;
347 adjustPowerState();
348 }
349
350 if( power_button_string
351 && (b = OSDynamicCast(OSBoolean, dict->getObject(power_button_string))) )
352 {
353 setProperty(power_button_string, b);
354 }
355
356 if( stall_halt_string
357 && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) )
358 {
359 setProperty(stall_halt_string, b);
360 }
361
362 if ( hibernatemode_string
363 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string))))
364 {
365 setProperty(hibernatemode_string, n);
366 }
367 if ( hibernatefreeratio_string
368 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string))))
369 {
370 setProperty(hibernatefreeratio_string, n);
371 }
372 if ( hibernatefreetime_string
373 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string))))
374 {
375 setProperty(hibernatefreetime_string, n);
376 }
377 if ( hibernatefile_string
378 && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string))))
379 {
380 setProperty(hibernatefile_string, str);
381 }
382
383 // Relay AutoWake setting to its controller
384 if( auto_wake_string
385 && (n = OSDynamicCast(OSNumber, dict->getObject(auto_wake_string))) )
386 {
387 return_value = setPMSetting(kIOPMAutoWakeSetting, n);
388 if(kIOReturnSuccess != return_value) goto exit;
389 }
390
391 // Relay AutoPower setting to its controller
392 if( auto_power_string
393 && (n = OSDynamicCast(OSNumber, dict->getObject(auto_power_string))) )
394 {
395 return_value = setPMSetting(kIOPMAutoPowerOnSetting, n);
396 if(kIOReturnSuccess != return_value) goto exit;
397 }
398
399 // Relay WakeOnRing setting to its controller
400 if( wakeonring_string
401 && (n = OSDynamicCast(OSNumber, dict->getObject(wakeonring_string))) )
402 {
403 return_value = setPMSetting(kIOPMWakeOnRingSetting, n);
404 if(kIOReturnSuccess != return_value) goto exit;
405 }
406
407 // Relay FileServer setting to its controller
408 if( fileserver_string
409 && (n = OSDynamicCast(OSNumber, dict->getObject(fileserver_string))) )
410 {
411 return_value = setPMSetting(kIOPMAutoRestartOnPowerLossSetting, n);
412 if(kIOReturnSuccess != return_value) goto exit;
413 }
414
415 // Relay WakeOnLid setting to its controller
416 if( wakeonlid_string
417 && (n = OSDynamicCast(OSNumber, dict->getObject(wakeonlid_string))) )
418 {
419 return_value = setPMSetting(kIOPMWakeOnLidSetting, n);
420 if(kIOReturnSuccess != return_value) goto exit;
421 }
422
423 // Relay WakeOnACChange setting to its controller
424 if( wakeonac_string
425 && (n = OSDynamicCast(OSNumber, dict->getObject(wakeonac_string))) )
426 {
427 return_value = setPMSetting(kIOPMWakeOnACChangeSetting, n);
428 if(kIOReturnSuccess != return_value) goto exit;
429 }
430
431 // Relay timezone offset in seconds to SMU
432 if( timezone_string
433 && (n = OSDynamicCast(OSNumber, dict->getObject(timezone_string))) )
434 {
435 return_value = setPMSetting(kIOPMTimeZoneSetting, n);
436 if(kIOReturnSuccess != return_value) goto exit;
437 }
438
439
440 exit:
441 if(boot_complete_string) boot_complete_string->release();
442 if(power_button_string) power_button_string->release();
443 if(stall_halt_string) stall_halt_string->release();
444 if(auto_wake_string) auto_wake_string->release();
445 if(auto_power_string) auto_power_string->release();
446 if(wakeonring_string) wakeonring_string->release();
447 if(fileserver_string) fileserver_string->release();
448 if(wakeonlid_string) wakeonlid_string->release();
449 if(wakeonac_string) wakeonac_string->release();
450 if(timezone_string) timezone_string->release();
451 return return_value;
452 }
453
454
455 //*********************************************************************************
456 // youAreRoot
457 //
458 // Power Managment is informing us that we are the root power domain.
459 // We know we are not the root however, since we have just instantiated a parent
460 // for ourselves and made it the root. We override this method so it will have
461 // no effect
462 //*********************************************************************************
463 IOReturn IOPMrootDomain::youAreRoot ( void )
464 {
465 return IOPMNoErr;
466 }
467
468 // **********************************************************************************
469 // command_received
470 //
471 // No longer used
472 // **********************************************************************************
473 void IOPMrootDomain::command_received ( void * w, void * x, void * y, void * z )
474 {
475 super::command_received(w,x,y,z);
476 }
477
478
479 // **********************************************************************************
480 // broadcast_aggressiveness
481 //
482 // **********************************************************************************
483 IOReturn broadcast_aggressiveness ( OSObject * root, void * x, void * y, void *, void * )
484 {
485 ((IOPMrootDomain *)root)->broadcast_it((unsigned long)x,(unsigned long)y);
486 return IOPMNoErr;
487 }
488
489
490 // **********************************************************************************
491 // broadcast_it
492 //
493 // We are behind the command gate to broadcast an aggressiveness factor. We let the
494 // superclass do it, but we need to snoop on factors that affect idle sleep.
495 // **********************************************************************************
496 void IOPMrootDomain::broadcast_it (unsigned long type, unsigned long value)
497 {
498 super::setAggressiveness(type,value);
499
500 // Save user's spin down timer to restore after we replace it for idle sleep
501 if( type == kPMMinutesToSpinDown ) user_spindown = value;
502
503 // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer
504 longestNonSleepSlider = pm_vars->current_aggressiveness_values[kPMMinutesToDim];
505
506
507 if ( type == kPMMinutesToSleep ) {
508 if ( (sleepSlider == 0) && (value != 0) ) {
509 sleepSlider = value;
510 // idle sleep is now enabled, maybe sleep now
511 adjustPowerState();
512 }
513 sleepSlider = value;
514 if ( sleepSlider == 0 ) {
515 // idle sleep is now disabled
516 adjustPowerState();
517 // make sure we're powered
518 patriarch->wakeSystem();
519 }
520 }
521 if ( sleepSlider > longestNonSleepSlider ) {
522 extraSleepDelay = sleepSlider - longestNonSleepSlider ;
523 }
524 else {
525 extraSleepDelay = 0;
526 }
527 }
528
529
530 // **********************************************************************************
531 // sleepTimerExpired
532 //
533 // **********************************************************************************
534 static void sleepTimerExpired ( thread_call_param_t us)
535 {
536 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
537 }
538
539
540 static void wakeupClamshellTimerExpired ( thread_call_param_t us)
541 {
542 ((IOPMrootDomain *)us)->stopIgnoringClamshellEventsDuringWakeup();
543 }
544
545
546 // **********************************************************************************
547 // handleSleepTimerExpiration
548 //
549 // The time between the sleep idle timeout and the next longest one has elapsed.
550 // It's time to sleep. Start that by removing the clamp that's holding us awake.
551 // **********************************************************************************
552 void IOPMrootDomain::handleSleepTimerExpiration ( void )
553 {
554 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
555 if(0 != user_spindown)
556 setQuickSpinDownTimeout();
557
558 sleepASAP = true;
559 adjustPowerState();
560 }
561
562
563 void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void)
564 {
565 OSObject * state;
566
567 // Allow clamshell-induced sleep now
568 ignoringClamshellDuringWakeup = false;
569
570 if ((state = getProperty(kAppleClamshellStateKey)))
571 publishResource(kAppleClamshellStateKey, state);
572 }
573
574 //*********************************************************************************
575 // setAggressiveness
576 //
577 // Some aggressiveness factor has changed. We broadcast it to the hierarchy while on
578 // the Power Mangement workloop thread. This enables objects in the
579 // hierarchy to successfully alter their idle timers, which are all on the
580 // same thread.
581 //*********************************************************************************
582
583 static int pmsallsetup = 0;
584
585 IOReturn IOPMrootDomain::setAggressiveness ( unsigned long type, unsigned long newLevel )
586 {
587 #ifdef __ppc__
588 if(pmsExperimental & 3) kprintf("setAggressiveness: type = %08X, newlevel = %08X\n", type, newLevel);
589 if(pmsExperimental & 1) { /* Is experimental mode enabled? */
590 if(pmsInstalled && (type == kPMSetProcessorSpeed)) { /* We want to look at all processor speed changes if stepper is installed */
591 if(pmsallsetup) return kIOReturnSuccess; /* If already running, just eat this */
592 kprintf("setAggressiveness: starting stepper...\n");
593 pmsallsetup = 1; /* Remember we did this */
594 pmsPark();
595 pmsStart(); /* Get it all started up... */
596 return kIOReturnSuccess; /* Leave now... */
597 }
598 }
599 #endif
600
601 if ( pm_vars->PMcommandGate ) {
602 pm_vars->PMcommandGate->runAction(broadcast_aggressiveness,(void *)type,(void *)newLevel);
603 }
604
605 return kIOReturnSuccess;
606 }
607
608
609 // **********************************************************************************
610 // sleepSystem
611 //
612 // **********************************************************************************
613 IOReturn IOPMrootDomain::sleepSystem ( void )
614 {
615 //kprintf("sleep demand received\n");
616 if ( !systemBooting && allowSleep && sleepIsSupported ) {
617 patriarch->sleepSystem();
618
619 return kIOReturnSuccess;
620 }
621 if ( !systemBooting && allowSleep && !sleepIsSupported ) {
622 patriarch->dozeSystem();
623 return kIOReturnSuccess;
624 }
625 return kIOReturnSuccess;
626 }
627
628
629 // **********************************************************************************
630 // shutdownSystem
631 //
632 // **********************************************************************************
633 IOReturn IOPMrootDomain::shutdownSystem ( void )
634 {
635 //patriarch->shutDownSystem();
636 return kIOReturnUnsupported;
637 }
638
639
640 // **********************************************************************************
641 // restartSystem
642 //
643 // **********************************************************************************
644 IOReturn IOPMrootDomain::restartSystem ( void )
645 {
646 //patriarch->restartSystem();
647 return kIOReturnUnsupported;
648 }
649
650
651 // **********************************************************************************
652 // powerChangeDone
653 //
654 // This overrides powerChangeDone in IOService.
655 //
656 // Finder sleep and idle sleep move us from the ON state to the SLEEP_STATE.
657 // In this case:
658 // If we just finished going to the SLEEP_STATE, and the platform is capable of true sleep,
659 // sleep the kernel. Otherwise switch up to the DOZE_STATE which will keep almost
660 // everything as off as it can get.
661 //
662 // **********************************************************************************
663 void IOPMrootDomain::powerChangeDone ( unsigned long previousState )
664 {
665 OSNumber * propertyPtr;
666 unsigned short theProperty;
667 AbsoluteTime deadline;
668
669 switch ( pm_vars->myCurrentState ) {
670 case SLEEP_STATE:
671 if ( canSleep && sleepIsSupported )
672 {
673 // re-enable this timer for next sleep
674 idleSleepPending = false;
675
676 IOLog("System %sSleep\n", gIOHibernateState ? "Safe" : "");
677
678 IOHibernateSystemHasSlept();
679
680 pm_vars->thePlatform->sleepKernel();
681
682 // The CPU(s) are off at this point. When they're awakened by CPU interrupt,
683 // code will resume execution here.
684
685 // Now we're waking...
686 IOHibernateSystemWake();
687
688 // stay awake for at least 30 seconds
689 clock_interval_to_deadline(30, kSecondScale, &deadline);
690 thread_call_enter_delayed(extraSleepTimer, deadline);
691 // this gets turned off when we sleep again
692 idleSleepPending = true;
693
694 // Ignore closed clamshell during wakeup and for a few seconds
695 // after wakeup is complete
696 ignoringClamshellDuringWakeup = true;
697
698 // sleep transition complete
699 gSleepOrShutdownPending = 0;
700
701 // trip the reset of the calendar clock
702 clock_wakeup_calendar();
703
704 // get us some power
705 patriarch->wakeSystem();
706
707 // early stage wake notification
708 tellClients(kIOMessageSystemWillPowerOn);
709
710 // tell the tree we're waking
711 IOLog("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
712 systemWake();
713
714 // Allow drivers to request extra processing time before clamshell
715 // sleep if kIOREMSleepEnabledKey is present.
716 // Ignore clamshell events for at least 5 seconds
717 if(getProperty(kIOREMSleepEnabledKey)) {
718 // clamshellWakeupIgnore callout clears ignoreClamshellDuringWakeup bit
719 clock_interval_to_deadline(5, kSecondScale, &deadline);
720 if(clamshellWakeupIgnore) thread_call_enter_delayed(clamshellWakeupIgnore, deadline);
721 } else ignoringClamshellDuringWakeup = false;
722
723 // Find out what woke us
724 propertyPtr = OSDynamicCast(OSNumber,getProperty("WakeEvent"));
725 if ( propertyPtr ) {
726 theProperty = propertyPtr->unsigned16BitValue();
727 IOLog("Wake event %04x\n",theProperty);
728 if ( (theProperty & 0x0008) || //lid
729 (theProperty & 0x0800) || // front panel button
730 (theProperty & 0x0020) || // external keyboard
731 (theProperty & 0x0001) ) { // internal keyboard
732 // We've identified the wakeup event as UI driven
733 reportUserInput();
734 }
735 } else {
736 // Since we can't identify the wakeup event, treat it as UI activity
737 reportUserInput();
738 }
739
740 // Wake for thirty seconds
741 changePowerStateToPriv(ON_STATE);
742 powerOverrideOffPriv();
743 } else {
744 // allow us to step up a power state
745 patriarch->sleepToDoze();
746 // and do it
747 changePowerStateToPriv(DOZE_STATE);
748 }
749 break;
750
751 case DOZE_STATE:
752 if ( previousState != DOZE_STATE )
753 {
754 IOLog("System Doze\n");
755 }
756 // re-enable this timer for next sleep
757 idleSleepPending = false;
758 gSleepOrShutdownPending = 0;
759 break;
760
761 case RESTART_STATE:
762 IOLog("System Restart\n");
763 PEHaltRestart(kPERestartCPU);
764 break;
765
766 case OFF_STATE:
767 IOLog("System Halt\n");
768 PEHaltRestart(kPEHaltCPU);
769 break;
770 }
771 }
772
773
774 // **********************************************************************************
775 // wakeFromDoze
776 //
777 // The Display Wrangler calls here when it switches to its highest state. If the
778 // system is currently dozing, allow it to wake by making sure the parent is
779 // providing power.
780 // **********************************************************************************
781 void IOPMrootDomain::wakeFromDoze( void )
782 {
783 if ( pm_vars->myCurrentState == DOZE_STATE )
784 {
785 // reset this till next attempt
786 canSleep = true;
787 powerOverrideOffPriv();
788
789 // early wake notification
790 tellClients(kIOMessageSystemWillPowerOn);
791
792 // allow us to wake if children so desire
793 patriarch->wakeSystem();
794 }
795 }
796
797
798 // **********************************************************************************
799 // publishFeature
800 //
801 // Adds a new feature to the supported features dictionary
802 //
803 //
804 // **********************************************************************************
805 void IOPMrootDomain::publishFeature( const char * feature )
806 {
807 if(featuresDictLock) IOLockLock(featuresDictLock);
808 OSDictionary *features =
809 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
810
811 if ( features && OSDynamicCast(OSDictionary, features))
812 features = OSDictionary::withDictionary(features);
813 else
814 features = OSDictionary::withCapacity(1);
815
816 features->setObject(feature, kOSBooleanTrue);
817 setProperty(kRootDomainSupportedFeatures, features);
818 features->release();
819 if(featuresDictLock) IOLockUnlock(featuresDictLock);
820 }
821
822
823 void IOPMrootDomain::unIdleDevice( IOService *theDevice, unsigned long theState )
824 {
825 if(pmPowerStateQueue)
826 pmPowerStateQueue->unIdleOccurred(theDevice, theState);
827 }
828
829 void IOPMrootDomain::announcePowerSourceChange( void )
830 {
831 IORegistryEntry *_batteryRegEntry = (IORegistryEntry *) getProperty("BatteryEntry");
832
833 // (if possible) re-publish power source state under IOPMrootDomain
834 // (only done if the battery controller publishes an IOResource defining battery location)
835 if(_batteryRegEntry)
836 {
837 OSArray *batt_info;
838 batt_info = (OSArray *) _batteryRegEntry->getProperty(kIOBatteryInfoKey);
839 if(batt_info)
840 setProperty(kIOBatteryInfoKey, batt_info);
841 }
842
843 messageClients(kIOPMMessageBatteryStatusHasChanged);
844 }
845
846 IOReturn IOPMrootDomain::registerPMSettingController
847 (IOPMSettingControllerCallback func, void *info)
848 {
849 if(_settingController) return kIOReturnExclusiveAccess;
850
851 _settingController = (PMSettingCtrl *)IOMalloc(sizeof(PMSettingCtrl));
852 if(!_settingController) return kIOReturnNoMemory;
853
854 _settingController->func = func;
855 _settingController->refcon = info;
856 return kIOReturnSuccess;
857 }
858
859
860 //*********************************************************************************
861 // receivePowerNotification
862 //
863 // The power controller is notifying us of a hardware-related power management
864 // event that we must handle. This is a result of an 'environment' interrupt from
865 // the power mgt micro.
866 //*********************************************************************************
867
868 IOReturn IOPMrootDomain::receivePowerNotification (UInt32 msg)
869 {
870 if (msg & kIOPMOverTemp)
871 {
872 IOLog("Power Management received emergency overtemp signal. Going to sleep.");
873 (void) sleepSystem ();
874 }
875 if (msg & kIOPMSetDesktopMode)
876 {
877 desktopMode = (0 != (msg & kIOPMSetValue));
878 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
879 }
880 if (msg & kIOPMSetACAdaptorConnected)
881 {
882 acAdaptorConnect = (0 != (msg & kIOPMSetValue));
883 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
884 }
885 if (msg & kIOPMEnableClamshell)
886 {
887 ignoringClamshell = false;
888 }
889 if (msg & kIOPMDisableClamshell)
890 {
891 ignoringClamshell = true;
892 }
893
894 if (msg & kIOPMProcessorSpeedChange)
895 {
896 IOService *pmu = waitForService(serviceMatching("ApplePMU"));
897 pmu->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
898 pm_vars->thePlatform->sleepKernel();
899 pmu->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
900 }
901
902 if (msg & kIOPMSleepNow)
903 {
904 (void) sleepSystem ();
905 }
906
907 if (msg & kIOPMPowerEmergency)
908 {
909 (void) sleepSystem ();
910 }
911
912 if (msg & kIOPMClamshellClosed)
913 {
914 if ( !ignoringClamshell && !ignoringClamshellDuringWakeup
915 && (!desktopMode || !acAdaptorConnect) )
916 {
917
918 (void) sleepSystem ();
919 }
920 }
921
922 if (msg & kIOPMPowerButton)
923 {
924 // toggle state of sleep/wake
925 // are we dozing?
926 if ( pm_vars->myCurrentState == DOZE_STATE )
927 {
928 // yes, tell the tree we're waking
929 systemWake();
930 // wake the Display Wrangler
931 reportUserInput();
932 }
933 else {
934 // Check that power button sleep is enabled
935 if(kOSBooleanTrue != getProperty(OSString::withCString("DisablePowerButtonSleep")))
936 sleepSystem();
937 }
938 }
939
940 // if the case has been closed, we allow
941 // the machine to be put to sleep or to idle sleep
942
943 if ( (msg & kIOPMAllowSleep) && !allowSleep )
944 {
945 allowSleep = true;
946 adjustPowerState();
947 }
948
949 // if the case has been opened, we disallow sleep/doze
950
951 if (msg & kIOPMPreventSleep) {
952 allowSleep = false;
953 // are we dozing?
954 if ( pm_vars->myCurrentState == DOZE_STATE ) {
955 // yes, tell the tree we're waking
956 systemWake();
957 adjustPowerState();
958 // wake the Display Wrangler
959 reportUserInput();
960 } else {
961 adjustPowerState();
962 // make sure we have power to clamp
963 patriarch->wakeSystem();
964 }
965 }
966
967 return 0;
968 }
969
970
971 //*********************************************************************************
972 // sleepSupported
973 //
974 //*********************************************************************************
975
976 void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
977 {
978 if ( flags & kPCICantSleep )
979 {
980 canSleep = false;
981 } else {
982 platformSleepSupport = flags;
983 }
984
985 }
986
987 //*********************************************************************************
988 // requestPowerDomainState
989 //
990 // The root domain intercepts this call to the superclass.
991 //
992 // If the clamp bit is not set in the desire, then the child doesn't need the power
993 // state it's requesting; it just wants it. The root ignores desires but not needs.
994 // If the clamp bit is not set, the root takes it that the child can tolerate no
995 // power and interprets the request accordingly. If all children can thus tolerate
996 // no power, we are on our way to idle sleep.
997 //*********************************************************************************
998
999 IOReturn IOPMrootDomain::requestPowerDomainState ( IOPMPowerFlags desiredState, IOPowerConnection * whichChild, unsigned long specification )
1000 {
1001 OSIterator *iter;
1002 OSObject *next;
1003 IOPowerConnection *connection;
1004 unsigned long powerRequestFlag = 0;
1005 IOPMPowerFlags editedDesire = desiredState;
1006
1007 // if they don't really need it, they don't get it
1008 if ( !(desiredState & kIOPMPreventIdleSleep) ) {
1009 editedDesire = 0;
1010 }
1011
1012
1013 IOLockLock(pm_vars->childLock);
1014
1015 // recompute sleepIsSupported and see if all children are asleep
1016 iter = getChildIterator(gIOPowerPlane);
1017 sleepIsSupported = true;
1018 if ( iter )
1019 {
1020 while ( (next = iter->getNextObject()) )
1021 {
1022 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
1023 {
1024 if ( connection == whichChild )
1025 {
1026 powerRequestFlag += editedDesire;
1027 if ( desiredState & kIOPMPreventSystemSleep )
1028 {
1029 sleepIsSupported = false;
1030 }
1031 } else {
1032 powerRequestFlag += connection->getDesiredDomainState();
1033 if ( connection->getPreventSystemSleepFlag() )
1034 {
1035 sleepIsSupported = false;
1036 }
1037 }
1038 }
1039 }
1040 iter->release();
1041 }
1042
1043 if ( (extraSleepDelay == 0) && (powerRequestFlag == 0) )
1044 {
1045 sleepASAP = true;
1046 }
1047
1048 // this may put the system to sleep
1049 adjustPowerState();
1050
1051 IOLockUnlock(pm_vars->childLock);
1052
1053 editedDesire |= desiredState & kIOPMPreventSystemSleep;
1054
1055 return super::requestPowerDomainState(editedDesire,whichChild,specification);
1056 }
1057
1058
1059 //*********************************************************************************
1060 // getSleepSupported
1061 //
1062 //*********************************************************************************
1063
1064 IOOptionBits IOPMrootDomain::getSleepSupported( void )
1065 {
1066 return( platformSleepSupport );
1067 }
1068
1069
1070 //*********************************************************************************
1071 // tellChangeDown
1072 //
1073 // We override the superclass implementation so we can send a different message
1074 // type to the client or application being notified.
1075 //*********************************************************************************
1076
1077 bool IOPMrootDomain::tellChangeDown ( unsigned long stateNum )
1078 {
1079 switch ( stateNum ) {
1080 case DOZE_STATE:
1081 case SLEEP_STATE:
1082 return super::tellClientsWithResponse(kIOMessageSystemWillSleep);
1083 case RESTART_STATE:
1084 return super::tellClientsWithResponse(kIOMessageSystemWillRestart);
1085 case OFF_STATE:
1086 return super::tellClientsWithResponse(kIOMessageSystemWillPowerOff);
1087 }
1088 // this shouldn't execute
1089 return super::tellChangeDown(stateNum);
1090 }
1091
1092
1093 //*********************************************************************************
1094 // askChangeDown
1095 //
1096 // We override the superclass implementation so we can send a different message
1097 // type to the client or application being notified.
1098 //
1099 // This must be idle sleep since we don't ask apps during any other power change.
1100 //*********************************************************************************
1101
1102 bool IOPMrootDomain::askChangeDown ( unsigned long )
1103 {
1104 return super::tellClientsWithResponse(kIOMessageCanSystemSleep);
1105 }
1106
1107
1108 //*********************************************************************************
1109 // tellNoChangeDown
1110 //
1111 // Notify registered applications and kernel clients that we are not
1112 // dropping power.
1113 //
1114 // We override the superclass implementation so we can send a different message
1115 // type to the client or application being notified.
1116 //
1117 // This must be a vetoed idle sleep, since no other power change can be vetoed.
1118 //*********************************************************************************
1119
1120 void IOPMrootDomain::tellNoChangeDown ( unsigned long )
1121 {
1122 return tellClients(kIOMessageSystemWillNotSleep);
1123 }
1124
1125
1126 //*********************************************************************************
1127 // tellChangeUp
1128 //
1129 // Notify registered applications and kernel clients that we are raising power.
1130 //
1131 // We override the superclass implementation so we can send a different message
1132 // type to the client or application being notified.
1133 //*********************************************************************************
1134
1135 void IOPMrootDomain::tellChangeUp ( unsigned long stateNum)
1136 {
1137 if ( stateNum == ON_STATE )
1138 {
1139 IOHibernateSystemPostWake();
1140 return tellClients(kIOMessageSystemHasPoweredOn);
1141 }
1142 }
1143
1144 //*********************************************************************************
1145 // reportUserInput
1146 //
1147 //*********************************************************************************
1148
1149 void IOPMrootDomain::reportUserInput ( void )
1150 {
1151 OSIterator * iter;
1152
1153 if(!wrangler)
1154 {
1155 iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
1156 if(iter)
1157 {
1158 wrangler = (IOService *) iter->getNextObject();
1159 iter->release();
1160 }
1161 }
1162
1163 if(wrangler)
1164 wrangler->activityTickle(0,0);
1165 }
1166
1167 //*********************************************************************************
1168 // setQuickSpinDownTimeout
1169 //
1170 //*********************************************************************************
1171
1172 void IOPMrootDomain::setQuickSpinDownTimeout ( void )
1173 {
1174 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)1);
1175 }
1176
1177 //*********************************************************************************
1178 // restoreUserSpinDownTimeout
1179 //
1180 //*********************************************************************************
1181
1182 void IOPMrootDomain::restoreUserSpinDownTimeout ( void )
1183 {
1184 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)user_spindown);
1185 }
1186
1187 //*********************************************************************************
1188 // changePowerStateTo & changePowerStateToPriv
1189 //
1190 // Override of these methods for logging purposes.
1191 //*********************************************************************************
1192
1193 IOReturn IOPMrootDomain::changePowerStateTo ( unsigned long ordinal )
1194 {
1195 return super::changePowerStateTo(ordinal);
1196 }
1197
1198 IOReturn IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal )
1199 {
1200 return super::changePowerStateToPriv(ordinal);
1201 }
1202
1203
1204 //*********************************************************************************
1205 // sysPowerDownHandler
1206 //
1207 // Receives a notification when the RootDomain changes state.
1208 //
1209 // Allows us to take action on system sleep, power down, and restart after
1210 // applications have received their power change notifications and replied,
1211 // but before drivers have powered down. We perform a vfs sync on power down.
1212 //*********************************************************************************
1213
1214 IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon,
1215 UInt32 messageType, IOService * service,
1216 void * messageArgument, vm_size_t argSize )
1217 {
1218 IOReturn ret;
1219 IOPowerStateChangeNotification *params = (IOPowerStateChangeNotification *) messageArgument;
1220 IOPMrootDomain *rootDomain = OSDynamicCast(IOPMrootDomain, service);
1221
1222 if(!rootDomain)
1223 return kIOReturnUnsupported;
1224
1225 switch (messageType) {
1226 case kIOMessageSystemWillSleep:
1227 rootDomain->powerOverrideOnPriv(); // start ignoring children's requests
1228 // (fall through to other cases)
1229
1230 // Interested applications have been notified of an impending power
1231 // change and have acked (when applicable).
1232 // This is our chance to save whatever state we can before powering
1233 // down.
1234 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
1235 // via callout
1236
1237 // We will ack within 20 seconds
1238 params->returnValue = 20 * 1000 * 1000;
1239 if (gIOHibernateState)
1240 params->returnValue += gIOHibernateFreeTime * 1000; //add in time we could spend freeing pages
1241
1242 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
1243 {
1244 // Purposely delay the ack and hope that shutdown occurs quickly.
1245 // Another option is not to schedule the thread and wait for
1246 // ack timeout...
1247 AbsoluteTime deadline;
1248 clock_interval_to_deadline( 30, kSecondScale, &deadline );
1249 thread_call_enter1_delayed( rootDomain->diskSyncCalloutEntry,
1250 (thread_call_param_t)params->powerRef,
1251 deadline );
1252 }
1253 else
1254 thread_call_enter1(rootDomain->diskSyncCalloutEntry, (thread_call_param_t)params->powerRef);
1255 ret = kIOReturnSuccess;
1256 break;
1257
1258 case kIOMessageSystemWillPowerOff:
1259 case kIOMessageSystemWillRestart:
1260 ret = kIOReturnUnsupported;
1261 break;
1262
1263 default:
1264 ret = kIOReturnUnsupported;
1265 break;
1266 }
1267 return ret;
1268 }
1269
1270 //*********************************************************************************
1271 // displayWranglerNotification
1272 //
1273 // Receives a notification when the IODisplayWrangler changes state.
1274 //
1275 // Allows us to take action on display dim/undim.
1276 //
1277 // When the display goes dim we:
1278 // - Start the idle sleep timer
1279 // - set the quick spin down timeout
1280 //
1281 // On wake from display dim:
1282 // - Cancel the idle sleep timer
1283 // - restore the user's chosen spindown timer from the "quick" spin down value
1284 //*********************************************************************************
1285
1286 IOReturn IOPMrootDomain::displayWranglerNotification( void * target, void * refCon,
1287 UInt32 messageType, IOService * service,
1288 void * messageArgument, vm_size_t argSize )
1289 {
1290 IOPMrootDomain * rootDomain = OSDynamicCast(IOPMrootDomain, (IOService *)target);
1291 AbsoluteTime deadline;
1292 static bool deviceAlreadyPoweredOff = false;
1293
1294 if(!rootDomain)
1295 return kIOReturnUnsupported;
1296
1297 switch (messageType) {
1298 case kIOMessageDeviceWillPowerOff:
1299 // The IODisplayWrangler has powered off either because of idle display sleep
1300 // or force system sleep.
1301
1302 // The display wrangler will send the DeviceWillPowerOff message 4 times until
1303 // it gets into its lowest state. We only want to act on the first of those 4.
1304 if( deviceAlreadyPoweredOff ) return kIOReturnUnsupported;
1305
1306 deviceAlreadyPoweredOff = true;
1307
1308 if( rootDomain->extraSleepDelay )
1309 {
1310 // start the extra sleep timer
1311 clock_interval_to_deadline(rootDomain->extraSleepDelay*60, kSecondScale, &deadline );
1312 thread_call_enter_delayed(rootDomain->extraSleepTimer, deadline);
1313 rootDomain->idleSleepPending = true;
1314 } else {
1315 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
1316 // and if system sleep is non-Never
1317 if( (0 != rootDomain->user_spindown) && (0 != rootDomain->sleepSlider) )
1318 rootDomain->setQuickSpinDownTimeout();
1319 }
1320
1321 break;
1322
1323 case kIOMessageDeviceHasPoweredOn:
1324
1325 // The display has powered on either because of UI activity or wake from sleep/doze
1326 deviceAlreadyPoweredOff = false;
1327 rootDomain->adjustPowerState();
1328
1329
1330 // cancel any pending idle sleep
1331 if(rootDomain->idleSleepPending)
1332 {
1333 thread_call_cancel(rootDomain->extraSleepTimer);
1334 rootDomain->idleSleepPending = false;
1335 }
1336
1337 // Change the spindown value back to the user's selection from our accelerated setting
1338 if(0 != rootDomain->user_spindown)
1339 rootDomain->restoreUserSpinDownTimeout();
1340
1341 // Put on the policy maker's on clamp.
1342
1343 break;
1344
1345 default:
1346 break;
1347 }
1348 return kIOReturnUnsupported;
1349 }
1350
1351 //*********************************************************************************
1352 // displayWranglerPublished
1353 //
1354 // Receives a notification when the IODisplayWrangler is published.
1355 // When it's published we install a power state change handler.
1356 //
1357 //*********************************************************************************
1358
1359 bool IOPMrootDomain::displayWranglerPublished( void * target, void * refCon,
1360 IOService * newService)
1361 {
1362 IOPMrootDomain * rootDomain = OSDynamicCast(IOPMrootDomain, (IOService *)target);
1363
1364 if(!rootDomain)
1365 return false;
1366
1367 rootDomain->wrangler = newService;
1368
1369 // we found the display wrangler, now install a handler
1370 if( !rootDomain->wrangler->registerInterest( gIOGeneralInterest, &displayWranglerNotification, target, 0) ) {
1371 IOLog("IOPMrootDomain::displayWranglerPublished registerInterest failed\n");
1372 return false;
1373 }
1374
1375 return true;
1376 }
1377
1378 //*********************************************************************************
1379 // batteryLocationPublished
1380 //
1381 // Notification on AppleSMU publishing location of battery data
1382 //
1383 //*********************************************************************************
1384
1385 bool IOPMrootDomain::batteryLocationPublished( void * target, void * root_domain,
1386 IOService * resourceService )
1387 {
1388 IORegistryEntry *battery_location;
1389
1390 battery_location = (IORegistryEntry *) resourceService->getProperty("battery");
1391 if (!battery_location || !OSDynamicCast(IORegistryEntry, battery_location))
1392 return (true);
1393
1394 ((IOPMrootDomain *)root_domain)->setProperty("BatteryEntry", battery_location);
1395
1396 // rdar://2936060
1397 // All laptops have dimmable LCD displays
1398 // All laptops have batteries
1399 // So if this machine has a battery, publish the fact that the backlight
1400 // supports dimming.
1401 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
1402
1403 ((IOPMrootDomain *)root_domain)->announcePowerSourceChange();
1404 return (true);
1405 }
1406
1407
1408
1409 //*********************************************************************************
1410 // adjustPowerState
1411 //
1412 // Some condition that affects our wake/sleep/doze decision has changed.
1413 //
1414 // If the sleep slider is in the off position, we cannot sleep or doze.
1415 // If the enclosure is open, we cannot sleep or doze.
1416 // If the system is still booting, we cannot sleep or doze.
1417 //
1418 // In those circumstances, we prevent sleep and doze by holding power on with
1419 // changePowerStateToPriv(ON).
1420 //
1421 // If the above conditions do not exist, and also the sleep timer has expired, we
1422 // allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
1423 // changePowerStateToPriv(DOZE) depending on whether or not we already know the
1424 // platform cannot sleep.
1425 //
1426 // In this case, sleep or doze will either occur immediately or at the next time
1427 // that no children are holding the system out of idle sleep via the
1428 // kIOPMPreventIdleSleep flag in their power state arrays.
1429 //*********************************************************************************
1430
1431 void IOPMrootDomain::adjustPowerState( void )
1432 {
1433 if ( (sleepSlider == 0) ||
1434 ! allowSleep ||
1435 systemBooting ) {
1436 changePowerStateToPriv(ON_STATE);
1437 } else {
1438 if ( sleepASAP )
1439 {
1440 sleepASAP = false;
1441 if ( sleepIsSupported )
1442 {
1443 changePowerStateToPriv(SLEEP_STATE);
1444 } else {
1445 changePowerStateToPriv(DOZE_STATE);
1446 }
1447 }
1448 }
1449 }
1450
1451
1452 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1453
1454 #undef super
1455 #define super IOService
1456
1457 OSDefineMetaClassAndStructors(IORootParent, IOService)
1458
1459 // This array exactly parallels the state array for the root domain.
1460 // Power state changes initiated by a device can be vetoed by a client of the device, and
1461 // power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
1462 // so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
1463 // its parent to make the change. That is the reason for this complexity.
1464
1465 static IOPMPowerState patriarchPowerStates[number_of_power_states] = {
1466 {1,0,0,0,0,0,0,0,0,0,0,0}, // off
1467 {1,0,RESTART_POWER,0,0,0,0,0,0,0,0,0}, // reset
1468 {1,0,SLEEP_POWER,0,0,0,0,0,0,0,0,0}, // sleep
1469 {1,0,DOZE_POWER,0,0,0,0,0,0,0,0,0}, // doze
1470 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0} // running
1471 };
1472
1473 bool IORootParent::start ( IOService * nub )
1474 {
1475 mostRecentChange = ON_STATE;
1476 super::start(nub);
1477 PMinit();
1478 registerPowerDriver(this,patriarchPowerStates,number_of_power_states);
1479 powerOverrideOnPriv();
1480 return true;
1481 }
1482
1483
1484 void IORootParent::shutDownSystem ( void )
1485 {
1486 mostRecentChange = OFF_STATE;
1487 changePowerStateToPriv(OFF_STATE);
1488 }
1489
1490
1491 void IORootParent::restartSystem ( void )
1492 {
1493 mostRecentChange = RESTART_STATE;
1494 changePowerStateToPriv(RESTART_STATE);
1495 }
1496
1497
1498 void IORootParent::sleepSystem ( void )
1499 {
1500 mostRecentChange = SLEEP_STATE;
1501 changePowerStateToPriv(SLEEP_STATE);
1502 }
1503
1504
1505 void IORootParent::dozeSystem ( void )
1506 {
1507 mostRecentChange = DOZE_STATE;
1508 changePowerStateToPriv(DOZE_STATE);
1509 }
1510
1511 // Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
1512 // This brings the parent to doze, which allows the root to step up from sleep to doze.
1513
1514 // In idle sleep, do nothing because the parent is still on and the root can freely change state.
1515
1516 void IORootParent::sleepToDoze ( void )
1517 {
1518 if ( mostRecentChange == SLEEP_STATE ) {
1519 changePowerStateToPriv(DOZE_STATE);
1520 }
1521 }
1522
1523
1524 void IORootParent::wakeSystem ( void )
1525 {
1526 mostRecentChange = ON_STATE;
1527 changePowerStateToPriv(ON_STATE);
1528 }
1529