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