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