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