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