]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPMrootDomain.cpp
xnu-792.25.20.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
1 /*
2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 #include <IOKit/IOWorkLoop.h>
23 #include <IOKit/IOCommandGate.h>
24 #include <IOKit/IOTimerEventSource.h>
25 #include <IOKit/IOPlatformExpert.h>
26 #include <IOKit/IOKitDebug.h>
27 #include <IOKit/IOTimeStamp.h>
28 #include <IOKit/pwr_mgt/RootDomain.h>
29 #include <IOKit/pwr_mgt/IOPMPrivate.h>
30 #include <IOKit/IODeviceTreeSupport.h>
31 #include <IOKit/IOMessage.h>
32 #include <IOKit/IOReturn.h>
33 #include "RootDomainUserClient.h"
34 #include "IOKit/pwr_mgt/IOPowerConnection.h"
35 #include "IOPMPowerStateQueue.h"
36 #include <IOKit/IOCatalogue.h>
37 #include <IOKit/IOHibernatePrivate.h>
38 #include "IOPMWorkArbiter.h"
39
40 #ifdef __ppc__
41 #include <ppc/pms.h>
42 #endif
43
44 extern "C" {
45 IOReturn OSMetaClassSystemSleepOrWake( UInt32 );
46 }
47
48 extern const IORegistryPlane * gIOPowerPlane;
49
50 IOReturn broadcast_aggressiveness ( OSObject *, void *, void *, void *, void * );
51 static void sleepTimerExpired(thread_call_param_t);
52 static void wakeupClamshellTimerExpired ( thread_call_param_t us);
53
54 // "IOPMSetSleepSupported" callPlatformFunction name
55 static const OSSymbol *sleepSupportedPEFunction = NULL;
56
57 #define kIOSleepSupportedKey "IOSleepSupported"
58
59 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
60 | kIOPMSupportedOnBatt \
61 | kIOPMSupportedOnUPS)
62
63 #define number_of_power_states 5
64 #define OFF_STATE 0
65 #define RESTART_STATE 1
66 #define SLEEP_STATE 2
67 #define DOZE_STATE 3
68 #define ON_STATE 4
69
70 #define ON_POWER kIOPMPowerOn
71 #define RESTART_POWER kIOPMRestart
72 #define SLEEP_POWER kIOPMAuxPowerOn
73 #define DOZE_POWER kIOPMDoze
74
75 #define kLocalEvalClamshellCommand (1 << 15)
76
77 static IOPMPowerState ourPowerStates[number_of_power_states] = {
78 // state 0, off
79 {1,0, 0, 0,0,0,0,0,0,0,0,0},
80 // state 1, restart
81 {1,kIOPMRestartCapability, kIOPMRestart, RESTART_POWER,0,0,0,0,0,0,0,0},
82 // state 2, sleep
83 {1,kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER,0,0,0,0,0,0,0,0},
84 // state 3, doze
85 {1,kIOPMDoze, kIOPMDoze, DOZE_POWER,0,0,0,0,0,0,0,0},
86 // state 4, on
87 {1,kIOPMPowerOn, kIOPMPowerOn, ON_POWER,0,0,0,0,0,0,0,0},
88 };
89
90 static IOPMrootDomain * gRootDomain;
91 static UInt32 gSleepOrShutdownPending = 0;
92
93
94 class PMSettingObject : public OSObject
95 {
96 OSDeclareDefaultStructors(PMSettingObject)
97 private:
98 IOPMrootDomain *parent;
99 IOPMSettingControllerCallback func;
100 OSObject *target;
101 uintptr_t refcon;
102 uint32_t *publishedFeatureID;
103 int releaseAtCount;
104 public:
105 static PMSettingObject *pmSettingObject(
106 IOPMrootDomain *parent_arg,
107 IOPMSettingControllerCallback handler_arg,
108 OSObject *target_arg,
109 uintptr_t refcon_arg,
110 uint32_t supportedPowerSources,
111 const OSSymbol *settings[]);
112
113 void setPMSetting(const OSSymbol *type, OSObject *obj);
114
115 void taggedRelease(const void *tag, const int when) const;
116 void free(void);
117 };
118
119
120
121 #define super IOService
122 OSDefineMetaClassAndStructors(IOPMrootDomain,IOService)
123
124 extern "C"
125 {
126 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
127 {
128 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
129 }
130
131 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
132 {
133 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
134 }
135
136 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
137 {
138 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
139 }
140
141 IOReturn vetoSleepWakeNotification(void * PMrefcon)
142 {
143 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
144 }
145
146 IOReturn rootDomainRestart ( void )
147 {
148 return gRootDomain->restartSystem();
149 }
150
151 IOReturn rootDomainShutdown ( void )
152 {
153 return gRootDomain->shutdownSystem();
154 }
155
156 void IOSystemShutdownNotification ( void )
157 {
158 IOCatalogue::disableExternalLinker();
159 for ( int i = 0; i < 100; i++ )
160 {
161 if ( OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) ) break;
162 IOSleep( 100 );
163 }
164 }
165
166 int sync_internal(void);
167 }
168
169 /*
170 A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain
171 children it has, but within the constraint of the power state provided by its parent. The driver expresses its desire by
172 calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children
173 express their desires by calling requestPowerDomainState().
174
175 The Root Power Domain owns the policy for idle and demand sleep and doze for the system. It is a power-managed IOService just
176 like the others in the system. It implements several power states which correspond to what we see as Sleep, Doze, etc.
177
178 The sleep/doze policy is as follows:
179 Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards.
180 Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero.
181 The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep.
182
183 These three conditions are enforced using the "driver clamp" by calling changePowerStateTo(). For example, if the case is
184 opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or
185 the state of the other clamp.
186
187 Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item.
188 In this case the root's parent actually initiates the power state change so that the root has no choice and does not give
189 applications the opportunity to veto the change.
190
191 Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep. When this is true, the root's
192 children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE)
193 to hold itself on until the sleep timer expires. This timer is set for the difference between the sleep timeout slider and
194 the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel. For example, if
195 the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes,
196 when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root
197 sets its timer for 25 minutes (30 - 5). When the timer expires, it releases its clamp and now nothing is holding it awake,
198 so it falls asleep.
199
200 Demand sleep is prevented when the system is booting. When preferences are transmitted by the loginwindow at the end of
201 boot, a flag is cleared, and this allows subsequent Demand Sleep.
202
203 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
204 a clamp, but sets a flag which is noticed before actually sleeping the kernel. If the flag is set, the root steps up
205 one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and
206 ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler
207 to be tickled)).
208 */
209
210 // **********************************************************************************
211
212 IOPMrootDomain * IOPMrootDomain::construct( void )
213 {
214 IOPMrootDomain *root;
215
216 root = new IOPMrootDomain;
217 if( root)
218 root->init();
219
220 return( root );
221 }
222
223 // **********************************************************************************
224
225 static void disk_sync_callout(thread_call_param_t p0, thread_call_param_t p1)
226 {
227 IOService *rootDomain = (IOService *) p0;
228 unsigned long pmRef = (unsigned long) p1;
229
230 IOHibernateSystemSleep();
231 sync_internal();
232 rootDomain->allowPowerChange(pmRef);
233 }
234
235 // **********************************************************************************
236 IOPMWorkArbiter *IOPMrootDomain::getPMArbiter(void)
237 {
238 return pmArbiter;
239 }
240
241
242 // **********************************************************************************
243 // start
244 //
245 // We don't do much here. The real initialization occurs when the platform
246 // expert informs us we are the root.
247 // **********************************************************************************
248
249 #define kRootDomainSettingsCount 13
250
251 bool IOPMrootDomain::start ( IOService * nub )
252 {
253 OSIterator *psIterator;
254 OSDictionary *tmpDict;
255 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
256 {
257 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
258 OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey),
259 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
260 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey),
261 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
262 OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey),
263 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
264 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
265 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
266 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
267 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
268 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
269 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey)
270 };
271
272
273 pmPowerStateQueue = 0;
274
275 _reserved = (ExpansionData *)IOMalloc(sizeof(ExpansionData));
276 if(!_reserved) return false;
277
278 super::start(nub);
279
280 gRootDomain = this;
281
282 PMinit();
283
284 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
285 canSleep = true;
286 setProperty(kIOSleepSupportedKey,true);
287
288 allowSleep = true;
289 sleepIsSupported = true;
290 systemBooting = true;
291 sleepSlider = 0;
292 idleSleepPending = false;
293 wrangler = NULL;
294 sleepASAP = false;
295 clamshellIsClosed = false;
296 clamshellExists = false;
297 ignoringClamshell = true;
298 ignoringClamshellDuringWakeup = false;
299 acAdaptorConnect = true;
300
301 tmpDict = OSDictionary::withCapacity(1);
302 setProperty(kRootDomainSupportedFeatures, tmpDict);
303 tmpDict->release();
304
305 settingsCallbacks = OSDictionary::withCapacity(1);
306
307 // Create a list of the valid PM settings that we'll relay to
308 // interested clients in setProperties() => setPMSetting()
309 allowedPMSettings = OSArray::withObjects(
310 (const OSObject **)settingsArr,
311 kRootDomainSettingsCount,
312 0);
313
314 fPMSettingsDict = OSDictionary::withCapacity(5);
315
316 pm_vars->PMworkloop = IOWorkLoop::workLoop();
317 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(this);
318 pm_vars->PMworkloop->addEventSource(pmPowerStateQueue);
319
320 /* Initialize PM arbiter */
321 pmArbiter = IOPMWorkArbiter::pmWorkArbiter(this);
322 arbiterWorkLoop = IOWorkLoop::workLoop();
323 arbiterWorkLoop->addEventSource(pmArbiter);
324
325 featuresDictLock = IOLockAlloc();
326 settingsCtrlLock = IORecursiveLockAlloc();
327
328 extraSleepTimer = thread_call_allocate(
329 (thread_call_func_t)sleepTimerExpired,
330 (thread_call_param_t) this);
331 clamshellWakeupIgnore = thread_call_allocate(
332 (thread_call_func_t)wakeupClamshellTimerExpired,
333 (thread_call_param_t) this);
334 diskSyncCalloutEntry = thread_call_allocate(
335 &disk_sync_callout,
336 (thread_call_param_t) this);
337
338 // create our parent
339 patriarch = new IORootParent;
340 patriarch->init();
341 patriarch->attach(this);
342 patriarch->start(this);
343 patriarch->youAreRoot();
344 patriarch->wakeSystem();
345 patriarch->addPowerChild(this);
346
347 registerPowerDriver(this,ourPowerStates,number_of_power_states);
348
349 setPMRootDomain(this);
350 // set a clamp until we sleep
351 changePowerStateToPriv(ON_STATE);
352
353 // install power change handler
354 registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
355
356 // Register for a notification when IODisplayWrangler is published
357 _displayWranglerNotifier = addNotification(
358 gIOPublishNotification, serviceMatching("IODisplayWrangler"),
359 &displayWranglerPublished, this, 0);
360
361 // Battery location published - ApplePMU support only
362 _batteryPublishNotifier = addNotification(
363 gIOPublishNotification, serviceMatching("IOPMPowerSource"),
364 &batteryPublished, this, this);
365
366
367 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
368 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
369 ucClassName->release();
370
371 // IOBacklightDisplay can take a long time to load at boot, or it may
372 // not load at all if you're booting with clamshell closed. We publish
373 // 'DisplayDims' here redundantly to get it published early and at all.
374 psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") );
375 if( psIterator && psIterator->getNextObject() )
376 {
377 // There's at least one battery on the system, so we publish
378 // 'DisplayDims' support for the LCD.
379 publishFeature("DisplayDims");
380 }
381 if(psIterator) {
382 psIterator->release();
383 }
384
385 IOHibernateSystemInit(this);
386
387 registerService(); // let clients find us
388
389 return true;
390 }
391
392 // **********************************************************************************
393 // setProperties
394 //
395 // Receive a setProperty call
396 // The "System Boot" property means the system is completely booted.
397 // **********************************************************************************
398 IOReturn IOPMrootDomain::setProperties ( OSObject *props_obj)
399 {
400 IOReturn return_value = kIOReturnSuccess;
401 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
402 OSBoolean *b;
403 OSNumber *n;
404 OSString *str;
405 OSSymbol *type;
406 OSObject *obj;
407 unsigned int i;
408
409 const OSSymbol *boot_complete_string =
410 OSSymbol::withCString("System Boot Complete");
411 const OSSymbol *sys_shutdown_string =
412 OSSymbol::withCString("System Shutdown");
413 const OSSymbol *stall_halt_string =
414 OSSymbol::withCString("StallSystemAtHalt");
415 const OSSymbol *hibernatemode_string =
416 OSSymbol::withCString(kIOHibernateModeKey);
417 const OSSymbol *hibernatefile_string =
418 OSSymbol::withCString(kIOHibernateFileKey);
419 const OSSymbol *hibernatefreeratio_string =
420 OSSymbol::withCString(kIOHibernateFreeRatioKey);
421 const OSSymbol *hibernatefreetime_string =
422 OSSymbol::withCString(kIOHibernateFreeTimeKey);
423
424 if(!dict)
425 {
426 return_value = kIOReturnBadArgument;
427 goto exit;
428 }
429
430 if( systemBooting
431 && boot_complete_string
432 && dict->getObject(boot_complete_string))
433 {
434 systemBooting = false;
435 adjustPowerState();
436
437 // If lid is closed, re-send lid closed notification
438 // now that booting is complete.
439 if( clamshellIsClosed )
440 {
441 this->receivePowerNotification(kLocalEvalClamshellCommand);
442 }
443 }
444
445 if( sys_shutdown_string
446 && (b = OSDynamicCast(OSBoolean, dict->getObject(sys_shutdown_string))))
447 {
448
449 if(kOSBooleanTrue == b)
450 {
451 /* We set systemShutdown = true during shutdown
452 to prevent sleep at unexpected times while loginwindow is trying
453 to shutdown apps and while the OS is trying to transition to
454 complete power of.
455
456 Set to true during shutdown, as soon as loginwindow shows
457 the "shutdown countdown dialog", through individual app
458 termination, and through black screen kernel shutdown.
459 */
460 kprintf("systemShutdown true\n");
461 systemShutdown = true;
462 } else {
463 /*
464 A shutdown was initiated, but then the shutdown
465 was cancelled, clearing systemShutdown to false here.
466 */
467 kprintf("systemShutdown false\n");
468 systemShutdown = false;
469 }
470 }
471
472 if( stall_halt_string
473 && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) )
474 {
475 setProperty(stall_halt_string, b);
476 }
477
478 if ( hibernatemode_string
479 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string))))
480 {
481 setProperty(hibernatemode_string, n);
482 }
483 if ( hibernatefreeratio_string
484 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string))))
485 {
486 setProperty(hibernatefreeratio_string, n);
487 }
488 if ( hibernatefreetime_string
489 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string))))
490 {
491 setProperty(hibernatefreetime_string, n);
492 }
493 if ( hibernatefile_string
494 && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string))))
495 {
496 setProperty(hibernatefile_string, str);
497 }
498
499 // Relay our allowed PM settings onto our registered PM clients
500 for(i = 0; i < allowedPMSettings->getCount(); i++) {
501
502 type = (OSSymbol *)allowedPMSettings->getObject(i);
503 if(!type) continue;
504
505 obj = dict->getObject(type);
506 if(!obj) continue;
507
508 return_value = setPMSetting(type, obj);
509
510 if(kIOReturnSuccess != return_value) goto exit;
511 }
512
513 exit:
514 if(boot_complete_string) boot_complete_string->release();
515 if(stall_halt_string) stall_halt_string->release();
516 return return_value;
517 }
518
519
520 //*********************************************************************************
521 // youAreRoot
522 //
523 // Power Managment is informing us that we are the root power domain.
524 // We know we are not the root however, since we have just instantiated a parent
525 // for ourselves and made it the root. We override this method so it will have
526 // no effect
527 //*********************************************************************************
528 IOReturn IOPMrootDomain::youAreRoot ( void )
529 {
530 return IOPMNoErr;
531 }
532
533 // **********************************************************************************
534 // command_received
535 //
536 // No longer used
537 // **********************************************************************************
538 void IOPMrootDomain::command_received ( void * w, void * x, void * y, void * z )
539 {
540 super::command_received(w,x,y,z);
541 }
542
543
544 // **********************************************************************************
545 // broadcast_aggressiveness
546 //
547 // **********************************************************************************
548 IOReturn broadcast_aggressiveness ( OSObject * root, void * x, void * y, void *, void * )
549 {
550 ((IOPMrootDomain *)root)->broadcast_it((unsigned long)x,(unsigned long)y);
551 return IOPMNoErr;
552 }
553
554
555 // **********************************************************************************
556 // broadcast_it
557 //
558 // We are behind the command gate to broadcast an aggressiveness factor. We let the
559 // superclass do it, but we need to snoop on factors that affect idle sleep.
560 // **********************************************************************************
561 void IOPMrootDomain::broadcast_it (unsigned long type, unsigned long value)
562 {
563 super::setAggressiveness(type,value);
564
565 // Save user's spin down timer to restore after we replace it for idle sleep
566 if( type == kPMMinutesToSpinDown ) user_spindown = value;
567
568 // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer
569 longestNonSleepSlider = pm_vars->current_aggressiveness_values[kPMMinutesToDim];
570
571
572 if ( type == kPMMinutesToSleep ) {
573 if ( (sleepSlider == 0) && (value != 0) ) {
574 sleepSlider = value;
575 // idle sleep is now enabled, maybe sleep now
576 adjustPowerState();
577 }
578 sleepSlider = value;
579 if ( sleepSlider == 0 ) {
580 // idle sleep is now disabled
581 adjustPowerState();
582 // make sure we're powered
583 patriarch->wakeSystem();
584 }
585 }
586 if ( sleepSlider > longestNonSleepSlider ) {
587 extraSleepDelay = sleepSlider - longestNonSleepSlider ;
588 }
589 else {
590 extraSleepDelay = 0;
591 }
592 }
593
594
595 // **********************************************************************************
596 // sleepTimerExpired
597 //
598 // **********************************************************************************
599 static void sleepTimerExpired ( thread_call_param_t us)
600 {
601 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
602 }
603
604
605 static void wakeupClamshellTimerExpired ( thread_call_param_t us)
606 {
607 ((IOPMrootDomain *)us)->stopIgnoringClamshellEventsDuringWakeup();
608 }
609
610
611 // **********************************************************************************
612 // handleSleepTimerExpiration
613 //
614 // The time between the sleep idle timeout and the next longest one has elapsed.
615 // It's time to sleep. Start that by removing the clamp that's holding us awake.
616 // **********************************************************************************
617 void IOPMrootDomain::handleSleepTimerExpiration ( void )
618 {
619 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
620 if(0 != user_spindown)
621 setQuickSpinDownTimeout();
622
623 sleepASAP = true;
624 adjustPowerState();
625 }
626
627
628 void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void)
629 {
630 // Allow clamshell-induced sleep now
631 ignoringClamshellDuringWakeup = false;
632
633 // Re-send clamshell event, in case it causes a sleep
634 if(clamshellIsClosed)
635 this->receivePowerNotification( kLocalEvalClamshellCommand );
636 }
637
638 //*********************************************************************************
639 // setAggressiveness
640 //
641 // Some aggressiveness factor has changed. We broadcast it to the hierarchy while on
642 // the Power Mangement workloop thread. This enables objects in the
643 // hierarchy to successfully alter their idle timers, which are all on the
644 // same thread.
645 //*********************************************************************************
646
647 static int pmsallsetup = 0;
648
649 IOReturn IOPMrootDomain::setAggressiveness ( unsigned long type, unsigned long newLevel )
650 {
651 #ifdef __ppc__
652 if(pmsExperimental & 3) kprintf("setAggressiveness: type = %08X, newlevel = %08X\n", type, newLevel);
653 if(pmsExperimental & 1) { /* Is experimental mode enabled? */
654 if(pmsInstalled && (type == kPMSetProcessorSpeed)) { /* We want to look at all processor speed changes if stepper is installed */
655 if(pmsallsetup) return kIOReturnSuccess; /* If already running, just eat this */
656 kprintf("setAggressiveness: starting stepper...\n");
657 pmsallsetup = 1; /* Remember we did this */
658 pmsPark();
659 pmsStart(); /* Get it all started up... */
660 return kIOReturnSuccess; /* Leave now... */
661 }
662 }
663 #endif
664
665 if ( pm_vars->PMcommandGate ) {
666 pm_vars->PMcommandGate->runAction(broadcast_aggressiveness,(void *)type,(void *)newLevel);
667 }
668
669 return kIOReturnSuccess;
670 }
671
672
673 // **********************************************************************************
674 // sleepSystem
675 //
676 // **********************************************************************************
677 IOReturn IOPMrootDomain::sleepSystem ( void )
678 {
679 if(systemShutdown) {
680 kprintf("Preventing system sleep on grounds of systemShutdown.\n");
681 }
682
683 if ( !systemBooting && !systemShutdown && allowSleep ) {
684 if ( !sleepIsSupported )
685 setSleepSupported( kPCICantSleep );
686
687 patriarch->sleepSystem();
688 return kIOReturnSuccess;
689 }
690 return kIOReturnError;
691 }
692
693
694 // **********************************************************************************
695 // shutdownSystem
696 //
697 // **********************************************************************************
698 IOReturn IOPMrootDomain::shutdownSystem ( void )
699 {
700 //patriarch->shutDownSystem();
701 return kIOReturnUnsupported;
702 }
703
704
705 // **********************************************************************************
706 // restartSystem
707 //
708 // **********************************************************************************
709 IOReturn IOPMrootDomain::restartSystem ( void )
710 {
711 //patriarch->restartSystem();
712 return kIOReturnUnsupported;
713 }
714
715
716 // **********************************************************************************
717 // powerChangeDone
718 //
719 // This overrides powerChangeDone in IOService.
720 //
721 // Finder sleep and idle sleep move us from the ON state to the SLEEP_STATE.
722 // In this case:
723 // If we just finished going to the SLEEP_STATE, and the platform is capable of true sleep,
724 // sleep the kernel. Otherwise switch up to the DOZE_STATE which will keep almost
725 // everything as off as it can get.
726 //
727 // **********************************************************************************
728 void IOPMrootDomain::powerChangeDone ( unsigned long previousState )
729 {
730 OSNumber * propertyPtr;
731 unsigned short theProperty;
732 AbsoluteTime deadline;
733
734 switch ( pm_vars->myCurrentState ) {
735 case SLEEP_STATE:
736 if ( canSleep && sleepIsSupported )
737 {
738 // re-enable this timer for next sleep
739 idleSleepPending = false;
740
741 IOLog("System %sSleep\n", gIOHibernateState ? "Safe" : "");
742
743 IOHibernateSystemHasSlept();
744
745 pm_vars->thePlatform->sleepKernel();
746
747 // The CPU(s) are off at this point. When they're awakened by CPU interrupt,
748 // code will resume execution here.
749
750 // Now we're waking...
751 IOHibernateSystemWake();
752
753 // stay awake for at least 30 seconds
754 clock_interval_to_deadline(30, kSecondScale, &deadline);
755 thread_call_enter_delayed(extraSleepTimer, deadline);
756 // this gets turned off when we sleep again
757 idleSleepPending = true;
758
759 // Ignore closed clamshell during wakeup and for a few seconds
760 // after wakeup is complete
761 ignoringClamshellDuringWakeup = true;
762
763 // sleep transition complete
764 gSleepOrShutdownPending = 0;
765
766 // trip the reset of the calendar clock
767 clock_wakeup_calendar();
768
769 // get us some power
770 patriarch->wakeSystem();
771
772 // early stage wake notification
773 tellClients(kIOMessageSystemWillPowerOn);
774
775 // tell the tree we're waking
776 IOLog("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
777 systemWake();
778
779 // Allow drivers to request extra processing time before clamshell
780 // sleep if kIOREMSleepEnabledKey is present.
781 // Ignore clamshell events for at least 5 seconds
782 if(getProperty(kIOREMSleepEnabledKey)) {
783 // clamshellWakeupIgnore callout clears ignoreClamshellDuringWakeup bit
784 clock_interval_to_deadline(5, kSecondScale, &deadline);
785 if(clamshellWakeupIgnore) {
786 thread_call_enter_delayed(clamshellWakeupIgnore, deadline);
787 }
788 } else ignoringClamshellDuringWakeup = false;
789
790 // Find out what woke us
791 propertyPtr = OSDynamicCast(OSNumber,getProperty("WakeEvent"));
792 if ( propertyPtr ) {
793 theProperty = propertyPtr->unsigned16BitValue();
794 IOLog("Wake event %04x\n",theProperty);
795 if ( (theProperty & 0x0008) || //lid
796 (theProperty & 0x0800) || // front panel button
797 (theProperty & 0x0020) || // external keyboard
798 (theProperty & 0x0001) ) { // internal keyboard
799 // We've identified the wakeup event as UI driven
800 reportUserInput();
801 }
802 } else {
803 // Since we can't identify the wakeup event, treat it as UI activity
804 reportUserInput();
805 }
806
807 // Wake for thirty seconds
808 changePowerStateToPriv(ON_STATE);
809 powerOverrideOffPriv();
810 } else {
811 // allow us to step up a power state
812 patriarch->sleepToDoze();
813 // and do it
814 changePowerStateToPriv(DOZE_STATE);
815 }
816 break;
817
818 case DOZE_STATE:
819 if ( previousState != DOZE_STATE )
820 {
821 IOLog("System Doze\n");
822 }
823 // re-enable this timer for next sleep
824 idleSleepPending = false;
825 gSleepOrShutdownPending = 0;
826 break;
827
828 case RESTART_STATE:
829 IOLog("System Restart\n");
830 PEHaltRestart(kPERestartCPU);
831 break;
832
833 case OFF_STATE:
834 IOLog("System Halt\n");
835 PEHaltRestart(kPEHaltCPU);
836 break;
837 }
838 }
839
840
841 // **********************************************************************************
842 // wakeFromDoze
843 //
844 // The Display Wrangler calls here when it switches to its highest state. If the
845 // system is currently dozing, allow it to wake by making sure the parent is
846 // providing power.
847 // **********************************************************************************
848 void IOPMrootDomain::wakeFromDoze( void )
849 {
850 if ( pm_vars->myCurrentState == DOZE_STATE )
851 {
852 // Reset sleep support till next sleep attempt.
853 // A machine's support of sleep vs. doze can change over the course of
854 // a running system, so we recalculate it before every sleep.
855 setSleepSupported(0);
856
857 powerOverrideOffPriv();
858
859 // early wake notification
860 tellClients(kIOMessageSystemWillPowerOn);
861
862 // allow us to wake if children so desire
863 patriarch->wakeSystem();
864 }
865 }
866
867
868 // *****************************************************************************
869 // publishFeature
870 //
871 // Adds a new feature to the supported features dictionary
872 //
873 //
874 // *****************************************************************************
875 void IOPMrootDomain::publishFeature( const char * feature )
876 {
877 publishFeature(feature, kIOPMSupportedOnAC
878 | kIOPMSupportedOnBatt
879 | kIOPMSupportedOnUPS,
880 NULL);
881 return;
882 }
883
884
885 // *****************************************************************************
886 // publishFeature (with supported power source specified)
887 //
888 // Adds a new feature to the supported features dictionary
889 //
890 //
891 // *****************************************************************************
892 void IOPMrootDomain::publishFeature(
893 const char *feature,
894 uint32_t supportedWhere,
895 uint32_t *uniqueFeatureID)
896 {
897 static uint16_t next_feature_id = 500;
898
899 OSNumber *new_feature_data = NULL;
900 OSNumber *existing_feature = NULL;
901 OSArray *existing_feature_arr = NULL;
902 OSObject *osObj = NULL;
903 uint32_t feature_value = 0;
904
905 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
906
907 if(!supportedWhere) {
908 // Feature isn't supported anywhere!
909 return;
910 }
911
912 if(next_feature_id > 5000) {
913 // Far, far too many features!
914 return;
915 }
916
917 if(featuresDictLock) IOLockLock(featuresDictLock);
918
919 OSDictionary *features =
920 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
921
922 // Create new features dict if necessary
923 if ( features && OSDynamicCast(OSDictionary, features)) {
924 features = OSDictionary::withDictionary(features);
925 } else {
926 features = OSDictionary::withCapacity(1);
927 }
928
929 // Create OSNumber to track new feature
930
931 next_feature_id += 1;
932 if( uniqueFeatureID ) {
933 // We don't really mind if the calling kext didn't give us a place
934 // to stash their unique id. Many kexts don't plan to unload, and thus
935 // have no need to remove themselves later.
936 *uniqueFeatureID = next_feature_id;
937 }
938
939 feature_value = supportedWhere + (next_feature_id << 16);
940 new_feature_data = OSNumber::withNumber(
941 (unsigned long long)feature_value, 32);
942
943 // Does features object already exist?
944 if( (osObj = features->getObject(feature)) )
945 {
946 if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
947 {
948 // We need to create an OSArray to hold the now 2 elements.
949 existing_feature_arr = OSArray::withObjects(
950 (const OSObject **)&existing_feature, 1, 2);
951 existing_feature_arr->setObject(new_feature_data);
952 features->setObject(feature, existing_feature_arr);
953 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
954 {
955 // Add object to existing array
956 existing_feature_arr->setObject(new_feature_data);
957 }
958 } else {
959 // The easy case: no previously existing features listed. We simply
960 // set the OSNumber at key 'feature' and we're on our way.
961 features->setObject(feature, new_feature_data);
962 }
963
964 new_feature_data->release();
965
966 setProperty(kRootDomainSupportedFeatures, features);
967
968 features->release();
969
970 // Notify EnergySaver and all those in user space so they might
971 // re-populate their feature specific UI
972 messageClients(kIOPMMessageFeatureChange, this);
973
974 if(featuresDictLock) IOLockUnlock(featuresDictLock);
975 }
976
977 // *****************************************************************************
978 // removePublishedFeature
979 //
980 // Removes previously published feature
981 //
982 //
983 // *****************************************************************************
984 IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
985 {
986 IOReturn ret = kIOReturnError;
987 uint32_t feature_value = 0;
988 uint16_t feature_id = 0;
989 bool madeAChange = false;
990
991 OSSymbol *dictKey = NULL;
992 OSCollectionIterator *dictIterator = NULL;
993 OSArray *arrayMember = NULL;
994 OSNumber *numberMember = NULL;
995 OSObject *osObj = NULL;
996 OSNumber *osNum = NULL;
997
998 if(featuresDictLock) IOLockLock(featuresDictLock);
999
1000 OSDictionary *features =
1001 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
1002
1003 if ( features && OSDynamicCast(OSDictionary, features) )
1004 {
1005 // Any modifications to the dictionary are made to the copy to prevent
1006 // races & crashes with userland clients. Dictionary updated
1007 // automically later.
1008 features = OSDictionary::withDictionary(features);
1009 } else {
1010 features = NULL;
1011 ret = kIOReturnNotFound;
1012 goto exit;
1013 }
1014
1015 // We iterate 'features' dictionary looking for an entry tagged
1016 // with 'removeFeatureID'. If found, we remove it from our tracking
1017 // structures and notify the OS via a general interest message.
1018
1019 dictIterator = OSCollectionIterator::withCollection(features);
1020 if(!dictIterator) {
1021 goto exit;
1022 }
1023
1024 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
1025 {
1026 osObj = features->getObject(dictKey);
1027
1028 // Each Feature is either tracked by an OSNumber
1029 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
1030 {
1031 feature_value = numberMember->unsigned32BitValue();
1032 feature_id = (uint16_t)(feature_value >> 16);
1033
1034 if( feature_id == (uint16_t)removeFeatureID )
1035 {
1036 // Remove this node
1037 features->removeObject(dictKey);
1038 madeAChange = true;
1039 break;
1040 }
1041
1042 // Or tracked by an OSArray of OSNumbers
1043 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
1044 {
1045 unsigned int arrayCount = arrayMember->getCount();
1046
1047 for(unsigned int i=0; i<arrayCount; i++)
1048 {
1049 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
1050 if(!osNum) {
1051 continue;
1052 }
1053
1054 feature_value = osNum->unsigned32BitValue();
1055 feature_id = (uint16_t)(feature_value >> 16);
1056
1057 if( feature_id == (uint16_t)removeFeatureID )
1058 {
1059 // Remove this node
1060 if( 1 == arrayCount ) {
1061 // If the array only contains one element, remove
1062 // the whole thing.
1063 features->removeObject(dictKey);
1064 } else {
1065 // Otherwise just remove the element in question.
1066 arrayMember->removeObject(i);
1067 }
1068
1069 madeAChange = true;
1070 break;
1071 }
1072 }
1073 }
1074 }
1075
1076
1077 dictIterator->release();
1078
1079 if( madeAChange )
1080 {
1081 ret = kIOReturnSuccess;
1082
1083 setProperty(kRootDomainSupportedFeatures, features);
1084
1085 // Notify EnergySaver and all those in user space so they might
1086 // re-populate their feature specific UI
1087 messageClients(kIOPMMessageFeatureChange, this);
1088 } else {
1089 ret = kIOReturnNotFound;
1090 }
1091
1092 exit:
1093 if(features) features->release();
1094 if(featuresDictLock) IOLockUnlock(featuresDictLock);
1095 return ret;
1096 }
1097
1098
1099 // **********************************************************************************
1100 // unIdleDevice
1101 //
1102 // Enqueues unidle event to be performed later in a serialized context.
1103 //
1104 // **********************************************************************************
1105 void IOPMrootDomain::unIdleDevice( IOService *theDevice, unsigned long theState )
1106 {
1107 if(pmPowerStateQueue)
1108 pmPowerStateQueue->unIdleOccurred(theDevice, theState);
1109 }
1110
1111 // **********************************************************************************
1112 // announcePowerSourceChange
1113 //
1114 // Notifies "interested parties" that the batteries have changed state
1115 //
1116 // **********************************************************************************
1117 void IOPMrootDomain::announcePowerSourceChange( void )
1118 {
1119 IORegistryEntry *_batteryRegEntry = (IORegistryEntry *) getProperty("BatteryEntry");
1120
1121 // (if possible) re-publish power source state under IOPMrootDomain;
1122 // only do so if the battery controller publishes an IOResource
1123 // defining battery location. Called from ApplePMU battery driver.
1124
1125 if(_batteryRegEntry)
1126 {
1127 OSArray *batt_info;
1128 batt_info = (OSArray *) _batteryRegEntry->getProperty(kIOBatteryInfoKey);
1129 if(batt_info)
1130 setProperty(kIOBatteryInfoKey, batt_info);
1131 }
1132
1133 }
1134
1135
1136 // *****************************************************************************
1137 // setPMSetting (private)
1138 //
1139 // Internal helper to relay PM settings changes from user space to individual
1140 // drivers. Should be called only by IOPMrootDomain::setProperties.
1141 //
1142 // *****************************************************************************
1143 IOReturn IOPMrootDomain::setPMSetting(
1144 const OSSymbol *type,
1145 OSObject *obj)
1146 {
1147 OSArray *arr = NULL;
1148 PMSettingObject *p_obj = NULL;
1149 int count;
1150 int i;
1151
1152 if(NULL == type) return kIOReturnBadArgument;
1153
1154 IORecursiveLockLock(settingsCtrlLock);
1155
1156 fPMSettingsDict->setObject(type, obj);
1157
1158 arr = (OSArray *)settingsCallbacks->getObject(type);
1159 if(NULL == arr) goto exit;
1160 count = arr->getCount();
1161 for(i=0; i<count; i++) {
1162 p_obj = (PMSettingObject *)OSDynamicCast(PMSettingObject, arr->getObject(i));
1163 if(p_obj) p_obj->setPMSetting(type, obj);
1164 }
1165
1166 exit:
1167 IORecursiveLockUnlock(settingsCtrlLock);
1168 return kIOReturnSuccess;
1169 }
1170
1171 // *****************************************************************************
1172 // copyPMSetting (public)
1173 //
1174 // Allows kexts to safely read setting values, without being subscribed to
1175 // notifications.
1176 //
1177 // *****************************************************************************
1178 OSObject * IOPMrootDomain::copyPMSetting(
1179 OSSymbol *whichSetting)
1180 {
1181 OSObject *obj = NULL;
1182
1183 if(!whichSetting) return NULL;
1184
1185 IORecursiveLockLock(settingsCtrlLock);
1186 obj = fPMSettingsDict->getObject(whichSetting);
1187 if(obj) {
1188 obj->retain();
1189 }
1190 IORecursiveLockUnlock(settingsCtrlLock);
1191
1192 return obj;
1193 }
1194
1195 // *****************************************************************************
1196 // registerPMSettingController (public)
1197 //
1198 // direct wrapper to registerPMSettingController with uint32_t power source arg
1199 // *****************************************************************************
1200 IOReturn IOPMrootDomain::registerPMSettingController(
1201 const OSSymbol * settings[],
1202 IOPMSettingControllerCallback func,
1203 OSObject *target,
1204 uintptr_t refcon,
1205 OSObject **handle)
1206 {
1207 return registerPMSettingController(
1208 settings,
1209 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
1210 func, target, refcon, handle);
1211 }
1212
1213 // *****************************************************************************
1214 // registerPMSettingController (public)
1215 //
1216 // Kexts may register for notifications when a particular setting is changed.
1217 // A list of settings is available in IOPM.h.
1218 // Arguments:
1219 // * settings - An OSArray containing OSSymbols. Caller should populate this
1220 // array with a list of settings caller wants notifications from.
1221 // * func - A C function callback of the type IOPMSettingControllerCallback
1222 // * target - caller may provide an OSObject *, which PM will pass as an
1223 // target to calls to "func"
1224 // * refcon - caller may provide an void *, which PM will pass as an
1225 // argument to calls to "func"
1226 // * handle - This is a return argument. We will populate this pointer upon
1227 // call success. Hold onto this and pass this argument to
1228 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
1229 // Returns:
1230 // kIOReturnSuccess on success
1231 // *****************************************************************************
1232 IOReturn IOPMrootDomain::registerPMSettingController(
1233 const OSSymbol * settings[],
1234 uint32_t supportedPowerSources,
1235 IOPMSettingControllerCallback func,
1236 OSObject *target,
1237 uintptr_t refcon,
1238 OSObject **handle)
1239 {
1240 PMSettingObject *pmso = NULL;
1241 OSArray *list = NULL;
1242 IOReturn ret = kIOReturnSuccess;
1243 int i;
1244
1245 if( NULL == settings ||
1246 NULL == func ||
1247 NULL == handle)
1248 {
1249 return kIOReturnBadArgument;
1250 }
1251
1252
1253 pmso = PMSettingObject::pmSettingObject(
1254 (IOPMrootDomain *)this, func, target,
1255 refcon, supportedPowerSources, settings);
1256
1257 if(!pmso) {
1258 ret = kIOReturnInternalError;
1259 goto bail_no_unlock;
1260 }
1261
1262 IORecursiveLockLock(settingsCtrlLock);
1263 for(i=0; settings[i]; i++)
1264 {
1265 list = (OSArray *)settingsCallbacks->getObject(settings[i]);
1266 if(!list) {
1267 // New array of callbacks for this setting
1268 list = OSArray::withCapacity(1);
1269 settingsCallbacks->setObject(settings[i], list);
1270 list->release();
1271 }
1272
1273 // Add caller to the callback list
1274 list->setObject(pmso);
1275 }
1276
1277 ret = kIOReturnSuccess;
1278
1279 // Track this instance by its OSData ptr from now on
1280 *handle = pmso;
1281
1282 IORecursiveLockUnlock(settingsCtrlLock);
1283
1284 bail_no_unlock:
1285 if(kIOReturnSuccess != ret)
1286 {
1287 // Error return case
1288 if(pmso) pmso->release();
1289 if(handle) *handle = NULL;
1290 }
1291 return ret;
1292 }
1293
1294 //******************************************************************************
1295 // sleepOnClamshellClosed
1296 //
1297 // contains the logic to determine if the system should sleep when the clamshell
1298 // is closed.
1299 //******************************************************************************
1300
1301 bool IOPMrootDomain::shouldSleepOnClamshellClosed ( void )
1302 {
1303 return ( !ignoringClamshell
1304 && !ignoringClamshellDuringWakeup
1305 && !(desktopMode && acAdaptorConnect) );
1306 }
1307
1308 void IOPMrootDomain::sendClientClamshellNotification ( void )
1309 {
1310 /* Only broadcast clamshell alert if clamshell exists. */
1311 if(!clamshellExists)
1312 return;
1313
1314 setProperty(kAppleClamshellStateKey,
1315 clamshellIsClosed ? kOSBooleanTrue : kOSBooleanFalse);
1316
1317 setProperty(kAppleClamshellCausesSleepKey,
1318 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
1319
1320
1321 /* Argument to message is a bitfield of
1322 * ( kClamshellStateBit | kClamshellSleepBit )
1323 * Carry on the clamshell state change notification from an
1324 * independent thread.
1325 */
1326 pmArbiter->clamshellStateChangeOccurred(
1327 (uint32_t) ( (clamshellIsClosed ? kClamshellStateBit : 0)
1328 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)));
1329 }
1330
1331 //******************************************************************************
1332 // receivePowerNotification
1333 //
1334 // The power controller is notifying us of a hardware-related power management
1335 // event that we must handle. This is a result of an 'environment' interrupt from
1336 // the power mgt micro.
1337 //******************************************************************************
1338
1339 IOReturn IOPMrootDomain::receivePowerNotification (UInt32 msg)
1340 {
1341 bool eval_clamshell = false;
1342
1343 /*
1344 * Local (IOPMrootDomain only) eval clamshell command
1345 */
1346 if (msg & kLocalEvalClamshellCommand)
1347 {
1348 eval_clamshell = true;
1349 }
1350
1351 /*
1352 * Overtemp
1353 */
1354 if (msg & kIOPMOverTemp)
1355 {
1356 IOLog("PowerManagement emergency overtemp signal. Going to sleep!");
1357 (void) sleepSystem ();
1358 }
1359
1360 /*
1361 * PMU Processor Speed Change
1362 */
1363 if (msg & kIOPMProcessorSpeedChange)
1364 {
1365 IOService *pmu = waitForService(serviceMatching("ApplePMU"));
1366 pmu->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
1367 pm_vars->thePlatform->sleepKernel();
1368 pmu->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
1369 }
1370
1371 /*
1372 * Sleep Now!
1373 */
1374 if (msg & kIOPMSleepNow)
1375 {
1376 (void) sleepSystem ();
1377 }
1378
1379 /*
1380 * Power Emergency
1381 */
1382 if (msg & kIOPMPowerEmergency)
1383 {
1384 (void) sleepSystem ();
1385 }
1386
1387
1388 /*
1389 * Clamshell OPEN
1390 */
1391 if (msg & kIOPMClamshellOpened)
1392 {
1393 // Received clamshel open message from clamshell controlling driver
1394 // Update our internal state and tell general interest clients
1395 clamshellIsClosed = false;
1396 clamshellExists = true;
1397
1398 sendClientClamshellNotification();
1399 }
1400
1401 /*
1402 * Clamshell CLOSED
1403 * Send the clamshell interest notification since the lid is closing.
1404 */
1405 if (msg & kIOPMClamshellClosed)
1406 {
1407 // Received clamshel open message from clamshell controlling driver
1408 // Update our internal state and tell general interest clients
1409 clamshellIsClosed = true;
1410 clamshellExists = true;
1411
1412 sendClientClamshellNotification();
1413
1414 // And set eval_clamshell = so we can attempt
1415 eval_clamshell = true;
1416 }
1417
1418 /*
1419 * Set Desktop mode (sent from graphics)
1420 *
1421 * -> reevaluate lid state
1422 */
1423 if (msg & kIOPMSetDesktopMode)
1424 {
1425 desktopMode = (0 != (msg & kIOPMSetValue));
1426 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
1427
1428 sendClientClamshellNotification();
1429
1430 // Re-evaluate the lid state
1431 if( clamshellIsClosed )
1432 {
1433 eval_clamshell = true;
1434 }
1435 }
1436
1437 /*
1438 * AC Adaptor connected
1439 *
1440 * -> reevaluate lid state
1441 */
1442 if (msg & kIOPMSetACAdaptorConnected)
1443 {
1444 acAdaptorConnect = (0 != (msg & kIOPMSetValue));
1445 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
1446
1447 sendClientClamshellNotification();
1448
1449 // Re-evaluate the lid state
1450 if( clamshellIsClosed )
1451 {
1452 eval_clamshell = true;
1453 }
1454
1455 }
1456
1457 /*
1458 * Enable Clamshell (external display disappear)
1459 *
1460 * -> reevaluate lid state
1461 */
1462 if (msg & kIOPMEnableClamshell)
1463 {
1464 // Re-evaluate the lid state
1465 // System should sleep on external display disappearance
1466 // in lid closed operation.
1467 if( clamshellIsClosed && (true == ignoringClamshell) )
1468 {
1469 eval_clamshell = true;
1470 }
1471
1472 ignoringClamshell = false;
1473
1474 sendClientClamshellNotification();
1475 }
1476
1477 /*
1478 * Disable Clamshell (external display appeared)
1479 * We don't bother re-evaluating clamshell state. If the system is awake,
1480 * the lid is probably open.
1481 */
1482 if (msg & kIOPMDisableClamshell)
1483 {
1484 ignoringClamshell = true;
1485
1486 sendClientClamshellNotification();
1487 }
1488
1489 /*
1490 * Evaluate clamshell and SLEEP if appropiate
1491 */
1492 if ( eval_clamshell && shouldSleepOnClamshellClosed() )
1493 {
1494
1495
1496 // SLEEP!
1497 sleepSystem();
1498 }
1499
1500 /*
1501 * Power Button
1502 */
1503 if (msg & kIOPMPowerButton)
1504 {
1505 // toggle state of sleep/wake
1506 // are we dozing?
1507 if ( pm_vars->myCurrentState == DOZE_STATE )
1508 {
1509 // yes, tell the tree we're waking
1510 systemWake();
1511 // wake the Display Wrangler
1512 reportUserInput();
1513 }
1514 else {
1515 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
1516 // Check that power button sleep is enabled
1517 if( pbs ) {
1518 if( kOSBooleanTrue != getProperty(pbs))
1519 sleepSystem();
1520 }
1521 }
1522 }
1523
1524 /*
1525 * Allow Sleep
1526 *
1527 */
1528 if ( (msg & kIOPMAllowSleep) && !allowSleep )
1529 {
1530 allowSleep = true;
1531 adjustPowerState();
1532 }
1533
1534 /*
1535 * Prevent Sleep
1536 *
1537 */
1538 if (msg & kIOPMPreventSleep) {
1539 allowSleep = false;
1540 // are we dozing?
1541 if ( pm_vars->myCurrentState == DOZE_STATE ) {
1542 // yes, tell the tree we're waking
1543 systemWake();
1544 adjustPowerState();
1545 // wake the Display Wrangler
1546 reportUserInput();
1547 } else {
1548 adjustPowerState();
1549 // make sure we have power to clamp
1550 patriarch->wakeSystem();
1551 }
1552 }
1553
1554 return 0;
1555 }
1556
1557
1558 //*********************************************************************************
1559 // sleepSupported
1560 //
1561 //*********************************************************************************
1562
1563 void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
1564 {
1565 if ( flags & kPCICantSleep )
1566 {
1567 canSleep = false;
1568 } else {
1569 canSleep = true;
1570 platformSleepSupport = flags;
1571 }
1572
1573 setProperty(kIOSleepSupportedKey, canSleep);
1574
1575 }
1576
1577 //*********************************************************************************
1578 // requestPowerDomainState
1579 //
1580 // The root domain intercepts this call to the superclass.
1581 //
1582 // If the clamp bit is not set in the desire, then the child doesn't need the power
1583 // state it's requesting; it just wants it. The root ignores desires but not needs.
1584 // If the clamp bit is not set, the root takes it that the child can tolerate no
1585 // power and interprets the request accordingly. If all children can thus tolerate
1586 // no power, we are on our way to idle sleep.
1587 //*********************************************************************************
1588
1589 IOReturn IOPMrootDomain::requestPowerDomainState ( IOPMPowerFlags desiredState, IOPowerConnection * whichChild, unsigned long specification )
1590 {
1591 OSIterator *iter;
1592 OSObject *next;
1593 IOPowerConnection *connection;
1594 unsigned long powerRequestFlag = 0;
1595 IOPMPowerFlags editedDesire = desiredState;
1596
1597 // if they don't really need it, they don't get it
1598 if ( !(desiredState & kIOPMPreventIdleSleep) ) {
1599 editedDesire = 0;
1600 }
1601
1602
1603 IOLockLock(pm_vars->childLock);
1604
1605 // recompute sleepIsSupported and see if all children are asleep
1606 iter = getChildIterator(gIOPowerPlane);
1607 sleepIsSupported = true;
1608 if ( iter )
1609 {
1610 while ( (next = iter->getNextObject()) )
1611 {
1612 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
1613 {
1614 if ( connection == whichChild )
1615 {
1616 powerRequestFlag += editedDesire;
1617 if ( desiredState & kIOPMPreventSystemSleep )
1618 {
1619 sleepIsSupported = false;
1620 }
1621 } else {
1622 powerRequestFlag += connection->getDesiredDomainState();
1623 if ( connection->getPreventSystemSleepFlag() )
1624 {
1625 sleepIsSupported = false;
1626 }
1627 }
1628 }
1629 }
1630 iter->release();
1631 }
1632
1633 if ( (extraSleepDelay == 0) && (powerRequestFlag == 0) )
1634 {
1635 sleepASAP = true;
1636 }
1637
1638 // this may put the system to sleep
1639 adjustPowerState();
1640
1641 IOLockUnlock(pm_vars->childLock);
1642
1643 editedDesire |= desiredState & kIOPMPreventSystemSleep;
1644
1645 return super::requestPowerDomainState(editedDesire,whichChild,specification);
1646 }
1647
1648
1649 //*********************************************************************************
1650 // getSleepSupported
1651 //
1652 //*********************************************************************************
1653
1654 IOOptionBits IOPMrootDomain::getSleepSupported( void )
1655 {
1656 return( platformSleepSupport );
1657 }
1658
1659
1660 //*********************************************************************************
1661 // tellChangeDown
1662 //
1663 // We override the superclass implementation so we can send a different message
1664 // type to the client or application being notified.
1665 //*********************************************************************************
1666
1667 bool IOPMrootDomain::tellChangeDown ( unsigned long stateNum )
1668 {
1669 switch ( stateNum ) {
1670 case DOZE_STATE:
1671 case SLEEP_STATE:
1672
1673 // Direct callout into OSMetaClass so it can disable kmod unloads
1674 // during sleep/wake to prevent deadlocks.
1675 OSMetaClassSystemSleepOrWake( kIOMessageSystemWillSleep );
1676
1677 return super::tellClientsWithResponse(kIOMessageSystemWillSleep);
1678 case RESTART_STATE:
1679 // Unsupported shutdown ordering hack on RESTART only
1680 // For Bluetooth and USB (4368327)
1681 super::tellClients(iokit_common_msg(0x759));
1682
1683 return super::tellClientsWithResponse(kIOMessageSystemWillRestart);
1684 case OFF_STATE:
1685 // Unsupported shutdown ordering hack on SHUTDOWN only
1686 // For Bluetooth and USB (4554440)
1687 super::tellClients(iokit_common_msg(0x749));
1688
1689 return super::tellClientsWithResponse(kIOMessageSystemWillPowerOff);
1690 }
1691 // this shouldn't execute
1692 return super::tellChangeDown(stateNum);
1693 }
1694
1695
1696 //*********************************************************************************
1697 // askChangeDown
1698 //
1699 // We override the superclass implementation so we can send a different message
1700 // type to the client or application being notified.
1701 //
1702 // This must be idle sleep since we don't ask apps during any other power change.
1703 //*********************************************************************************
1704
1705 bool IOPMrootDomain::askChangeDown ( unsigned long )
1706 {
1707 return super::tellClientsWithResponse(kIOMessageCanSystemSleep);
1708 }
1709
1710
1711 //*********************************************************************************
1712 // tellNoChangeDown
1713 //
1714 // Notify registered applications and kernel clients that we are not
1715 // dropping power.
1716 //
1717 // We override the superclass implementation so we can send a different message
1718 // type to the client or application being notified.
1719 //
1720 // This must be a vetoed idle sleep, since no other power change can be vetoed.
1721 //*********************************************************************************
1722
1723 void IOPMrootDomain::tellNoChangeDown ( unsigned long )
1724 {
1725 return tellClients(kIOMessageSystemWillNotSleep);
1726 }
1727
1728
1729 //*********************************************************************************
1730 // tellChangeUp
1731 //
1732 // Notify registered applications and kernel clients that we are raising power.
1733 //
1734 // We override the superclass implementation so we can send a different message
1735 // type to the client or application being notified.
1736 //*********************************************************************************
1737
1738 void IOPMrootDomain::tellChangeUp ( unsigned long stateNum)
1739 {
1740 if ( stateNum == ON_STATE )
1741 {
1742 // Direct callout into OSMetaClass so it can disable kmod unloads
1743 // during sleep/wake to prevent deadlocks.
1744 OSMetaClassSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
1745
1746 IOHibernateSystemPostWake();
1747 return tellClients(kIOMessageSystemHasPoweredOn);
1748 }
1749 }
1750
1751 //*********************************************************************************
1752 // reportUserInput
1753 //
1754 //*********************************************************************************
1755
1756 void IOPMrootDomain::reportUserInput ( void )
1757 {
1758 OSIterator * iter;
1759
1760 if(!wrangler)
1761 {
1762 iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
1763 if(iter)
1764 {
1765 wrangler = (IOService *) iter->getNextObject();
1766 iter->release();
1767 }
1768 }
1769
1770 if(wrangler)
1771 wrangler->activityTickle(0,0);
1772 }
1773
1774 //*********************************************************************************
1775 // setQuickSpinDownTimeout
1776 //
1777 //*********************************************************************************
1778
1779 void IOPMrootDomain::setQuickSpinDownTimeout ( void )
1780 {
1781 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)1);
1782 }
1783
1784 //*********************************************************************************
1785 // restoreUserSpinDownTimeout
1786 //
1787 //*********************************************************************************
1788
1789 void IOPMrootDomain::restoreUserSpinDownTimeout ( void )
1790 {
1791 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)user_spindown);
1792 }
1793
1794 //*********************************************************************************
1795 // changePowerStateTo & changePowerStateToPriv
1796 //
1797 // Override of these methods for logging purposes.
1798 //*********************************************************************************
1799
1800 IOReturn IOPMrootDomain::changePowerStateTo ( unsigned long ordinal )
1801 {
1802 return super::changePowerStateTo(ordinal);
1803 }
1804
1805 IOReturn IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal )
1806 {
1807 IOReturn ret;
1808
1809 if( (systemBooting || systemShutdown) && (ordinal == SLEEP_STATE) )
1810 {
1811 kprintf("DANGER DANGER DANGER unexpected code path. aborting SLEEPSTATE change.\n");
1812 super::changePowerStateToPriv(ON_STATE);
1813 }
1814
1815 if( (SLEEP_STATE == ordinal) && sleepSupportedPEFunction )
1816 {
1817
1818 // Determine if the machine supports sleep, or must doze.
1819 ret = getPlatform()->callPlatformFunction(
1820 sleepSupportedPEFunction, false,
1821 NULL, NULL, NULL, NULL);
1822
1823 // If the machine only supports doze, the callPlatformFunction call
1824 // boils down toIOPMrootDomain::setSleepSupported(kPCICantSleep),
1825 // otherwise nothing.
1826 }
1827
1828 return super::changePowerStateToPriv(ordinal);
1829 }
1830
1831
1832 //*********************************************************************************
1833 // sysPowerDownHandler
1834 //
1835 // Receives a notification when the RootDomain changes state.
1836 //
1837 // Allows us to take action on system sleep, power down, and restart after
1838 // applications have received their power change notifications and replied,
1839 // but before drivers have powered down. We perform a vfs sync on power down.
1840 //*********************************************************************************
1841
1842 IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon,
1843 UInt32 messageType, IOService * service,
1844 void * messageArgument, vm_size_t argSize )
1845 {
1846 IOReturn ret;
1847 IOPowerStateChangeNotification *params = (IOPowerStateChangeNotification *) messageArgument;
1848 IOPMrootDomain *rootDomain = OSDynamicCast(IOPMrootDomain, service);
1849
1850 if(!rootDomain)
1851 return kIOReturnUnsupported;
1852
1853 switch (messageType) {
1854 case kIOMessageSystemWillSleep:
1855 rootDomain->powerOverrideOnPriv(); // start ignoring children's requests
1856 // (fall through to other cases)
1857
1858 // Interested applications have been notified of an impending power
1859 // change and have acked (when applicable).
1860 // This is our chance to save whatever state we can before powering
1861 // down.
1862 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
1863 // via callout
1864
1865 // We will ack within 20 seconds
1866 params->returnValue = 20 * 1000 * 1000;
1867 if (gIOHibernateState)
1868 params->returnValue += gIOHibernateFreeTime * 1000; //add in time we could spend freeing pages
1869
1870 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
1871 {
1872 // Purposely delay the ack and hope that shutdown occurs quickly.
1873 // Another option is not to schedule the thread and wait for
1874 // ack timeout...
1875 AbsoluteTime deadline;
1876 clock_interval_to_deadline( 30, kSecondScale, &deadline );
1877 thread_call_enter1_delayed( rootDomain->diskSyncCalloutEntry,
1878 (thread_call_param_t)params->powerRef,
1879 deadline );
1880 }
1881 else
1882 thread_call_enter1(rootDomain->diskSyncCalloutEntry, (thread_call_param_t)params->powerRef);
1883 ret = kIOReturnSuccess;
1884 break;
1885
1886 case kIOMessageSystemWillPowerOff:
1887 case kIOMessageSystemWillRestart:
1888 ret = kIOReturnUnsupported;
1889 break;
1890
1891 default:
1892 ret = kIOReturnUnsupported;
1893 break;
1894 }
1895 return ret;
1896 }
1897
1898 //*********************************************************************************
1899 // displayWranglerNotification
1900 //
1901 // Receives a notification when the IODisplayWrangler changes state.
1902 //
1903 // Allows us to take action on display dim/undim.
1904 //
1905 // When the display goes dim we:
1906 // - Start the idle sleep timer
1907 // - set the quick spin down timeout
1908 //
1909 // On wake from display dim:
1910 // - Cancel the idle sleep timer
1911 // - restore the user's chosen spindown timer from the "quick" spin down value
1912 //*********************************************************************************
1913
1914 IOReturn IOPMrootDomain::displayWranglerNotification( void * target, void * refCon,
1915 UInt32 messageType, IOService * service,
1916 void * messageArgument, vm_size_t argSize )
1917 {
1918 IOPMrootDomain * rootDomain = OSDynamicCast(IOPMrootDomain, (IOService *)target);
1919 AbsoluteTime deadline;
1920 static bool deviceAlreadyPoweredOff = false;
1921
1922 if(!rootDomain)
1923 return kIOReturnUnsupported;
1924
1925 switch (messageType) {
1926 case kIOMessageDeviceWillPowerOff:
1927 // The IODisplayWrangler has powered off either because of idle display sleep
1928 // or force system sleep.
1929
1930 // The display wrangler will send the DeviceWillPowerOff message 4 times until
1931 // it gets into its lowest state. We only want to act on the first of those 4.
1932 if( deviceAlreadyPoweredOff ) return kIOReturnUnsupported;
1933
1934 deviceAlreadyPoweredOff = true;
1935
1936 if( rootDomain->extraSleepDelay )
1937 {
1938 // start the extra sleep timer
1939 clock_interval_to_deadline(rootDomain->extraSleepDelay*60, kSecondScale, &deadline );
1940 thread_call_enter_delayed(rootDomain->extraSleepTimer, deadline);
1941 rootDomain->idleSleepPending = true;
1942 } else {
1943 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
1944 // and if system sleep is non-Never
1945 if( (0 != rootDomain->user_spindown) && (0 != rootDomain->sleepSlider) )
1946 rootDomain->setQuickSpinDownTimeout();
1947 }
1948
1949 break;
1950
1951 case kIOMessageDeviceHasPoweredOn:
1952
1953 // The display has powered on either because of UI activity or wake from sleep/doze
1954 deviceAlreadyPoweredOff = false;
1955 rootDomain->adjustPowerState();
1956
1957
1958 // cancel any pending idle sleep
1959 if(rootDomain->idleSleepPending)
1960 {
1961 thread_call_cancel(rootDomain->extraSleepTimer);
1962 rootDomain->idleSleepPending = false;
1963 }
1964
1965 // Change the spindown value back to the user's selection from our accelerated setting
1966 if(0 != rootDomain->user_spindown)
1967 rootDomain->restoreUserSpinDownTimeout();
1968
1969 // Put on the policy maker's on clamp.
1970
1971 break;
1972
1973 default:
1974 break;
1975 }
1976 return kIOReturnUnsupported;
1977 }
1978
1979 //*********************************************************************************
1980 // displayWranglerPublished
1981 //
1982 // Receives a notification when the IODisplayWrangler is published.
1983 // When it's published we install a power state change handler.
1984 //
1985 //*********************************************************************************
1986
1987 bool IOPMrootDomain::displayWranglerPublished(
1988 void * target,
1989 void * refCon,
1990 IOService * newService)
1991 {
1992 IOPMrootDomain *rootDomain =
1993 OSDynamicCast(IOPMrootDomain, (IOService *)target);
1994
1995 if(!rootDomain)
1996 return false;
1997
1998 rootDomain->wrangler = newService;
1999
2000 // we found the display wrangler, now install a handler
2001 if( !rootDomain->wrangler->registerInterest( gIOGeneralInterest,
2002 &displayWranglerNotification, target, 0) )
2003 {
2004 return false;
2005 }
2006
2007 return true;
2008 }
2009
2010
2011 //*********************************************************************************
2012 // batteryPublished
2013 //
2014 // Notification on battery class IOPowerSource appearance
2015 //
2016 //******************************************************************************
2017
2018 bool IOPMrootDomain::batteryPublished(
2019 void * target,
2020 void * root_domain,
2021 IOService * resourceService )
2022 {
2023 // rdar://2936060&4435589
2024 // All laptops have dimmable LCD displays
2025 // All laptops have batteries
2026 // So if this machine has a battery, publish the fact that the backlight
2027 // supports dimming.
2028 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
2029
2030 return (true);
2031 }
2032
2033
2034
2035 //*********************************************************************************
2036 // adjustPowerState
2037 //
2038 // Some condition that affects our wake/sleep/doze decision has changed.
2039 //
2040 // If the sleep slider is in the off position, we cannot sleep or doze.
2041 // If the enclosure is open, we cannot sleep or doze.
2042 // If the system is still booting, we cannot sleep or doze.
2043 //
2044 // In those circumstances, we prevent sleep and doze by holding power on with
2045 // changePowerStateToPriv(ON).
2046 //
2047 // If the above conditions do not exist, and also the sleep timer has expired, we
2048 // allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
2049 // changePowerStateToPriv(DOZE) depending on whether or not we already know the
2050 // platform cannot sleep.
2051 //
2052 // In this case, sleep or doze will either occur immediately or at the next time
2053 // that no children are holding the system out of idle sleep via the
2054 // kIOPMPreventIdleSleep flag in their power state arrays.
2055 //*********************************************************************************
2056
2057 void IOPMrootDomain::adjustPowerState( void )
2058 {
2059 if ( (sleepSlider == 0)
2060 || !allowSleep
2061 || systemBooting
2062 || systemShutdown )
2063 {
2064 if(systemBooting || systemShutdown) {
2065 kprintf("adjusting power state to ON_STATE [2063] on grounds of systemBooting.\n");
2066 }
2067
2068 changePowerStateToPriv(ON_STATE);
2069 } else {
2070 if ( sleepASAP )
2071 {
2072 sleepASAP = false;
2073 if ( !sleepIsSupported )
2074 setSleepSupported( kPCICantSleep );
2075 changePowerStateToPriv(SLEEP_STATE);
2076 }
2077 }
2078 }
2079
2080 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2081
2082
2083
2084 #undef super
2085 #define super OSObject
2086 OSDefineMetaClassAndStructors(PMSettingObject, OSObject)
2087
2088 void PMSettingObject::setPMSetting(const OSSymbol *type, OSObject *obj)
2089 {
2090 (*func)(target, type, obj, refcon);
2091 }
2092
2093 /*
2094 * Static constructor/initializer for PMSettingObject
2095 */
2096 PMSettingObject *PMSettingObject::pmSettingObject(
2097 IOPMrootDomain *parent_arg,
2098 IOPMSettingControllerCallback handler_arg,
2099 OSObject *target_arg,
2100 uintptr_t refcon_arg,
2101 uint32_t supportedPowerSources,
2102 const OSSymbol * settings[])
2103 {
2104 uint32_t objCount = 0;
2105 PMSettingObject *pmso;
2106
2107 if( !parent_arg || !handler_arg || !settings ) return NULL;
2108
2109 // count OSSymbol entries in NULL terminated settings array
2110 while( settings[objCount] ) {
2111 objCount++;
2112 }
2113 if(0 == objCount) return NULL;
2114
2115 pmso = new PMSettingObject;
2116 if(!pmso || !pmso->init()) return NULL;
2117
2118 pmso->parent = parent_arg;
2119 pmso->func = handler_arg;
2120 pmso->target = target_arg;
2121 pmso->refcon = refcon_arg;
2122 pmso->releaseAtCount = objCount + 1; // release when it has count+1 retains
2123
2124 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount);
2125 if(pmso->publishedFeatureID) {
2126 for(unsigned int i=0; i<objCount; i++) {
2127 // Since there is now at least one listener to this setting, publish
2128 // PM root domain support for it.
2129 parent_arg->publishFeature( settings[i]->getCStringNoCopy(),
2130 supportedPowerSources, &pmso->publishedFeatureID[i] );
2131 }
2132 }
2133
2134 return pmso;
2135 }
2136
2137 void PMSettingObject::free(void)
2138 {
2139 OSCollectionIterator *settings_iter;
2140 OSSymbol *sym;
2141 OSArray *arr;
2142 int arr_idx;
2143 int i;
2144 int objCount = releaseAtCount - 1;
2145
2146 if(publishedFeatureID) {
2147 for(i=0; i<objCount; i++) {
2148 if(0 != publishedFeatureID[i]) {
2149 parent->removePublishedFeature( publishedFeatureID[i] );
2150 }
2151 }
2152
2153 IOFree(publishedFeatureID, sizeof(uint32_t) * objCount);
2154 }
2155
2156 IORecursiveLockLock(parent->settingsCtrlLock);
2157
2158 // Search each PM settings array in the kernel.
2159 settings_iter = OSCollectionIterator::withCollection(parent->settingsCallbacks);
2160 if(settings_iter)
2161 {
2162 while(( sym = OSDynamicCast(OSSymbol, settings_iter->getNextObject()) ))
2163 {
2164 arr = (OSArray *)parent->settingsCallbacks->getObject(sym);
2165 arr_idx = arr->getNextIndexOfObject(this, 0);
2166 if(-1 != arr_idx) {
2167 // 'this' was found in the array; remove it
2168 arr->removeObject(arr_idx);
2169 }
2170 }
2171
2172 settings_iter->release();
2173 }
2174
2175 IORecursiveLockUnlock(parent->settingsCtrlLock);
2176
2177 super::free();
2178 }
2179
2180 void PMSettingObject::taggedRelease(const void *tag, const int when) const
2181 {
2182 // We have n+1 retains - 1 per array that this PMSettingObject is a member
2183 // of, and 1 retain to ourself. When we get a release with n+1 retains
2184 // remaining, we go ahead and free ourselves, cleaning up array pointers
2185 // in free();
2186
2187 super::taggedRelease(tag, releaseAtCount);
2188 }
2189
2190
2191
2192 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2193
2194 #undef super
2195 #define super IOService
2196
2197 OSDefineMetaClassAndStructors(IORootParent, IOService)
2198
2199 // This array exactly parallels the state array for the root domain.
2200 // Power state changes initiated by a device can be vetoed by a client of the device, and
2201 // power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
2202 // so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
2203 // its parent to make the change. That is the reason for this complexity.
2204
2205 static IOPMPowerState patriarchPowerStates[number_of_power_states] = {
2206 {1,0,0,0,0,0,0,0,0,0,0,0}, // off
2207 {1,0,RESTART_POWER,0,0,0,0,0,0,0,0,0}, // reset
2208 {1,0,SLEEP_POWER,0,0,0,0,0,0,0,0,0}, // sleep
2209 {1,0,DOZE_POWER,0,0,0,0,0,0,0,0,0}, // doze
2210 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0} // running
2211 };
2212
2213 bool IORootParent::start ( IOService * nub )
2214 {
2215 mostRecentChange = ON_STATE;
2216 super::start(nub);
2217 PMinit();
2218 registerPowerDriver(this,patriarchPowerStates,number_of_power_states);
2219 powerOverrideOnPriv();
2220 return true;
2221 }
2222
2223
2224 void IORootParent::shutDownSystem ( void )
2225 {
2226 mostRecentChange = OFF_STATE;
2227 changePowerStateToPriv(OFF_STATE);
2228 }
2229
2230
2231 void IORootParent::restartSystem ( void )
2232 {
2233 mostRecentChange = RESTART_STATE;
2234 changePowerStateToPriv(RESTART_STATE);
2235 }
2236
2237
2238 void IORootParent::sleepSystem ( void )
2239 {
2240 mostRecentChange = SLEEP_STATE;
2241 changePowerStateToPriv(SLEEP_STATE);
2242 }
2243
2244
2245 void IORootParent::dozeSystem ( void )
2246 {
2247 mostRecentChange = DOZE_STATE;
2248 changePowerStateToPriv(DOZE_STATE);
2249 }
2250
2251 // Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
2252 // This brings the parent to doze, which allows the root to step up from sleep to doze.
2253
2254 // In idle sleep, do nothing because the parent is still on and the root can freely change state.
2255
2256 void IORootParent::sleepToDoze ( void )
2257 {
2258 if ( mostRecentChange == SLEEP_STATE ) {
2259 changePowerStateToPriv(DOZE_STATE);
2260 }
2261 }
2262
2263
2264 void IORootParent::wakeSystem ( void )
2265 {
2266 mostRecentChange = ON_STATE;
2267 changePowerStateToPriv(ON_STATE);
2268 }
2269
2270 IOReturn IORootParent::changePowerStateToPriv ( unsigned long ordinal )
2271 {
2272 IOReturn ret;
2273
2274 if( (SLEEP_STATE == ordinal) && sleepSupportedPEFunction )
2275 {
2276
2277 // Determine if the machine supports sleep, or must doze.
2278 ret = getPlatform()->callPlatformFunction(
2279 sleepSupportedPEFunction, false,
2280 NULL, NULL, NULL, NULL);
2281
2282 // If the machine only supports doze, the callPlatformFunction call
2283 // boils down toIOPMrootDomain::setSleepSupported(kPCICantSleep),
2284 // otherwise nothing.
2285 }
2286
2287 return super::changePowerStateToPriv(ordinal);
2288 }
2289