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