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