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