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