]> git.saurik.com Git - apple/xnu.git/blame_incremental - iokit/Kernel/IOPMrootDomain.cpp
xnu-1228.15.4.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
... / ...
CommitLineData
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#if HIBERNATION
44#include <IOKit/IOHibernatePrivate.h>
45#endif
46#include <sys/syslog.h>
47#include <sys/sysctl.h>
48#include <sys/time.h>
49#include "IOServicePrivate.h" // _IOServiceInterestNotifier
50
51
52#if __i386__
53__BEGIN_DECLS
54#include "IOPMrootDomainInternal.h"
55__END_DECLS
56#endif
57
58
59//#define DEBUG 1
60#if DEBUG
61#define DEBUG_LOG(x...) do { kprintf(x); } while (0)
62#else
63#define DEBUG_LOG(x...)
64#endif
65#define HaltRestartLog(x...) do { kprintf(x); } while (0)
66
67extern "C" {
68IOReturn OSMetaClassSystemSleepOrWake( UInt32 );
69}
70
71extern const IORegistryPlane * gIOPowerPlane;
72
73IOReturn broadcast_aggressiveness ( OSObject *, void *, void *, void *, void * );
74static void sleepTimerExpired(thread_call_param_t);
75static void wakeupClamshellTimerExpired ( thread_call_param_t us);
76static void notifySystemShutdown( IOService * root, unsigned long event );
77
78// "IOPMSetSleepSupported" callPlatformFunction name
79static const OSSymbol *sleepSupportedPEFunction = NULL;
80
81#define kIOSleepSupportedKey "IOSleepSupported"
82
83#define kRD_AllPowerSources (kIOPMSupportedOnAC \
84 | kIOPMSupportedOnBatt \
85 | kIOPMSupportedOnUPS)
86
87#define number_of_power_states 5
88#define OFF_STATE 0
89#define RESTART_STATE 1
90#define SLEEP_STATE 2
91#define DOZE_STATE 3
92#define ON_STATE 4
93
94#define ON_POWER kIOPMPowerOn
95#define RESTART_POWER kIOPMRestart
96#define SLEEP_POWER kIOPMAuxPowerOn
97#define DOZE_POWER kIOPMDoze
98
99enum
100{
101 // not idle around autowake time, secs
102 kAutoWakePreWindow = 45,
103 kAutoWakePostWindow = 15
104};
105
106
107#define kLocalEvalClamshellCommand (1 << 15)
108
109static IOPMPowerState ourPowerStates[number_of_power_states] = {
110 // state 0, off
111 {1,0, 0, 0,0,0,0,0,0,0,0,0},
112 // state 1, restart
113 {1,kIOPMRestartCapability, kIOPMRestart, RESTART_POWER,0,0,0,0,0,0,0,0},
114 // state 2, sleep
115 {1,kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER,0,0,0,0,0,0,0,0},
116 // state 3, doze
117 {1,kIOPMDoze, kIOPMDoze, DOZE_POWER,0,0,0,0,0,0,0,0},
118 // state 4, on
119 {1,kIOPMPowerOn, kIOPMPowerOn, ON_POWER,0,0,0,0,0,0,0,0},
120};
121
122static IOPMrootDomain * gRootDomain;
123static UInt32 gSleepOrShutdownPending = 0;
124
125struct timeval gIOLastSleepTime;
126struct timeval gIOLastWakeTime;
127
128// Constants used as arguments to IOPMrootDomain::informCPUStateChange
129#define kCPUUnknownIndex 9999999
130enum {
131 kInformAC = 0,
132 kInformLid = 1,
133 kInformableCount = 2
134};
135
136class PMSettingObject : public OSObject
137{
138 OSDeclareDefaultStructors(PMSettingObject)
139private:
140 IOPMrootDomain *parent;
141 IOPMSettingControllerCallback func;
142 OSObject *target;
143 uintptr_t refcon;
144 uint32_t *publishedFeatureID;
145 int releaseAtCount;
146public:
147 static PMSettingObject *pmSettingObject(
148 IOPMrootDomain *parent_arg,
149 IOPMSettingControllerCallback handler_arg,
150 OSObject *target_arg,
151 uintptr_t refcon_arg,
152 uint32_t supportedPowerSources,
153 const OSSymbol *settings[]);
154
155 void setPMSetting(const OSSymbol *type, OSObject *obj);
156
157 void taggedRelease(const void *tag, const int when) const;
158 void free(void);
159};
160
161/*
162 * Internal helper object for Shutdown/Restart notifications.
163 */
164#define kPMHaltMaxWorkers 8
165#define kPMHaltTimeoutMS 100
166
167class PMHaltWorker : public OSObject
168{
169 OSDeclareDefaultStructors( PMHaltWorker )
170
171public:
172 IOService * service; // service being worked on
173 AbsoluteTime startTime; // time when work started
174 int depth; // work on nubs at this PM-tree depth
175 int visits; // number of nodes visited (debug)
176 IOLock * lock;
177 bool timeout; // service took too long
178
179 static PMHaltWorker * worker( void );
180 static void main( void * arg );
181 static void work( PMHaltWorker * me );
182 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
183 virtual void free( void );
184};
185
186OSDefineMetaClassAndStructors( PMHaltWorker, OSObject )
187
188
189#define super IOService
190OSDefineMetaClassAndStructors(IOPMrootDomain,IOService)
191
192extern "C"
193{
194 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
195 {
196 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
197 }
198
199 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
200 {
201 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
202 }
203
204 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
205 {
206 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
207 }
208
209 IOReturn vetoSleepWakeNotification(void * PMrefcon)
210 {
211 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
212 }
213
214 IOReturn rootDomainRestart ( void )
215 {
216 return gRootDomain->restartSystem();
217 }
218
219 IOReturn rootDomainShutdown ( void )
220 {
221 return gRootDomain->shutdownSystem();
222 }
223
224 void IOSystemShutdownNotification ( void )
225 {
226 IOCatalogue::disableExternalLinker();
227 for ( int i = 0; i < 100; i++ )
228 {
229 if ( OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) ) break;
230 IOSleep( 100 );
231 }
232 }
233
234 int sync_internal(void);
235}
236
237/*
238A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain
239children it has, but within the constraint of the power state provided by its parent. The driver expresses its desire by
240calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children
241express their desires by calling requestPowerDomainState().
242
243The Root Power Domain owns the policy for idle and demand sleep and doze for the system. It is a power-managed IOService just
244like the others in the system. It implements several power states which correspond to what we see as Sleep, Doze, etc.
245
246The sleep/doze policy is as follows:
247Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards.
248Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero.
249The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep.
250
251These three conditions are enforced using the "driver clamp" by calling changePowerStateTo(). For example, if the case is
252opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or
253the state of the other clamp.
254
255Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item.
256In this case the root's parent actually initiates the power state change so that the root has no choice and does not give
257applications the opportunity to veto the change.
258
259Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep. When this is true, the root's
260children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE)
261to hold itself on until the sleep timer expires. This timer is set for the difference between the sleep timeout slider and
262the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel. For example, if
263the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes,
264when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root
265sets its timer for 25 minutes (30 - 5). When the timer expires, it releases its clamp and now nothing is holding it awake,
266so it falls asleep.
267
268Demand sleep is prevented when the system is booting. When preferences are transmitted by the loginwindow at the end of
269boot, a flag is cleared, and this allows subsequent Demand Sleep.
270
271The 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
272a clamp, but sets a flag which is noticed before actually sleeping the kernel. If the flag is set, the root steps up
273one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and
274ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler
275to be tickled)).
276*/
277
278// **********************************************************************************
279
280IOPMrootDomain * IOPMrootDomain::construct( void )
281{
282 IOPMrootDomain *root;
283
284 root = new IOPMrootDomain;
285 if( root)
286 root->init();
287
288 return( root );
289}
290
291// **********************************************************************************
292
293static void disk_sync_callout(thread_call_param_t p0, thread_call_param_t p1)
294{
295 IOService *rootDomain = (IOService *) p0;
296 unsigned long pmRef = (unsigned long) p1;
297
298 DEBUG_LOG("disk_sync_callout: start\n");
299
300#if HIBERNATION
301 IOHibernateSystemSleep();
302#endif
303 sync_internal();
304 rootDomain->allowPowerChange(pmRef);
305 DEBUG_LOG("disk_sync_callout: finish\n");
306}
307
308// **********************************************************************************
309
310static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime )
311{
312 AbsoluteTime endTime;
313 UInt64 nano = 0;
314
315 clock_get_uptime(&endTime);
316 if (CMP_ABSOLUTETIME(&endTime, startTime) > 0)
317 {
318 SUB_ABSOLUTETIME(&endTime, startTime);
319 absolutetime_to_nanoseconds(endTime, &nano);
320 }
321
322 return (UInt32)(nano / 1000000ULL);
323}
324
325// **********************************************************************************
326// start
327//
328// We don't do much here. The real initialization occurs when the platform
329// expert informs us we are the root.
330// **********************************************************************************
331
332#define kRootDomainSettingsCount 16
333
334static SYSCTL_STRUCT(_kern, OID_AUTO, sleeptime,
335 CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN,
336 &gIOLastSleepTime, timeval, "");
337
338static SYSCTL_STRUCT(_kern, OID_AUTO, waketime,
339 CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN,
340 &gIOLastWakeTime, timeval, "");
341
342static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
343
344bool IOPMrootDomain::start ( IOService * nub )
345{
346 OSIterator *psIterator;
347 OSDictionary *tmpDict;
348
349 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
350
351 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
352 {
353 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
354 gIOPMSettingAutoWakeSecondsKey,
355 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
356 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey),
357 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
358 OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey),
359 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
360 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
361 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
362 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
363 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
364 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
365 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
366 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
367 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
368 OSSymbol::withCString(kIOPMStateConsoleShutdown)
369 };
370
371
372 pmPowerStateQueue = 0;
373
374 _reserved = (ExpansionData *)IOMalloc(sizeof(ExpansionData));
375 if(!_reserved) return false;
376
377 super::start(nub);
378
379 gRootDomain = this;
380
381 PMinit();
382
383 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
384 canSleep = true;
385 setProperty(kIOSleepSupportedKey,true);
386
387 userDisabledAllSleep = false;
388 allowSleep = true;
389 sleepIsSupported = true;
390 systemBooting = true;
391 sleepSlider = 0;
392 idleSleepPending = false;
393 wrangler = NULL;
394 sleepASAP = false;
395 clamshellIsClosed = false;
396 clamshellExists = false;
397 ignoringClamshell = true;
398 ignoringClamshellDuringWakeup = false;
399 acAdaptorConnect = true;
400
401 idxPMCPUClamshell = kCPUUnknownIndex;
402 idxPMCPULimitedPower = kCPUUnknownIndex;
403
404 tmpDict = OSDictionary::withCapacity(1);
405 setProperty(kRootDomainSupportedFeatures, tmpDict);
406 tmpDict->release();
407
408 settingsCallbacks = OSDictionary::withCapacity(1);
409
410 // Create a list of the valid PM settings that we'll relay to
411 // interested clients in setProperties() => setPMSetting()
412 allowedPMSettings = OSArray::withObjects(
413 (const OSObject **)settingsArr,
414 kRootDomainSettingsCount,
415 0);
416
417 fPMSettingsDict = OSDictionary::withCapacity(5);
418
419 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(this);
420 getPMworkloop()->addEventSource(pmPowerStateQueue);
421
422 featuresDictLock = IOLockAlloc();
423 settingsCtrlLock = IORecursiveLockAlloc();
424
425 extraSleepTimer = thread_call_allocate(
426 (thread_call_func_t)sleepTimerExpired,
427 (thread_call_param_t) this);
428 clamshellWakeupIgnore = thread_call_allocate(
429 (thread_call_func_t)wakeupClamshellTimerExpired,
430 (thread_call_param_t) this);
431 diskSyncCalloutEntry = thread_call_allocate(
432 &disk_sync_callout,
433 (thread_call_param_t) this);
434
435 // create our parent
436 patriarch = new IORootParent;
437 patriarch->init();
438 patriarch->attach(this);
439 patriarch->start(this);
440 patriarch->addPowerChild(this);
441
442 registerPowerDriver(this,ourPowerStates,number_of_power_states);
443
444 setPMRootDomain(this);
445 // set a clamp until we sleep
446 changePowerStateToPriv(ON_STATE);
447
448 // install power change handler
449 registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
450
451#if !NO_KERNEL_HID
452 // Register for a notification when IODisplayWrangler is published
453 _displayWranglerNotifier = addNotification(
454 gIOPublishNotification, serviceMatching("IODisplayWrangler"),
455 &displayWranglerPublished, this, 0);
456#endif
457
458 // Battery location published - ApplePMU support only
459 _batteryPublishNotifier = addNotification(
460 gIOPublishNotification, serviceMatching("IOPMPowerSource"),
461 &batteryPublished, this, this);
462
463
464 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
465 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
466 ucClassName->release();
467
468 // IOBacklightDisplay can take a long time to load at boot, or it may
469 // not load at all if you're booting with clamshell closed. We publish
470 // 'DisplayDims' here redundantly to get it published early and at all.
471 psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") );
472 if( psIterator && psIterator->getNextObject() )
473 {
474 // There's at least one battery on the system, so we publish
475 // 'DisplayDims' support for the LCD.
476 publishFeature("DisplayDims");
477 }
478 if(psIterator) {
479 psIterator->release();
480 }
481
482
483 sysctl_register_oid(&sysctl__kern_sleeptime);
484 sysctl_register_oid(&sysctl__kern_waketime);
485
486#if HIBERNATION
487 IOHibernateSystemInit(this);
488#endif
489
490 registerService(); // let clients find us
491
492 return true;
493}
494
495// **********************************************************************************
496// setProperties
497//
498// Receive a setProperty call
499// The "System Boot" property means the system is completely booted.
500// **********************************************************************************
501IOReturn IOPMrootDomain::setProperties ( OSObject *props_obj)
502{
503 IOReturn return_value = kIOReturnSuccess;
504 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
505 OSBoolean *b;
506 OSNumber *n;
507 OSString *str;
508 OSSymbol *type;
509 OSObject *obj;
510 unsigned int i;
511
512 const OSSymbol *boot_complete_string =
513 OSSymbol::withCString("System Boot Complete");
514 const OSSymbol *sys_shutdown_string =
515 OSSymbol::withCString("System Shutdown");
516 const OSSymbol *stall_halt_string =
517 OSSymbol::withCString("StallSystemAtHalt");
518 const OSSymbol *battery_warning_disabled_string =
519 OSSymbol::withCString("BatteryWarningsDisabled");
520 const OSSymbol *idle_seconds_string =
521 OSSymbol::withCString("System Idle Seconds");
522#if HIBERNATION
523 const OSSymbol *hibernatemode_string =
524 OSSymbol::withCString(kIOHibernateModeKey);
525 const OSSymbol *hibernatefile_string =
526 OSSymbol::withCString(kIOHibernateFileKey);
527 const OSSymbol *hibernatefreeratio_string =
528 OSSymbol::withCString(kIOHibernateFreeRatioKey);
529 const OSSymbol *hibernatefreetime_string =
530 OSSymbol::withCString(kIOHibernateFreeTimeKey);
531#endif
532 const OSSymbol *sleepdisabled_string =
533 OSSymbol::withCString("SleepDisabled");
534
535 if(!dict)
536 {
537 return_value = kIOReturnBadArgument;
538 goto exit;
539 }
540
541 if ((n = OSDynamicCast(OSNumber, dict->getObject(idle_seconds_string))))
542 {
543 setProperty(idle_seconds_string, n);
544 idleSeconds = n->unsigned32BitValue();
545 }
546
547 if( systemBooting
548 && boot_complete_string
549 && dict->getObject(boot_complete_string))
550 {
551 systemBooting = false;
552 adjustPowerState();
553
554 // If lid is closed, re-send lid closed notification
555 // now that booting is complete.
556 if( clamshellIsClosed )
557 {
558 this->receivePowerNotification(kLocalEvalClamshellCommand);
559 }
560 }
561
562 if( battery_warning_disabled_string
563 && dict->getObject(battery_warning_disabled_string))
564 {
565 setProperty( battery_warning_disabled_string,
566 dict->getObject(battery_warning_disabled_string));
567 }
568
569 if( sys_shutdown_string
570 && (b = OSDynamicCast(OSBoolean, dict->getObject(sys_shutdown_string))))
571 {
572
573 if(kOSBooleanTrue == b)
574 {
575 /* We set systemShutdown = true during shutdown
576 to prevent sleep at unexpected times while loginwindow is trying
577 to shutdown apps and while the OS is trying to transition to
578 complete power of.
579
580 Set to true during shutdown, as soon as loginwindow shows
581 the "shutdown countdown dialog", through individual app
582 termination, and through black screen kernel shutdown.
583 */
584 kprintf("systemShutdown true\n");
585 systemShutdown = true;
586 } else {
587 /*
588 A shutdown was initiated, but then the shutdown
589 was cancelled, clearing systemShutdown to false here.
590 */
591 kprintf("systemShutdown false\n");
592 systemShutdown = false;
593 }
594 }
595
596 if( stall_halt_string
597 && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) )
598 {
599 setProperty(stall_halt_string, b);
600 }
601
602#if HIBERNATION
603 if ( hibernatemode_string
604 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string))))
605 {
606 setProperty(hibernatemode_string, n);
607 }
608 if ( hibernatefreeratio_string
609 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string))))
610 {
611 setProperty(hibernatefreeratio_string, n);
612 }
613 if ( hibernatefreetime_string
614 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string))))
615 {
616 setProperty(hibernatefreetime_string, n);
617 }
618 if ( hibernatefile_string
619 && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string))))
620 {
621 setProperty(hibernatefile_string, str);
622 }
623#endif
624
625 if( sleepdisabled_string
626 && (b = OSDynamicCast(OSBoolean, dict->getObject(sleepdisabled_string))) )
627 {
628 setProperty(sleepdisabled_string, b);
629
630 userDisabledAllSleep = (kOSBooleanTrue == b);
631 }
632
633 // Relay our allowed PM settings onto our registered PM clients
634 for(i = 0; i < allowedPMSettings->getCount(); i++) {
635
636 type = (OSSymbol *)allowedPMSettings->getObject(i);
637 if(!type) continue;
638
639 obj = dict->getObject(type);
640 if(!obj) continue;
641
642 if ((gIOPMSettingAutoWakeSecondsKey == type) && ((n = OSDynamicCast(OSNumber, obj))))
643 {
644 UInt32 rsecs = n->unsigned32BitValue();
645 if (!rsecs)
646 autoWakeStart = autoWakeEnd = 0;
647 else
648 {
649 AbsoluteTime deadline;
650 clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline);
651 autoWakeEnd = AbsoluteTime_to_scalar(&deadline);
652 if (rsecs > kAutoWakePreWindow)
653 rsecs -= kAutoWakePreWindow;
654 else
655 rsecs = 0;
656 clock_interval_to_deadline(rsecs, kSecondScale, &deadline);
657 autoWakeStart = AbsoluteTime_to_scalar(&deadline);
658 }
659 }
660
661 return_value = setPMSetting(type, obj);
662
663 if(kIOReturnSuccess != return_value) goto exit;
664 }
665
666exit:
667 if(sleepdisabled_string) sleepdisabled_string->release();
668 if(boot_complete_string) boot_complete_string->release();
669 if(stall_halt_string) stall_halt_string->release();
670 if(idle_seconds_string) idle_seconds_string->release();
671 return return_value;
672}
673
674
675//*********************************************************************************
676// youAreRoot
677//
678// Power Managment is informing us that we are the root power domain.
679// We know we are not the root however, since we have just instantiated a parent
680// for ourselves and made it the root. We override this method so it will have
681// no effect
682//*********************************************************************************
683IOReturn IOPMrootDomain::youAreRoot ( void )
684{
685 return IOPMNoErr;
686}
687
688// **********************************************************************************
689// command_received
690//
691// No longer used
692// **********************************************************************************
693void IOPMrootDomain::command_received ( void * w, void * x, void * y, void * z )
694{
695 super::command_received(w,x,y,z);
696}
697
698
699// **********************************************************************************
700// broadcast_aggressiveness
701//
702// **********************************************************************************
703IOReturn broadcast_aggressiveness ( OSObject * root, void * x, void * y, void *, void * )
704{
705 ((IOPMrootDomain *)root)->broadcast_it((unsigned long)x,(unsigned long)y);
706 return IOPMNoErr;
707}
708
709
710// **********************************************************************************
711// broadcast_it
712//
713// We are behind the command gate to broadcast an aggressiveness factor. We let the
714// superclass do it, but we need to snoop on factors that affect idle sleep.
715// **********************************************************************************
716void IOPMrootDomain::broadcast_it (unsigned long type, unsigned long value)
717{
718 super::setAggressiveness(type,value);
719
720 // Save user's spin down timer to restore after we replace it for idle sleep
721 if( type == kPMMinutesToSpinDown ) user_spindown = value;
722
723 // Use longestNonSleepSlider to calculate dimming adjust idle sleep timer
724 if (getAggressiveness(kPMMinutesToDim, (unsigned long *)&longestNonSleepSlider)
725 != kIOReturnSuccess)
726 longestNonSleepSlider = 0;
727
728 if ( type == kPMMinutesToSleep ) {
729 DEBUG_LOG("PM idle time -> %ld secs (ena %d)\n", idleSeconds, (value != 0));
730 if (0x7fffffff == value)
731 value = idleSeconds;
732
733 if ( (sleepSlider == 0) && (value != 0) ) {
734 if (!wrangler)
735 {
736 sleepASAP = false;
737 changePowerStateToPriv(ON_STATE);
738 if (idleSeconds)
739 {
740 AbsoluteTime deadline;
741 // stay awake for at least idleSeconds
742 clock_interval_to_deadline(idleSeconds, kSecondScale, &deadline);
743 thread_call_enter_delayed(extraSleepTimer, deadline);
744 // this gets turned off when we sleep again
745 idleSleepPending = true;
746 }
747 }
748 else
749 {
750 // If sleepASAP is already set, then calling adjustPowerState() here
751 // will put the system to sleep immediately which is bad. Note that
752 // this aggressiveness change can occur without waking up the display
753 // by (dis)connecting the AC adapter. To get around this, the power
754 // clamp is restore to ON state then dropped after waiting for the
755 // sleep timer to expire.
756
757 if (sleepASAP)
758 {
759 AbsoluteTime deadline;
760 // stay awake for at least sleepSlider minutes
761 clock_interval_to_deadline(value * 60, kSecondScale, &deadline);
762 thread_call_enter_delayed(extraSleepTimer, deadline);
763 // this gets turned off when we sleep again
764 idleSleepPending = true;
765 sleepASAP = false;
766 }
767 }
768 }
769 sleepSlider = value;
770 if ( sleepSlider == 0 ) {
771 // idle sleep is now disabled
772 adjustPowerState();
773 // make sure we're powered
774 patriarch->wakeSystem();
775 }
776 }
777 if ( sleepSlider > longestNonSleepSlider ) {
778 extraSleepDelay = sleepSlider - longestNonSleepSlider ;
779 }
780 else {
781 extraSleepDelay = 0;
782 }
783}
784
785
786// **********************************************************************************
787// sleepTimerExpired
788//
789// **********************************************************************************
790static void sleepTimerExpired ( thread_call_param_t us)
791{
792 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
793 }
794
795
796static void wakeupClamshellTimerExpired ( thread_call_param_t us)
797{
798 ((IOPMrootDomain *)us)->stopIgnoringClamshellEventsDuringWakeup();
799}
800
801
802// **********************************************************************************
803// handleSleepTimerExpiration
804//
805// The time between the sleep idle timeout and the next longest one has elapsed.
806// It's time to sleep. Start that by removing the clamp that's holding us awake.
807// **********************************************************************************
808void IOPMrootDomain::handleSleepTimerExpiration ( void )
809{
810 DEBUG_LOG("SleepTimerExpired\n");
811
812 AbsoluteTime time;
813
814 clock_get_uptime(&time);
815 if ((AbsoluteTime_to_scalar(&time) > autoWakeStart) && (AbsoluteTime_to_scalar(&time) < autoWakeEnd))
816 {
817 thread_call_enter_delayed(extraSleepTimer, *((AbsoluteTime *) &autoWakeEnd));
818 return;
819 }
820
821 // accelerate disk spin down if spin down timer is non-zero (zero = never spin down)
822 if(0 != user_spindown)
823 setQuickSpinDownTimeout();
824
825 sleepASAP = true;
826 adjustPowerState();
827}
828
829
830void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup(void)
831{
832 // Allow clamshell-induced sleep now
833 ignoringClamshellDuringWakeup = false;
834
835 // Re-send clamshell event, in case it causes a sleep
836 if(clamshellIsClosed)
837 this->receivePowerNotification( kLocalEvalClamshellCommand );
838}
839
840//*********************************************************************************
841// setAggressiveness
842//
843// Some aggressiveness factor has changed. We broadcast it to the hierarchy while on
844// the Power Mangement workloop thread. This enables objects in the
845// hierarchy to successfully alter their idle timers, which are all on the
846// same thread.
847//*********************************************************************************
848
849IOReturn IOPMrootDomain::setAggressiveness ( unsigned long type, unsigned long newLevel )
850{
851 IOWorkLoop * pmWorkLoop = getPMworkloop();
852 if (pmWorkLoop)
853 pmWorkLoop->runAction(broadcast_aggressiveness,this,(void *)type,(void *)newLevel);
854
855 return kIOReturnSuccess;
856}
857
858
859// **********************************************************************************
860// sleepSystem
861//
862// **********************************************************************************
863/* public */
864IOReturn IOPMrootDomain::sleepSystem ( void )
865{
866 return sleepSystemOptions (NULL);
867}
868
869/* private */
870IOReturn IOPMrootDomain::sleepSystemOptions ( OSDictionary *options )
871{
872 /* sleepSystem is a public function, and may be called by any kernel driver.
873 * And that's bad - drivers should sleep the system by calling
874 * receivePowerNotification() instead. Drivers should not use sleepSystem.
875 *
876 * Note that user space app calls to IOPMSleepSystem() will also travel
877 * this code path and thus be correctly identified as software sleeps.
878 */
879
880 if (options && options->getObject("OSSwitch"))
881 {
882
883 // Log specific sleep cause for OS Switch hibernation
884 return privateSleepSystem( kIOPMOSSwitchHibernationKey) ;
885
886 } else {
887
888 return privateSleepSystem( kIOPMSoftwareSleepKey);
889
890 }
891}
892
893/* private */
894IOReturn IOPMrootDomain::privateSleepSystem ( const char *sleepReason )
895{
896 // Record sleep cause in IORegistry
897 if (sleepReason) {
898 setProperty(kRootDomainSleepReasonKey, sleepReason);
899 }
900
901 if(systemShutdown) {
902 kprintf("Preventing system sleep on grounds of systemShutdown.\n");
903 }
904
905 if( userDisabledAllSleep )
906 {
907 /* Prevent sleep of all kinds if directed to by user space */
908 return kIOReturnNotPermitted;
909 }
910
911 if ( !systemBooting
912 && !systemShutdown
913 && allowSleep)
914 {
915 if ( !sleepIsSupported ) {
916 setSleepSupported( kPCICantSleep );
917 kprintf("Sleep prevented by kIOPMPreventSystemSleep flag\n");
918 }
919 patriarch->sleepSystem();
920 return kIOReturnSuccess;
921 } else {
922 // Unable to sleep because system is in the process of booting or shutting down,
923 // or sleep has otherwise been disallowed.
924 return kIOReturnError;
925 }
926}
927
928
929// **********************************************************************************
930// shutdownSystem
931//
932// **********************************************************************************
933IOReturn IOPMrootDomain::shutdownSystem ( void )
934{
935 //patriarch->shutDownSystem();
936 return kIOReturnUnsupported;
937}
938
939
940// **********************************************************************************
941// restartSystem
942//
943// **********************************************************************************
944IOReturn IOPMrootDomain::restartSystem ( void )
945{
946 //patriarch->restartSystem();
947 return kIOReturnUnsupported;
948}
949
950
951// **********************************************************************************
952// powerChangeDone
953//
954// This overrides powerChangeDone in IOService.
955//
956// Finder sleep and idle sleep move us from the ON state to the SLEEP_STATE.
957// In this case:
958// If we just finished going to the SLEEP_STATE, and the platform is capable of true sleep,
959// sleep the kernel. Otherwise switch up to the DOZE_STATE which will keep almost
960// everything as off as it can get.
961//
962// **********************************************************************************
963void IOPMrootDomain::powerChangeDone ( unsigned long previousState )
964{
965 OSNumber * propertyPtr;
966 unsigned short theProperty;
967 AbsoluteTime deadline;
968
969 DEBUG_LOG("PowerChangeDone: %ld -> %ld\n", previousState, getPowerState());
970
971 switch ( getPowerState() ) {
972 case SLEEP_STATE:
973 if ( previousState != ON_STATE )
974 break;
975
976 if ( canSleep && sleepIsSupported )
977 {
978 // re-enable this timer for next sleep
979 idleSleepPending = false;
980
981 uint32_t secs, microsecs;
982 clock_get_calendar_microtime(&secs, &microsecs);
983 logtime(secs);
984 gIOLastSleepTime.tv_sec = secs;
985 gIOLastSleepTime.tv_usec = microsecs;
986
987#if HIBERNATION
988 IOLog("System %sSleep\n", gIOHibernateState ? "Safe" : "");
989
990 IOHibernateSystemHasSlept();
991#else
992 IOLog("System Sleep\n");
993#endif
994
995 getPlatform()->sleepKernel();
996
997 // The CPU(s) are off at this point. When they're awakened by CPU interrupt,
998 // code will resume execution here.
999
1000 // Now we're waking...
1001#if HIBERNATION
1002 IOHibernateSystemWake();
1003#endif
1004
1005 // stay awake for at least 30 seconds
1006 clock_interval_to_deadline(30, kSecondScale, &deadline);
1007 thread_call_enter_delayed(extraSleepTimer, deadline);
1008 // this gets turned off when we sleep again
1009 idleSleepPending = true;
1010
1011 // Ignore closed clamshell during wakeup and for a few seconds
1012 // after wakeup is complete
1013 ignoringClamshellDuringWakeup = true;
1014
1015 // sleep transition complete
1016 gSleepOrShutdownPending = 0;
1017
1018 // trip the reset of the calendar clock
1019 clock_wakeup_calendar();
1020
1021 // get us some power
1022 patriarch->wakeSystem();
1023
1024 // early stage wake notification
1025 tellClients(kIOMessageSystemWillPowerOn);
1026
1027 // tell the tree we're waking
1028#if HIBERNATION
1029 IOLog("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
1030#endif
1031 systemWake();
1032
1033 // Allow drivers to request extra processing time before clamshell
1034 // sleep if kIOREMSleepEnabledKey is present.
1035 // Ignore clamshell events for at least 5 seconds
1036 if(getProperty(kIOREMSleepEnabledKey)) {
1037 // clamshellWakeupIgnore callout clears ignoreClamshellDuringWakeup bit
1038 clock_interval_to_deadline(5, kSecondScale, &deadline);
1039 if(clamshellWakeupIgnore) {
1040 thread_call_enter_delayed(clamshellWakeupIgnore, deadline);
1041 }
1042 } else ignoringClamshellDuringWakeup = false;
1043
1044 // Find out what woke us
1045 propertyPtr = OSDynamicCast(OSNumber,getProperty("WakeEvent"));
1046 if ( propertyPtr ) {
1047 theProperty = propertyPtr->unsigned16BitValue();
1048 IOLog("Wake event %04x\n",theProperty);
1049 if ( (theProperty & 0x0008) || //lid
1050 (theProperty & 0x0800) || // front panel button
1051 (theProperty & 0x0020) || // external keyboard
1052 (theProperty & 0x0001) ) { // internal keyboard
1053 // We've identified the wakeup event as UI driven
1054 reportUserInput();
1055 }
1056 } else {
1057 // Since we can't identify the wakeup event, treat it as UI activity
1058 reportUserInput();
1059 }
1060
1061 // Wake for thirty seconds
1062 changePowerStateToPriv(ON_STATE);
1063 } else {
1064 // allow us to step up a power state
1065 patriarch->sleepToDoze();
1066
1067 // ignore children's request for higher power during doze.
1068 powerOverrideOnPriv();
1069 changePowerStateToPriv(DOZE_STATE);
1070 }
1071 break;
1072
1073 case DOZE_STATE:
1074 if ( previousState != DOZE_STATE )
1075 {
1076 IOLog("System Doze\n");
1077 }
1078 // re-enable this timer for next sleep
1079 idleSleepPending = false;
1080 gSleepOrShutdownPending = 0;
1081
1082 // Invalidate prior activity tickles to allow wake from doze.
1083 if (wrangler) wrangler->changePowerStateTo(0);
1084 break;
1085
1086 case RESTART_STATE:
1087 IOLog("System Restart\n");
1088 PEHaltRestart(kPERestartCPU);
1089 break;
1090
1091 case OFF_STATE:
1092 IOLog("System Halt\n");
1093 PEHaltRestart(kPEHaltCPU);
1094 break;
1095 }
1096}
1097
1098
1099// **********************************************************************************
1100// wakeFromDoze
1101//
1102// The Display Wrangler calls here when it switches to its highest state. If the
1103// system is currently dozing, allow it to wake by making sure the parent is
1104// providing power.
1105// **********************************************************************************
1106void IOPMrootDomain::wakeFromDoze( void )
1107{
1108 if ( getPowerState() == DOZE_STATE )
1109 {
1110 // Reset sleep support till next sleep attempt.
1111 // A machine's support of sleep vs. doze can change over the course of
1112 // a running system, so we recalculate it before every sleep.
1113 setSleepSupported(0);
1114
1115 changePowerStateToPriv(ON_STATE);
1116 powerOverrideOffPriv();
1117
1118 // early wake notification
1119 tellClients(kIOMessageSystemWillPowerOn);
1120
1121 // allow us to wake if children so desire
1122 patriarch->wakeSystem();
1123 }
1124}
1125
1126
1127// *****************************************************************************
1128// publishFeature
1129//
1130// Adds a new feature to the supported features dictionary
1131//
1132//
1133// *****************************************************************************
1134void IOPMrootDomain::publishFeature( const char * feature )
1135{
1136 publishFeature(feature, kIOPMSupportedOnAC
1137 | kIOPMSupportedOnBatt
1138 | kIOPMSupportedOnUPS,
1139 NULL);
1140 return;
1141}
1142
1143
1144// *****************************************************************************
1145// publishFeature (with supported power source specified)
1146//
1147// Adds a new feature to the supported features dictionary
1148//
1149//
1150// *****************************************************************************
1151void IOPMrootDomain::publishFeature(
1152 const char *feature,
1153 uint32_t supportedWhere,
1154 uint32_t *uniqueFeatureID)
1155{
1156 static uint16_t next_feature_id = 500;
1157
1158 OSNumber *new_feature_data = NULL;
1159 OSNumber *existing_feature = NULL;
1160 OSArray *existing_feature_arr = NULL;
1161 OSObject *osObj = NULL;
1162 uint32_t feature_value = 0;
1163
1164 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
1165
1166// kprintf("IOPMrootDomain::publishFeature [\"%s\":%0x01x]\n", feature, supportedWhere);
1167
1168 if(!supportedWhere) {
1169 // Feature isn't supported anywhere!
1170 return;
1171 }
1172
1173 if(next_feature_id > 5000) {
1174 // Far, far too many features!
1175 return;
1176 }
1177
1178 if(featuresDictLock) IOLockLock(featuresDictLock);
1179
1180 OSDictionary *features =
1181 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
1182
1183 // Create new features dict if necessary
1184 if ( features && OSDynamicCast(OSDictionary, features)) {
1185 features = OSDictionary::withDictionary(features);
1186 } else {
1187 features = OSDictionary::withCapacity(1);
1188 }
1189
1190 // Create OSNumber to track new feature
1191
1192 next_feature_id += 1;
1193 if( uniqueFeatureID ) {
1194 // We don't really mind if the calling kext didn't give us a place
1195 // to stash their unique id. Many kexts don't plan to unload, and thus
1196 // have no need to remove themselves later.
1197 *uniqueFeatureID = next_feature_id;
1198 }
1199
1200 feature_value = supportedWhere + (next_feature_id << 16);
1201 new_feature_data = OSNumber::withNumber(
1202 (unsigned long long)feature_value, 32);
1203
1204 // Does features object already exist?
1205 if( (osObj = features->getObject(feature)) )
1206 {
1207 if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
1208 {
1209 // We need to create an OSArray to hold the now 2 elements.
1210 existing_feature_arr = OSArray::withObjects(
1211 (const OSObject **)&existing_feature, 1, 2);
1212 existing_feature_arr->setObject(new_feature_data);
1213 features->setObject(feature, existing_feature_arr);
1214 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
1215 {
1216 // Add object to existing array
1217 existing_feature_arr->setObject(new_feature_data);
1218 }
1219 } else {
1220 // The easy case: no previously existing features listed. We simply
1221 // set the OSNumber at key 'feature' and we're on our way.
1222 features->setObject(feature, new_feature_data);
1223 }
1224
1225 new_feature_data->release();
1226
1227 setProperty(kRootDomainSupportedFeatures, features);
1228
1229 features->release();
1230
1231 if(featuresDictLock) IOLockUnlock(featuresDictLock);
1232
1233 // Notify EnergySaver and all those in user space so they might
1234 // re-populate their feature specific UI
1235 if(pmPowerStateQueue) {
1236 pmPowerStateQueue->featureChangeOccurred(
1237 kIOPMMessageFeatureChange, this);
1238 }
1239}
1240
1241// *****************************************************************************
1242// removePublishedFeature
1243//
1244// Removes previously published feature
1245//
1246//
1247// *****************************************************************************
1248IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
1249{
1250 IOReturn ret = kIOReturnError;
1251 uint32_t feature_value = 0;
1252 uint16_t feature_id = 0;
1253 bool madeAChange = false;
1254
1255 OSSymbol *dictKey = NULL;
1256 OSCollectionIterator *dictIterator = NULL;
1257 OSArray *arrayMember = NULL;
1258 OSNumber *numberMember = NULL;
1259 OSObject *osObj = NULL;
1260 OSNumber *osNum = NULL;
1261
1262 if(featuresDictLock) IOLockLock(featuresDictLock);
1263
1264 OSDictionary *features =
1265 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
1266
1267 if ( features && OSDynamicCast(OSDictionary, features) )
1268 {
1269 // Any modifications to the dictionary are made to the copy to prevent
1270 // races & crashes with userland clients. Dictionary updated
1271 // automically later.
1272 features = OSDictionary::withDictionary(features);
1273 } else {
1274 features = NULL;
1275 ret = kIOReturnNotFound;
1276 goto exit;
1277 }
1278
1279 // We iterate 'features' dictionary looking for an entry tagged
1280 // with 'removeFeatureID'. If found, we remove it from our tracking
1281 // structures and notify the OS via a general interest message.
1282
1283 dictIterator = OSCollectionIterator::withCollection(features);
1284 if(!dictIterator) {
1285 goto exit;
1286 }
1287
1288 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
1289 {
1290 osObj = features->getObject(dictKey);
1291
1292 // Each Feature is either tracked by an OSNumber
1293 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
1294 {
1295 feature_value = numberMember->unsigned32BitValue();
1296 feature_id = (uint16_t)(feature_value >> 16);
1297
1298 if( feature_id == (uint16_t)removeFeatureID )
1299 {
1300 // Remove this node
1301 features->removeObject(dictKey);
1302 madeAChange = true;
1303 break;
1304 }
1305
1306 // Or tracked by an OSArray of OSNumbers
1307 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
1308 {
1309 unsigned int arrayCount = arrayMember->getCount();
1310
1311 for(unsigned int i=0; i<arrayCount; i++)
1312 {
1313 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
1314 if(!osNum) {
1315 continue;
1316 }
1317
1318 feature_value = osNum->unsigned32BitValue();
1319 feature_id = (uint16_t)(feature_value >> 16);
1320
1321 if( feature_id == (uint16_t)removeFeatureID )
1322 {
1323 // Remove this node
1324 if( 1 == arrayCount ) {
1325 // If the array only contains one element, remove
1326 // the whole thing.
1327 features->removeObject(dictKey);
1328 } else {
1329 // Otherwise just remove the element in question.
1330 arrayMember->removeObject(i);
1331 }
1332
1333 madeAChange = true;
1334 break;
1335 }
1336 }
1337 }
1338 }
1339
1340
1341 dictIterator->release();
1342
1343 if( madeAChange )
1344 {
1345 ret = kIOReturnSuccess;
1346
1347 setProperty(kRootDomainSupportedFeatures, features);
1348
1349 // Notify EnergySaver and all those in user space so they might
1350 // re-populate their feature specific UI
1351 if(pmPowerStateQueue) {
1352 pmPowerStateQueue->featureChangeOccurred(
1353 kIOPMMessageFeatureChange, this);
1354 }
1355 } else {
1356 ret = kIOReturnNotFound;
1357 }
1358
1359exit:
1360 if(features) features->release();
1361 if(featuresDictLock) IOLockUnlock(featuresDictLock);
1362 return ret;
1363}
1364
1365
1366// **********************************************************************************
1367// unIdleDevice
1368//
1369// Enqueues unidle event to be performed later in a serialized context.
1370//
1371// **********************************************************************************
1372void IOPMrootDomain::unIdleDevice( IOService *theDevice, unsigned long theState )
1373{
1374 if(pmPowerStateQueue)
1375 pmPowerStateQueue->unIdleOccurred(theDevice, theState);
1376}
1377
1378// **********************************************************************************
1379// announcePowerSourceChange
1380//
1381// Notifies "interested parties" that the batteries have changed state
1382//
1383// **********************************************************************************
1384void IOPMrootDomain::announcePowerSourceChange( void )
1385{
1386 IORegistryEntry *_batteryRegEntry = (IORegistryEntry *) getProperty("BatteryEntry");
1387
1388 // (if possible) re-publish power source state under IOPMrootDomain;
1389 // only do so if the battery controller publishes an IOResource
1390 // defining battery location. Called from ApplePMU battery driver.
1391
1392 if(_batteryRegEntry)
1393 {
1394 OSArray *batt_info;
1395 batt_info = (OSArray *) _batteryRegEntry->getProperty(kIOBatteryInfoKey);
1396 if(batt_info)
1397 setProperty(kIOBatteryInfoKey, batt_info);
1398 }
1399
1400}
1401
1402
1403// *****************************************************************************
1404// setPMSetting (private)
1405//
1406// Internal helper to relay PM settings changes from user space to individual
1407// drivers. Should be called only by IOPMrootDomain::setProperties.
1408//
1409// *****************************************************************************
1410IOReturn IOPMrootDomain::setPMSetting(
1411 const OSSymbol *type,
1412 OSObject *obj)
1413{
1414 OSArray *arr = NULL;
1415 PMSettingObject *p_obj = NULL;
1416 int count;
1417 int i;
1418
1419 if(NULL == type) return kIOReturnBadArgument;
1420
1421 IORecursiveLockLock(settingsCtrlLock);
1422
1423 fPMSettingsDict->setObject(type, obj);
1424
1425 arr = (OSArray *)settingsCallbacks->getObject(type);
1426 if(NULL == arr) goto exit;
1427 count = arr->getCount();
1428 for(i=0; i<count; i++) {
1429 p_obj = (PMSettingObject *)OSDynamicCast(PMSettingObject, arr->getObject(i));
1430 if(p_obj) p_obj->setPMSetting(type, obj);
1431 }
1432
1433exit:
1434 IORecursiveLockUnlock(settingsCtrlLock);
1435 return kIOReturnSuccess;
1436}
1437
1438// *****************************************************************************
1439// copyPMSetting (public)
1440//
1441// Allows kexts to safely read setting values, without being subscribed to
1442// notifications.
1443//
1444// *****************************************************************************
1445OSObject * IOPMrootDomain::copyPMSetting(
1446 OSSymbol *whichSetting)
1447{
1448 OSObject *obj = NULL;
1449
1450 if(!whichSetting) return NULL;
1451
1452 IORecursiveLockLock(settingsCtrlLock);
1453 obj = fPMSettingsDict->getObject(whichSetting);
1454 if(obj) {
1455 obj->retain();
1456 }
1457 IORecursiveLockUnlock(settingsCtrlLock);
1458
1459 return obj;
1460}
1461
1462// *****************************************************************************
1463// registerPMSettingController (public)
1464//
1465// direct wrapper to registerPMSettingController with uint32_t power source arg
1466// *****************************************************************************
1467IOReturn IOPMrootDomain::registerPMSettingController(
1468 const OSSymbol * settings[],
1469 IOPMSettingControllerCallback func,
1470 OSObject *target,
1471 uintptr_t refcon,
1472 OSObject **handle)
1473{
1474 return registerPMSettingController(
1475 settings,
1476 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
1477 func, target, refcon, handle);
1478}
1479
1480// *****************************************************************************
1481// registerPMSettingController (public)
1482//
1483// Kexts may register for notifications when a particular setting is changed.
1484// A list of settings is available in IOPM.h.
1485// Arguments:
1486// * settings - An OSArray containing OSSymbols. Caller should populate this
1487// array with a list of settings caller wants notifications from.
1488// * func - A C function callback of the type IOPMSettingControllerCallback
1489// * target - caller may provide an OSObject *, which PM will pass as an
1490// target to calls to "func"
1491// * refcon - caller may provide an void *, which PM will pass as an
1492// argument to calls to "func"
1493// * handle - This is a return argument. We will populate this pointer upon
1494// call success. Hold onto this and pass this argument to
1495// IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
1496// Returns:
1497// kIOReturnSuccess on success
1498// *****************************************************************************
1499IOReturn IOPMrootDomain::registerPMSettingController(
1500 const OSSymbol * settings[],
1501 uint32_t supportedPowerSources,
1502 IOPMSettingControllerCallback func,
1503 OSObject *target,
1504 uintptr_t refcon,
1505 OSObject **handle)
1506{
1507 PMSettingObject *pmso = NULL;
1508 OSArray *list = NULL;
1509 IOReturn ret = kIOReturnSuccess;
1510 int i;
1511
1512 if( NULL == settings ||
1513 NULL == func ||
1514 NULL == handle)
1515 {
1516 return kIOReturnBadArgument;
1517 }
1518
1519 pmso = PMSettingObject::pmSettingObject(
1520 (IOPMrootDomain *)this, func, target,
1521 refcon, supportedPowerSources, settings);
1522
1523 if(!pmso) {
1524 ret = kIOReturnInternalError;
1525 goto bail_no_unlock;
1526 }
1527
1528 IORecursiveLockLock(settingsCtrlLock);
1529 for(i=0; settings[i]; i++)
1530 {
1531 list = (OSArray *)settingsCallbacks->getObject(settings[i]);
1532 if(!list) {
1533 // New array of callbacks for this setting
1534 list = OSArray::withCapacity(1);
1535 settingsCallbacks->setObject(settings[i], list);
1536 list->release();
1537 }
1538
1539 // Add caller to the callback list
1540 list->setObject(pmso);
1541 }
1542
1543 IORecursiveLockUnlock(settingsCtrlLock);
1544
1545 ret = kIOReturnSuccess;
1546
1547 // Track this instance by its OSData ptr from now on
1548 *handle = pmso;
1549
1550bail_no_unlock:
1551 if(kIOReturnSuccess != ret)
1552 {
1553 // Error return case
1554 if(pmso) pmso->release();
1555 if(handle) *handle = NULL;
1556 }
1557 return ret;
1558}
1559
1560
1561//******************************************************************************
1562// sleepOnClamshellClosed
1563//
1564// contains the logic to determine if the system should sleep when the clamshell
1565// is closed.
1566//******************************************************************************
1567
1568bool IOPMrootDomain::shouldSleepOnClamshellClosed ( void )
1569{
1570 return ( !ignoringClamshell
1571 && !ignoringClamshellDuringWakeup
1572 && !(desktopMode && acAdaptorConnect) );
1573}
1574
1575void IOPMrootDomain::sendClientClamshellNotification ( void )
1576{
1577 /* Only broadcast clamshell alert if clamshell exists. */
1578 if(!clamshellExists)
1579 return;
1580
1581 setProperty(kAppleClamshellStateKey,
1582 clamshellIsClosed ? kOSBooleanTrue : kOSBooleanFalse);
1583
1584 setProperty(kAppleClamshellCausesSleepKey,
1585 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
1586
1587
1588 /* Argument to message is a bitfiel of
1589 * ( kClamshellStateBit | kClamshellSleepBit )
1590 */
1591 messageClients(kIOPMMessageClamshellStateChange,
1592 (void *) ( (clamshellIsClosed ? kClamshellStateBit : 0)
1593 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
1594}
1595
1596//******************************************************************************
1597// informCPUStateChange
1598//
1599// Call into PM CPU code so that CPU power savings may dynamically adjust for
1600// running on battery, with the lid closed, etc.
1601//
1602// informCPUStateChange is a no-op on non x86 systems
1603// only x86 has explicit support in the IntelCPUPowerManagement kext
1604//******************************************************************************
1605
1606void IOPMrootDomain::informCPUStateChange(
1607 uint32_t type,
1608 uint32_t value )
1609{
1610#ifdef __i386__
1611
1612 pmioctlVariableInfo_t varInfoStruct;
1613 int pmCPUret = 0;
1614 const char *varNameStr = NULL;
1615 int32_t *varIndex = NULL;
1616
1617 if (kInformAC == type) {
1618 varNameStr = kIOPMRootDomainBatPowerCString;
1619 varIndex = &idxPMCPULimitedPower;
1620 } else if (kInformLid == type) {
1621 varNameStr = kIOPMRootDomainLidCloseCString;
1622 varIndex = &idxPMCPUClamshell;
1623 } else {
1624 return;
1625 }
1626
1627 // Set the new value!
1628 // pmCPUControl will assign us a new ID if one doesn't exist yet
1629 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
1630 varInfoStruct.varID = *varIndex;
1631 varInfoStruct.varType = vBool;
1632 varInfoStruct.varInitValue = value;
1633 varInfoStruct.varCurValue = value;
1634 strncpy( (char *)varInfoStruct.varName,
1635 (const char *)varNameStr,
1636 strlen(varNameStr) + 1 );
1637
1638 // Set!
1639 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
1640
1641 // pmCPU only assigns numerical id's when a new varName is specified
1642 if ((0 == pmCPUret)
1643 && (*varIndex == kCPUUnknownIndex))
1644 {
1645 // pmCPUControl has assigned us a new variable ID.
1646 // Let's re-read the structure we just SET to learn that ID.
1647 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
1648
1649 if (0 == pmCPUret)
1650 {
1651 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
1652 *varIndex = varInfoStruct.varID;
1653 }
1654 }
1655
1656 return;
1657
1658#endif __i386__
1659}
1660
1661//******************************************************************************
1662// systemPowerEventOccurred
1663//
1664// The power controller is notifying us of a hardware-related power management
1665// event that we must handle.
1666//
1667// systemPowerEventOccurred covers the same functionality that receivePowerNotification
1668// does; it simply provides a richer API for conveying more information.
1669//******************************************************************************
1670IOReturn IOPMrootDomain::systemPowerEventOccurred(
1671 const OSSymbol *event,
1672 uint32_t intValue)
1673{
1674 IOReturn attempt = kIOReturnSuccess;
1675 OSNumber *newNumber = NULL;
1676
1677 if (!event)
1678 return kIOReturnBadArgument;
1679
1680 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
1681 if (!newNumber)
1682 return kIOReturnInternalError;
1683
1684 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
1685
1686 newNumber->release();
1687
1688 return attempt;
1689}
1690
1691IOReturn IOPMrootDomain::systemPowerEventOccurred(
1692 const OSSymbol *event,
1693 OSObject *value)
1694{
1695 OSDictionary *thermalsDict = NULL;
1696 bool shouldUpdate = true;
1697
1698 if (!event || !value)
1699 return kIOReturnBadArgument;
1700
1701 // LOCK
1702 // We reuse featuresDict Lock because it already exists and guards
1703 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
1704 // of stepping on that lock.
1705 if (featuresDictLock) IOLockLock(featuresDictLock);
1706
1707 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
1708
1709 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
1710 thermalsDict = OSDictionary::withDictionary(thermalsDict);
1711 } else {
1712 thermalsDict = OSDictionary::withCapacity(1);
1713 }
1714
1715 if (!thermalsDict) {
1716 shouldUpdate = false;
1717 goto exit;
1718 }
1719
1720 thermalsDict->setObject (event, value);
1721
1722 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
1723
1724 thermalsDict->release();
1725
1726exit:
1727 // UNLOCK
1728 if (featuresDictLock) IOLockUnlock(featuresDictLock);
1729
1730 if (shouldUpdate)
1731 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
1732
1733 return kIOReturnSuccess;
1734}
1735
1736
1737//******************************************************************************
1738// receivePowerNotification
1739//
1740// The power controller is notifying us of a hardware-related power management
1741// event that we must handle. This may be a result of an 'environment' interrupt from
1742// the power mgt micro.
1743//******************************************************************************
1744
1745IOReturn IOPMrootDomain::receivePowerNotification (UInt32 msg)
1746{
1747 bool eval_clamshell = false;
1748
1749 /*
1750 * Local (IOPMrootDomain only) eval clamshell command
1751 */
1752 if (msg & kLocalEvalClamshellCommand)
1753 {
1754 eval_clamshell = true;
1755 }
1756
1757 /*
1758 * Overtemp
1759 */
1760 if (msg & kIOPMOverTemp)
1761 {
1762 IOLog("PowerManagement emergency overtemp signal. Going to sleep!");
1763
1764 privateSleepSystem (kIOPMThermalEmergencySleepKey);
1765 }
1766
1767 /*
1768 * PMU Processor Speed Change
1769 */
1770 if (msg & kIOPMProcessorSpeedChange)
1771 {
1772 IOService *pmu = waitForService(serviceMatching("ApplePMU"));
1773 pmu->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
1774 getPlatform()->sleepKernel();
1775 pmu->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
1776 }
1777
1778 /*
1779 * Sleep Now!
1780 */
1781 if (msg & kIOPMSleepNow)
1782 {
1783 privateSleepSystem (kIOPMSoftwareSleepKey);
1784 }
1785
1786 /*
1787 * Power Emergency
1788 */
1789 if (msg & kIOPMPowerEmergency)
1790 {
1791 privateSleepSystem (kIOPMLowPowerSleepKey);
1792 }
1793
1794
1795 /*
1796 * Clamshell OPEN
1797 */
1798 if (msg & kIOPMClamshellOpened)
1799 {
1800 // Received clamshel open message from clamshell controlling driver
1801 // Update our internal state and tell general interest clients
1802 clamshellIsClosed = false;
1803 clamshellExists = true;
1804
1805 // Tell PMCPU
1806 informCPUStateChange(kInformLid, 0);
1807
1808 // Tell general interest clients
1809 sendClientClamshellNotification();
1810 }
1811
1812 /*
1813 * Clamshell CLOSED
1814 * Send the clamshell interest notification since the lid is closing.
1815 */
1816 if (msg & kIOPMClamshellClosed)
1817 {
1818 // Received clamshel open message from clamshell controlling driver
1819 // Update our internal state and tell general interest clients
1820 clamshellIsClosed = true;
1821 clamshellExists = true;
1822
1823 // Tell PMCPU
1824 informCPUStateChange(kInformLid, 1);
1825
1826 // Tell general interest clients
1827 sendClientClamshellNotification();
1828
1829 // And set eval_clamshell = so we can attempt
1830 eval_clamshell = true;
1831 }
1832
1833 /*
1834 * Set Desktop mode (sent from graphics)
1835 *
1836 * -> reevaluate lid state
1837 */
1838 if (msg & kIOPMSetDesktopMode)
1839 {
1840 desktopMode = (0 != (msg & kIOPMSetValue));
1841 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
1842
1843 sendClientClamshellNotification();
1844
1845 // Re-evaluate the lid state
1846 if( clamshellIsClosed )
1847 {
1848 eval_clamshell = true;
1849 }
1850 }
1851
1852 /*
1853 * AC Adaptor connected
1854 *
1855 * -> reevaluate lid state
1856 */
1857 if (msg & kIOPMSetACAdaptorConnected)
1858 {
1859 acAdaptorConnect = (0 != (msg & kIOPMSetValue));
1860 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
1861
1862 // Tell PMCPU
1863 informCPUStateChange(kInformAC, !acAdaptorConnect);
1864
1865 sendClientClamshellNotification();
1866
1867 // Re-evaluate the lid state
1868 if( clamshellIsClosed )
1869 {
1870 eval_clamshell = true;
1871 }
1872
1873 }
1874
1875 /*
1876 * Enable Clamshell (external display disappear)
1877 *
1878 * -> reevaluate lid state
1879 */
1880 if (msg & kIOPMEnableClamshell)
1881 {
1882 // Re-evaluate the lid state
1883 // System should sleep on external display disappearance
1884 // in lid closed operation.
1885 if( clamshellIsClosed && (true == ignoringClamshell) )
1886 {
1887 eval_clamshell = true;
1888 }
1889
1890 ignoringClamshell = false;
1891
1892 sendClientClamshellNotification();
1893 }
1894
1895 /*
1896 * Disable Clamshell (external display appeared)
1897 * We don't bother re-evaluating clamshell state. If the system is awake,
1898 * the lid is probably open.
1899 */
1900 if (msg & kIOPMDisableClamshell)
1901 {
1902 ignoringClamshell = true;
1903
1904 sendClientClamshellNotification();
1905 }
1906
1907 /*
1908 * Evaluate clamshell and SLEEP if appropiate
1909 */
1910 if ( eval_clamshell && shouldSleepOnClamshellClosed() )
1911 {
1912
1913
1914 // SLEEP!
1915 privateSleepSystem (kIOPMClamshellSleepKey);
1916 }
1917
1918 /*
1919 * Power Button
1920 */
1921 if (msg & kIOPMPowerButton)
1922 {
1923 // toggle state of sleep/wake
1924 // are we dozing?
1925 if ( getPowerState() == DOZE_STATE )
1926 {
1927 // yes, tell the tree we're waking
1928 systemWake();
1929 // wake the Display Wrangler
1930 reportUserInput();
1931 }
1932 else {
1933 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
1934 // Check that power button sleep is enabled
1935 if( pbs ) {
1936 if( kOSBooleanTrue != getProperty(pbs))
1937 privateSleepSystem (kIOPMPowerButtonSleepKey);
1938 }
1939 }
1940 }
1941
1942 /*
1943 * Allow Sleep
1944 *
1945 */
1946 if ( (msg & kIOPMAllowSleep) && !allowSleep )
1947 {
1948 allowSleep = true;
1949 adjustPowerState();
1950 }
1951
1952 /*
1953 * Prevent Sleep
1954 *
1955 */
1956 if (msg & kIOPMPreventSleep) {
1957 allowSleep = false;
1958 // are we dozing?
1959 if ( getPowerState() == DOZE_STATE ) {
1960 // yes, tell the tree we're waking
1961 systemWake();
1962 adjustPowerState();
1963 // wake the Display Wrangler
1964 reportUserInput();
1965 } else {
1966 adjustPowerState();
1967 // make sure we have power to clamp
1968 patriarch->wakeSystem();
1969 }
1970 }
1971
1972 return 0;
1973}
1974
1975
1976//*********************************************************************************
1977// sleepSupported
1978//
1979//*********************************************************************************
1980
1981void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
1982{
1983 if ( flags & kPCICantSleep )
1984 {
1985 canSleep = false;
1986 } else {
1987 canSleep = true;
1988 platformSleepSupport = flags;
1989 }
1990
1991 setProperty(kIOSleepSupportedKey, canSleep);
1992
1993}
1994
1995//*********************************************************************************
1996// requestPowerDomainState
1997//
1998// The root domain intercepts this call to the superclass.
1999// Called on the PM work loop thread.
2000//
2001// If the clamp bit is not set in the desire, then the child doesn't need the power
2002// state it's requesting; it just wants it. The root ignores desires but not needs.
2003// If the clamp bit is not set, the root takes it that the child can tolerate no
2004// power and interprets the request accordingly. If all children can thus tolerate
2005// no power, we are on our way to idle sleep.
2006//*********************************************************************************
2007
2008IOReturn IOPMrootDomain::requestPowerDomainState (
2009 IOPMPowerFlags desiredState,
2010 IOPowerConnection * whichChild,
2011 unsigned long specification )
2012{
2013 OSIterator *iter;
2014 OSObject *next;
2015 IOPowerConnection *connection;
2016 unsigned long powerRequestFlag = 0;
2017 IOPMPowerFlags editedDesire;
2018
2019#if DEBUG
2020 IOService *powerChild;
2021 powerChild = (IOService *) whichChild->getChildEntry(gIOPowerPlane);
2022#endif
2023
2024 DEBUG_LOG("RequestPowerDomainState: flags %lx, child %p [%s], spec %lx\n",
2025 desiredState, powerChild, powerChild ? powerChild->getName() : "?",
2026 specification);
2027
2028 // Force the child's input power requirements to 0 unless the prevent
2029 // idle-sleep flag is set. No input power flags map to our state 0.
2030 // Our power clamp (deviceDesire) keeps the minimum power state at 2.
2031
2032 if (desiredState & kIOPMPreventIdleSleep)
2033 editedDesire = desiredState;
2034 else
2035 editedDesire = 0;
2036
2037 // Recompute sleep supported flag (doze if not supported)
2038 sleepIsSupported = true;
2039
2040 iter = getChildIterator(gIOPowerPlane);
2041 if ( iter )
2042 {
2043 while ( (next = iter->getNextObject()) )
2044 {
2045 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
2046 {
2047 // Ignore child that are in the process of joining.
2048 if (connection->getReadyFlag() == false)
2049 continue;
2050
2051 // Is this connection attached to the child that called
2052 // requestPowerDomainState()?
2053
2054 if ( connection == whichChild )
2055 {
2056 // Yes, OR in the child's input power requirements.
2057 powerRequestFlag |= editedDesire;
2058
2059 if ( desiredState & kIOPMPreventSystemSleep )
2060 sleepIsSupported = false;
2061 }
2062 else
2063 {
2064#if DEBUG
2065 powerChild = (IOService *) connection->getChildEntry(gIOPowerPlane);
2066#endif
2067 DEBUG_LOG(" child %p, PState %ld, noIdle %d, noSleep %d, valid %d %s\n",
2068 powerChild,
2069 connection->getDesiredDomainState(),
2070 connection->getPreventIdleSleepFlag(),
2071 connection->getPreventSystemSleepFlag(),
2072 connection->getReadyFlag(),
2073 powerChild ? powerChild->getName() : "?");
2074
2075 // No, OR in the child's desired power domain state.
2076 // Which is our power state desired by this child.
2077 powerRequestFlag |= connection->getDesiredDomainState();
2078
2079 if ( connection->getPreventSystemSleepFlag() )
2080 sleepIsSupported = false;
2081 }
2082 }
2083 }
2084 iter->release();
2085 }
2086
2087 if ( !powerRequestFlag && !systemBooting )
2088 {
2089 if (!wrangler)
2090 {
2091 sleepASAP = false;
2092 changePowerStateToPriv(ON_STATE);
2093 if (idleSeconds)
2094 {
2095 AbsoluteTime deadline;
2096 // stay awake for at least idleSeconds
2097 clock_interval_to_deadline(idleSeconds, kSecondScale, &deadline);
2098 thread_call_enter_delayed(extraSleepTimer, deadline);
2099 // this gets turned off when we sleep again
2100 idleSleepPending = true;
2101 }
2102 }
2103 else if (extraSleepDelay == 0)
2104 {
2105 sleepASAP = true;
2106 }
2107 }
2108
2109 DEBUG_LOG(" sleepDelay %lx, mergedFlags %lx, sleepASAP %x, booting %x\n",
2110 extraSleepDelay, powerRequestFlag, sleepASAP, systemBooting);
2111
2112 // Drop our power clamp to SLEEP_STATE when all devices become idle.
2113 // Needed when the system sleep and display sleep timeouts are the same.
2114 // Otherwise, the extra sleep timer will also drop our power clamp.
2115
2116 adjustPowerState();
2117
2118 editedDesire |= (desiredState & kIOPMPreventSystemSleep);
2119
2120 // If our power clamp has already dropped to SLEEP_STATE, and no child
2121 // is keeping us at max power, then this will trigger idle sleep.
2122
2123 return super::requestPowerDomainState(editedDesire, whichChild, specification);
2124}
2125
2126
2127//*********************************************************************************
2128// getSleepSupported
2129//
2130//*********************************************************************************
2131
2132IOOptionBits IOPMrootDomain::getSleepSupported( void )
2133{
2134 return( platformSleepSupport );
2135}
2136
2137
2138//*********************************************************************************
2139// handlePlatformHaltRestart
2140//
2141//*********************************************************************************
2142
2143struct HaltRestartApplierContext {
2144 IOPMrootDomain * RootDomain;
2145 unsigned long PowerState;
2146 IOPMPowerFlags PowerFlags;
2147 UInt32 MessageType;
2148 UInt32 Counter;
2149};
2150
2151static void
2152platformHaltRestartApplier( OSObject * object, void * context )
2153{
2154 IOPowerStateChangeNotification notify;
2155 HaltRestartApplierContext * ctx;
2156 AbsoluteTime startTime;
2157 UInt32 deltaTime;
2158
2159 ctx = (HaltRestartApplierContext *) context;
2160
2161 memset(&notify, 0, sizeof(notify));
2162 notify.powerRef = (void *)ctx->Counter;
2163 notify.returnValue = 0;
2164 notify.stateNumber = ctx->PowerState;
2165 notify.stateFlags = ctx->PowerFlags;
2166
2167 clock_get_uptime(&startTime);
2168 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
2169 deltaTime = computeDeltaTimeMS(&startTime);
2170
2171 if ((deltaTime > kPMHaltTimeoutMS) || (gIOKitDebug & kIOLogDebugPower))
2172 {
2173 _IOServiceInterestNotifier * notifier;
2174 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
2175
2176 // IOService children of IOPMrootDomain are not instrumented.
2177 // Only IORootParent currently falls under that group.
2178
2179 if (notifier)
2180 {
2181 HaltRestartLog("%s handler %p took %lu ms\n",
2182 (ctx->MessageType == kIOMessageSystemWillPowerOff) ?
2183 "PowerOff" : "Restart",
2184 notifier->handler, deltaTime );
2185 }
2186 }
2187
2188 ctx->Counter++;
2189}
2190
2191void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
2192{
2193 HaltRestartApplierContext ctx;
2194 AbsoluteTime startTime;
2195 UInt32 deltaTime;
2196
2197 memset(&ctx, 0, sizeof(ctx));
2198 ctx.RootDomain = this;
2199
2200 clock_get_uptime(&startTime);
2201 switch (pe_type)
2202 {
2203 case kPEHaltCPU:
2204 ctx.PowerState = OFF_STATE;
2205 ctx.MessageType = kIOMessageSystemWillPowerOff;
2206 break;
2207
2208 case kPERestartCPU:
2209 ctx.PowerState = RESTART_STATE;
2210 ctx.MessageType = kIOMessageSystemWillRestart;
2211 break;
2212
2213 default:
2214 return;
2215 }
2216
2217 // Notify legacy clients
2218 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx);
2219
2220 // Notify in power tree order
2221 notifySystemShutdown(this, ctx.MessageType);
2222
2223 deltaTime = computeDeltaTimeMS(&startTime);
2224 HaltRestartLog("%s all drivers took %lu ms\n",
2225 (ctx.MessageType == kIOMessageSystemWillPowerOff) ?
2226 "PowerOff" : "Restart",
2227 deltaTime );
2228}
2229
2230
2231//*********************************************************************************
2232// tellChangeDown
2233//
2234// We override the superclass implementation so we can send a different message
2235// type to the client or application being notified.
2236//*********************************************************************************
2237
2238bool IOPMrootDomain::tellChangeDown ( unsigned long stateNum )
2239{
2240 switch ( stateNum ) {
2241 case DOZE_STATE:
2242 case SLEEP_STATE:
2243
2244 // Direct callout into OSMetaClass so it can disable kmod unloads
2245 // during sleep/wake to prevent deadlocks.
2246 OSMetaClassSystemSleepOrWake( kIOMessageSystemWillSleep );
2247
2248 return super::tellClientsWithResponse(kIOMessageSystemWillSleep);
2249 }
2250 return super::tellChangeDown(stateNum);
2251}
2252
2253
2254//*********************************************************************************
2255// askChangeDown
2256//
2257// We override the superclass implementation so we can send a different message
2258// type to the client or application being notified.
2259//
2260// This must be idle sleep since we don't ask apps during any other power change.
2261//*********************************************************************************
2262
2263bool IOPMrootDomain::askChangeDown ( unsigned long )
2264{
2265 return super::tellClientsWithResponse(kIOMessageCanSystemSleep);
2266}
2267
2268
2269//*********************************************************************************
2270// tellNoChangeDown
2271//
2272// Notify registered applications and kernel clients that we are not
2273// dropping power.
2274//
2275// We override the superclass implementation so we can send a different message
2276// type to the client or application being notified.
2277//
2278// This must be a vetoed idle sleep, since no other power change can be vetoed.
2279//*********************************************************************************
2280
2281void IOPMrootDomain::tellNoChangeDown ( unsigned long )
2282{
2283 if (idleSeconds && !wrangler)
2284 {
2285 AbsoluteTime deadline;
2286 sleepASAP = false;
2287 // stay awake for at least idleSeconds
2288 clock_interval_to_deadline(idleSeconds, kSecondScale, &deadline);
2289 thread_call_enter_delayed(extraSleepTimer, deadline);
2290 // this gets turned off when we sleep again
2291 idleSleepPending = true;
2292 }
2293 return tellClients(kIOMessageSystemWillNotSleep);
2294}
2295
2296
2297//*********************************************************************************
2298// tellChangeUp
2299//
2300// Notify registered applications and kernel clients that we are raising power.
2301//
2302// We override the superclass implementation so we can send a different message
2303// type to the client or application being notified.
2304//*********************************************************************************
2305
2306void IOPMrootDomain::tellChangeUp ( unsigned long stateNum)
2307{
2308 if ( stateNum == ON_STATE )
2309 {
2310 // Direct callout into OSMetaClass so it can disable kmod unloads
2311 // during sleep/wake to prevent deadlocks.
2312 OSMetaClassSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
2313
2314 if (getPowerState() == ON_STATE)
2315 {
2316 // this is a quick wake from aborted sleep
2317 if (idleSeconds && !wrangler)
2318 {
2319 AbsoluteTime deadline;
2320 sleepASAP = false;
2321 // stay awake for at least idleSeconds
2322 clock_interval_to_deadline(idleSeconds, kSecondScale, &deadline);
2323 thread_call_enter_delayed(extraSleepTimer, deadline);
2324 // this gets turned off when we sleep again
2325 idleSleepPending = true;
2326 }
2327 tellClients(kIOMessageSystemWillPowerOn);
2328 }
2329#if HIBERNATION
2330 else
2331 {
2332 IOHibernateSystemPostWake();
2333 }
2334#endif
2335 return tellClients(kIOMessageSystemHasPoweredOn);
2336 }
2337}
2338
2339//*********************************************************************************
2340// reportUserInput
2341//
2342//*********************************************************************************
2343
2344void IOPMrootDomain::reportUserInput ( void )
2345{
2346#if !NO_KERNEL_HID
2347 OSIterator * iter;
2348
2349 if(!wrangler)
2350 {
2351 iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
2352 if(iter)
2353 {
2354 wrangler = (IOService *) iter->getNextObject();
2355 iter->release();
2356 }
2357 }
2358
2359 if(wrangler)
2360 wrangler->activityTickle(0,0);
2361#endif
2362}
2363
2364//*********************************************************************************
2365// setQuickSpinDownTimeout
2366//
2367//*********************************************************************************
2368
2369void IOPMrootDomain::setQuickSpinDownTimeout ( void )
2370{
2371 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)1);
2372}
2373
2374//*********************************************************************************
2375// restoreUserSpinDownTimeout
2376//
2377//*********************************************************************************
2378
2379void IOPMrootDomain::restoreUserSpinDownTimeout ( void )
2380{
2381 super::setAggressiveness((unsigned long)kPMMinutesToSpinDown,(unsigned long)user_spindown);
2382}
2383
2384//*********************************************************************************
2385// changePowerStateTo & changePowerStateToPriv
2386//
2387// Override of these methods for logging purposes.
2388//*********************************************************************************
2389
2390IOReturn IOPMrootDomain::changePowerStateTo ( unsigned long ordinal )
2391{
2392 return super::changePowerStateTo(ordinal);
2393}
2394
2395IOReturn IOPMrootDomain::changePowerStateToPriv ( unsigned long ordinal )
2396{
2397 IOReturn ret;
2398
2399 DEBUG_LOG("ChangePowerStateToPriv: power state %ld\n", ordinal);
2400
2401 if ( (getPowerState() == DOZE_STATE) && (ordinal != ON_STATE) )
2402 {
2403 return kIOReturnSuccess;
2404 }
2405
2406 if( (userDisabledAllSleep || systemBooting || systemShutdown)
2407 && (ordinal == SLEEP_STATE) )
2408 {
2409 DEBUG_LOG(" sleep denied: disableAllSleep %d, booting %d, shutdown %d\n",
2410 userDisabledAllSleep, systemBooting, systemShutdown);
2411 super::changePowerStateToPriv(ON_STATE);
2412 }
2413
2414 if( (SLEEP_STATE == ordinal) && sleepSupportedPEFunction )
2415 {
2416
2417 // Determine if the machine supports sleep, or must doze.
2418 ret = getPlatform()->callPlatformFunction(
2419 sleepSupportedPEFunction, false,
2420 NULL, NULL, NULL, NULL);
2421
2422 // If the machine only supports doze, the callPlatformFunction call
2423 // boils down to IOPMrootDomain::setSleepSupported(kPCICantSleep),
2424 // otherwise nothing.
2425 }
2426
2427 return super::changePowerStateToPriv(ordinal);
2428}
2429
2430
2431//*********************************************************************************
2432// sysPowerDownHandler
2433//
2434// Receives a notification when the RootDomain changes state.
2435//
2436// Allows us to take action on system sleep, power down, and restart after
2437// applications have received their power change notifications and replied,
2438// but before drivers have powered down. We perform a vfs sync on power down.
2439//*********************************************************************************
2440
2441IOReturn IOPMrootDomain::sysPowerDownHandler( void * target, void * refCon,
2442 UInt32 messageType, IOService * service,
2443 void * messageArgument, vm_size_t argSize )
2444{
2445 IOReturn ret;
2446 IOPowerStateChangeNotification *params = (IOPowerStateChangeNotification *) messageArgument;
2447 IOPMrootDomain *rootDomain = OSDynamicCast(IOPMrootDomain, service);
2448
2449 if(!rootDomain)
2450 return kIOReturnUnsupported;
2451
2452 switch (messageType) {
2453 case kIOMessageSystemWillSleep:
2454 DEBUG_LOG("SystemWillSleep\n");
2455
2456 // Interested applications have been notified of an impending power
2457 // change and have acked (when applicable).
2458 // This is our chance to save whatever state we can before powering
2459 // down.
2460 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2461 // via callout
2462
2463 // We will ack within 20 seconds
2464 params->returnValue = 20 * 1000 * 1000;
2465#if HIBERNATION
2466 if (gIOHibernateState)
2467 params->returnValue += gIOHibernateFreeTime * 1000; //add in time we could spend freeing pages
2468#endif
2469
2470 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
2471 {
2472 // Purposely delay the ack and hope that shutdown occurs quickly.
2473 // Another option is not to schedule the thread and wait for
2474 // ack timeout...
2475 AbsoluteTime deadline;
2476 clock_interval_to_deadline( 30, kSecondScale, &deadline );
2477 thread_call_enter1_delayed( rootDomain->diskSyncCalloutEntry,
2478 (thread_call_param_t)params->powerRef,
2479 deadline );
2480 }
2481 else
2482 thread_call_enter1(rootDomain->diskSyncCalloutEntry, (thread_call_param_t)params->powerRef);
2483 ret = kIOReturnSuccess;
2484 break;
2485
2486 case kIOMessageSystemWillPowerOff:
2487 case kIOMessageSystemWillRestart:
2488 ret = kIOReturnUnsupported;
2489 break;
2490
2491 default:
2492 ret = kIOReturnUnsupported;
2493 break;
2494 }
2495 return ret;
2496}
2497
2498//*********************************************************************************
2499// displayWranglerNotification
2500//
2501// Receives a notification when the IODisplayWrangler changes state.
2502//
2503// Allows us to take action on display dim/undim.
2504//
2505// When the display sleeps we:
2506// - Start the idle sleep timer
2507// - set the quick spin down timeout
2508//
2509// On wake from display sleep:
2510// - Cancel the idle sleep timer
2511// - restore the user's chosen spindown timer from the "quick" spin down value
2512//*********************************************************************************
2513
2514IOReturn IOPMrootDomain::displayWranglerNotification(
2515 void * target, void * refCon,
2516 UInt32 messageType, IOService * service,
2517 void * messageArgument, vm_size_t argSize )
2518{
2519#if !NO_KERNEL_HID
2520 IOPMrootDomain * rootDomain = OSDynamicCast(IOPMrootDomain, (IOService *)target);
2521 AbsoluteTime deadline;
2522 static int displayPowerState = 4;
2523
2524 if (!rootDomain)
2525 return kIOReturnUnsupported;
2526
2527 switch (messageType) {
2528 case kIOMessageDeviceWillPowerOff:
2529 DEBUG_LOG("DisplayWranglerWillPowerOff: new p-state %d\n",
2530 displayPowerState - 1);
2531
2532 // The display wrangler has dropped power because of idle display sleep
2533 // or force system sleep. We will receive 4 messages before the display
2534 // wrangler reaches its lowest state. Act only when going to state 2.
2535 //
2536 // 4->3 Display Dim
2537 // 3->2 Display Sleep
2538 // 2->1 Not visible to user
2539 // 1->0 Not visible to user
2540
2541 displayPowerState--;
2542 if ( 2 != displayPowerState )
2543 return kIOReturnUnsupported;
2544
2545 // We start a timer here if the System Sleep timer is greater than the
2546 // Display Sleep timer. We kick off this timer when the display sleeps.
2547 //
2548 // Note that, although Display Dim timings may change adaptively accordingly
2549 // to the user's activity patterns, Display Sleep _always_ occurs at the
2550 // specified interval since last user activity.
2551
2552 if ( rootDomain->extraSleepDelay )
2553 {
2554 clock_interval_to_deadline(rootDomain->extraSleepDelay*60, kSecondScale, &deadline);
2555 thread_call_enter_delayed(rootDomain->extraSleepTimer, deadline);
2556 rootDomain->idleSleepPending = true;
2557 DEBUG_LOG(" sleep timer set to expire in %ld min\n",
2558 rootDomain->extraSleepDelay);
2559 } else {
2560 // Accelerate disk spindown if system sleep and display sleep
2561 // sliders are set to the same value (e.g. both set to 5 min),
2562 // and display is about to go dark. Check that spin down timer
2563 // is non-zero (zero = never spin down) and system sleep is
2564 // not set to never sleep.
2565
2566 if ( (0 != rootDomain->user_spindown) && (0 != rootDomain->sleepSlider) )
2567 {
2568 DEBUG_LOG(" accelerate quick disk spindown, was %d min\n",
2569 rootDomain->user_spindown);
2570 rootDomain->setQuickSpinDownTimeout();
2571 }
2572 }
2573
2574 break;
2575
2576 case kIOMessageDeviceHasPoweredOn:
2577 DEBUG_LOG("DisplayWranglerHasPoweredOn: previous p-state %d\n",
2578 displayPowerState);
2579
2580 // The display wrangler has powered on either because of user activity
2581 // or wake from sleep/doze.
2582
2583 displayPowerState = 4;
2584 rootDomain->adjustPowerState();
2585
2586 // cancel any pending idle sleep timers
2587 if (rootDomain->idleSleepPending)
2588 {
2589 DEBUG_LOG(" extra-sleep timer stopped\n");
2590 thread_call_cancel(rootDomain->extraSleepTimer);
2591 rootDomain->idleSleepPending = false;
2592 }
2593
2594 // Change the spindown value back to the user's selection from our
2595 // accelerated setting.
2596 if (0 != rootDomain->user_spindown)
2597 {
2598 DEBUG_LOG(" restoring disk spindown to %d min\n",
2599 rootDomain->user_spindown);
2600 rootDomain->restoreUserSpinDownTimeout();
2601 }
2602
2603 break;
2604
2605 default:
2606 break;
2607 }
2608#endif
2609 return kIOReturnUnsupported;
2610 }
2611
2612//*********************************************************************************
2613// displayWranglerPublished
2614//
2615// Receives a notification when the IODisplayWrangler is published.
2616// When it's published we install a power state change handler.
2617//
2618//*********************************************************************************
2619
2620bool IOPMrootDomain::displayWranglerPublished(
2621 void * target,
2622 void * refCon,
2623 IOService * newService)
2624{
2625#if !NO_KERNEL_HID
2626 IOPMrootDomain *rootDomain =
2627 OSDynamicCast(IOPMrootDomain, (IOService *)target);
2628
2629 if(!rootDomain)
2630 return false;
2631
2632 rootDomain->wrangler = newService;
2633
2634 // we found the display wrangler, now install a handler
2635 if( !rootDomain->wrangler->registerInterest( gIOGeneralInterest,
2636 &displayWranglerNotification, target, 0) )
2637 {
2638 return false;
2639 }
2640#endif
2641 return true;
2642}
2643
2644//*********************************************************************************
2645// batteryPublished
2646//
2647// Notification on battery class IOPowerSource appearance
2648//
2649//******************************************************************************
2650
2651bool IOPMrootDomain::batteryPublished(
2652 void * target,
2653 void * root_domain,
2654 IOService * resourceService )
2655{
2656 // rdar://2936060&4435589
2657 // All laptops have dimmable LCD displays
2658 // All laptops have batteries
2659 // So if this machine has a battery, publish the fact that the backlight
2660 // supports dimming.
2661 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
2662
2663 return (true);
2664}
2665
2666//*********************************************************************************
2667// adjustPowerState
2668//
2669// Some condition that affects our wake/sleep/doze decision has changed.
2670//
2671// If the sleep slider is in the off position, we cannot sleep or doze.
2672// If the enclosure is open, we cannot sleep or doze.
2673// If the system is still booting, we cannot sleep or doze.
2674//
2675// In those circumstances, we prevent sleep and doze by holding power on with
2676// changePowerStateToPriv(ON).
2677//
2678// If the above conditions do not exist, and also the sleep timer has expired, we
2679// allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
2680// changePowerStateToPriv(DOZE) depending on whether or not we already know the
2681// platform cannot sleep.
2682//
2683// In this case, sleep or doze will either occur immediately or at the next time
2684// that no children are holding the system out of idle sleep via the
2685// kIOPMPreventIdleSleep flag in their power state arrays.
2686//*********************************************************************************
2687
2688void IOPMrootDomain::adjustPowerState( void )
2689{
2690 if ( (sleepSlider == 0)
2691 || !allowSleep
2692 || systemBooting
2693 || systemShutdown
2694 || userDisabledAllSleep )
2695 {
2696 DEBUG_LOG("AdjustPowerState %ld -> ON: slider %ld, allowSleep %d, "
2697 "booting %d, shutdown %d, userDisabled %d\n",
2698 getPowerState(), sleepSlider, allowSleep, systemBooting,
2699 systemShutdown, userDisabledAllSleep);
2700
2701 changePowerStateToPriv(ON_STATE);
2702 } else {
2703 if ( sleepASAP )
2704 {
2705 DEBUG_LOG("AdjustPowerState SLEEP\n");
2706
2707 /* Convenient place to run any code at idle sleep time
2708 * IOPMrootDomain initiates an idle sleep here
2709 *
2710 * Set last sleep cause accordingly.
2711 */
2712 setProperty(kRootDomainSleepReasonKey, kIOPMIdleSleepKey);
2713
2714 sleepASAP = false;
2715 if ( !sleepIsSupported )
2716 {
2717 setSleepSupported( kPCICantSleep );
2718 kprintf("Sleep prevented by kIOPMPreventSystemSleep flag\n");
2719 }
2720 changePowerStateToPriv(SLEEP_STATE);
2721 }
2722 }
2723}
2724
2725//*********************************************************************************
2726// PMHaltWorker Class
2727//
2728//*********************************************************************************
2729
2730static unsigned int gPMHaltBusyCount;
2731static unsigned int gPMHaltIdleCount;
2732static int gPMHaltDepth;
2733static unsigned long gPMHaltEvent;
2734static IOLock * gPMHaltLock = 0;
2735static OSArray * gPMHaltArray = 0;
2736static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
2737
2738PMHaltWorker * PMHaltWorker::worker( void )
2739{
2740 PMHaltWorker * me;
2741 IOThread thread;
2742
2743 do {
2744 me = OSTypeAlloc( PMHaltWorker );
2745 if (!me || !me->init())
2746 break;
2747
2748 me->lock = IOLockAlloc();
2749 if (!me->lock)
2750 break;
2751
2752 DEBUG_LOG("PMHaltWorker %p\n", me);
2753 me->retain(); // thread holds extra retain
2754 thread = IOCreateThread( &PMHaltWorker::main, me );
2755 if (!thread)
2756 {
2757 me->release();
2758 break;
2759 }
2760 return me;
2761
2762 } while (false);
2763
2764 if (me) me->release();
2765 return 0;
2766}
2767
2768void PMHaltWorker::free( void )
2769{
2770 DEBUG_LOG("PMHaltWorker free %p\n", this);
2771 if (lock)
2772 {
2773 IOLockFree(lock);
2774 lock = 0;
2775 }
2776 return OSObject::free();
2777}
2778
2779void PMHaltWorker::main( void * arg )
2780{
2781 PMHaltWorker * me = (PMHaltWorker *) arg;
2782
2783 IOLockLock( gPMHaltLock );
2784 gPMHaltBusyCount++;
2785 me->depth = gPMHaltDepth;
2786 IOLockUnlock( gPMHaltLock );
2787
2788 while (me->depth >= 0)
2789 {
2790 PMHaltWorker::work( me );
2791
2792 IOLockLock( gPMHaltLock );
2793 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
2794 {
2795 // This is the last thread to finish work on this level,
2796 // inform everyone to start working on next lower level.
2797 gPMHaltDepth--;
2798 me->depth = gPMHaltDepth;
2799 gPMHaltIdleCount = 0;
2800 thread_wakeup((event_t) &gPMHaltIdleCount);
2801 }
2802 else
2803 {
2804 // One or more threads are still working on this level,
2805 // this thread must wait.
2806 me->depth = gPMHaltDepth - 1;
2807 do {
2808 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
2809 } while (me->depth != gPMHaltDepth);
2810 }
2811 IOLockUnlock( gPMHaltLock );
2812 }
2813
2814 // No more work to do, terminate thread
2815 DEBUG_LOG("All done for worker: %p (visits = %u)\n", me, me->visits);
2816 thread_wakeup( &gPMHaltDepth );
2817 me->release();
2818}
2819
2820void PMHaltWorker::work( PMHaltWorker * me )
2821{
2822 IOService * service;
2823 OSSet * inner;
2824 AbsoluteTime startTime;
2825 UInt32 deltaTime;
2826 bool timeout;
2827
2828 while (true)
2829 {
2830 service = 0;
2831 timeout = false;
2832
2833 // Claim an unit of work from the shared pool
2834 IOLockLock( gPMHaltLock );
2835 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
2836 if (inner)
2837 {
2838 service = (IOService *)inner->getAnyObject();
2839 if (service)
2840 {
2841 service->retain();
2842 inner->removeObject(service);
2843 }
2844 }
2845 IOLockUnlock( gPMHaltLock );
2846 if (!service)
2847 break; // no more work at this depth
2848
2849 clock_get_uptime(&startTime);
2850
2851 if (!service->isInactive() &&
2852 service->setProperty(gPMHaltClientAcknowledgeKey, me))
2853 {
2854 IOLockLock(me->lock);
2855 me->startTime = startTime;
2856 me->service = service;
2857 me->timeout = false;
2858 IOLockUnlock(me->lock);
2859
2860 service->systemWillShutdown( gPMHaltEvent );
2861
2862 // Wait for driver acknowledgement
2863 IOLockLock(me->lock);
2864 while (service->getProperty(gPMHaltClientAcknowledgeKey))
2865 {
2866 IOLockSleep(me->lock, me, THREAD_UNINT);
2867 }
2868 me->service = 0;
2869 timeout = me->timeout;
2870 IOLockUnlock(me->lock);
2871 }
2872
2873 deltaTime = computeDeltaTimeMS(&startTime);
2874 if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
2875 (gIOKitDebug & kIOLogDebugPower))
2876 {
2877 HaltRestartLog("%s driver %s (%p) took %lu ms\n",
2878 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
2879 "PowerOff" : "Restart",
2880 service->getName(), service,
2881 deltaTime );
2882 }
2883
2884 service->release();
2885 me->visits++;
2886 }
2887}
2888
2889void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
2890{
2891 UInt64 nano;
2892 AbsoluteTime startTime;
2893 AbsoluteTime endTime;
2894
2895 endTime = *now;
2896
2897 IOLockLock(me->lock);
2898 if (me->service && !me->timeout)
2899 {
2900 startTime = me->startTime;
2901 nano = 0;
2902 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
2903 {
2904 SUB_ABSOLUTETIME(&endTime, &startTime);
2905 absolutetime_to_nanoseconds(endTime, &nano);
2906 }
2907 if (nano > 3000000000ULL)
2908 {
2909 me->timeout = true;
2910 HaltRestartLog("%s still waiting on %s\n",
2911 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
2912 "PowerOff" : "Restart",
2913 me->service->getName());
2914 }
2915 }
2916 IOLockUnlock(me->lock);
2917}
2918
2919//*********************************************************************************
2920// acknowledgeSystemWillShutdown
2921//
2922// Acknowledgement from drivers that they have prepared for shutdown/restart.
2923//*********************************************************************************
2924
2925void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
2926{
2927 PMHaltWorker * worker;
2928 OSObject * prop;
2929
2930 if (!from)
2931 return;
2932
2933 //DEBUG_LOG("%s acknowledged\n", from->getName());
2934 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
2935 if (prop)
2936 {
2937 worker = (PMHaltWorker *) prop;
2938 IOLockLock(worker->lock);
2939 from->removeProperty( gPMHaltClientAcknowledgeKey );
2940 thread_wakeup((event_t) worker);
2941 IOLockUnlock(worker->lock);
2942 worker->release();
2943 }
2944 else
2945 {
2946 DEBUG_LOG("%s acknowledged without worker property\n",
2947 from->getName());
2948 }
2949}
2950
2951//*********************************************************************************
2952// notifySystemShutdown
2953//
2954// Notify all objects in PM tree that system will shutdown or restart
2955//*********************************************************************************
2956
2957static void
2958notifySystemShutdown( IOService * root, unsigned long event )
2959{
2960#define PLACEHOLDER ((OSSet *)gPMHaltArray)
2961 IORegistryIterator * iter;
2962 IORegistryEntry * entry;
2963 IOService * node;
2964 OSSet * inner;
2965 PMHaltWorker * workers[kPMHaltMaxWorkers];
2966 AbsoluteTime deadline;
2967 unsigned int totalNodes = 0;
2968 unsigned int depth;
2969 unsigned int rootDepth;
2970 unsigned int numWorkers;
2971 unsigned int count;
2972 int waitResult;
2973 void * baseFunc;
2974 bool ok;
2975
2976 DEBUG_LOG("%s event = %lx\n", __FUNCTION__, event);
2977
2978 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
2979
2980 // Iterate the entire PM tree starting from root
2981
2982 rootDepth = root->getDepth( gIOPowerPlane );
2983 if (!rootDepth) goto done;
2984
2985 // debug - for repeated test runs
2986 while (PMHaltWorker::metaClass->getInstanceCount())
2987 IOSleep(1);
2988
2989 if (!gPMHaltArray)
2990 {
2991 gPMHaltArray = OSArray::withCapacity(40);
2992 if (!gPMHaltArray) goto done;
2993 }
2994 else // debug
2995 gPMHaltArray->flushCollection();
2996
2997 if (!gPMHaltLock)
2998 {
2999 gPMHaltLock = IOLockAlloc();
3000 if (!gPMHaltLock) goto done;
3001 }
3002
3003 if (!gPMHaltClientAcknowledgeKey)
3004 {
3005 gPMHaltClientAcknowledgeKey =
3006 OSSymbol::withCStringNoCopy("PMShutdown");
3007 if (!gPMHaltClientAcknowledgeKey) goto done;
3008 }
3009
3010 gPMHaltEvent = event;
3011
3012 // Depth-first walk of PM plane
3013
3014 iter = IORegistryIterator::iterateOver(
3015 root, gIOPowerPlane, kIORegistryIterateRecursively);
3016
3017 if (iter)
3018 {
3019 while ((entry = iter->getNextObject()))
3020 {
3021 node = OSDynamicCast(IOService, entry);
3022 if (!node)
3023 continue;
3024
3025 if (baseFunc ==
3026 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
3027 continue;
3028
3029 depth = node->getDepth( gIOPowerPlane );
3030 if (depth <= rootDepth)
3031 continue;
3032
3033 ok = false;
3034
3035 // adjust to zero based depth
3036 depth -= (rootDepth + 1);
3037
3038 // gPMHaltArray is an array of containers, each container
3039 // refers to nodes with the same depth.
3040
3041 count = gPMHaltArray->getCount();
3042 while (depth >= count)
3043 {
3044 // expand array and insert placeholders
3045 gPMHaltArray->setObject(PLACEHOLDER);
3046 count++;
3047 }
3048 count = gPMHaltArray->getCount();
3049 if (depth < count)
3050 {
3051 inner = (OSSet *)gPMHaltArray->getObject(depth);
3052 if (inner == PLACEHOLDER)
3053 {
3054 inner = OSSet::withCapacity(40);
3055 if (inner)
3056 {
3057 gPMHaltArray->replaceObject(depth, inner);
3058 inner->release();
3059 }
3060 }
3061
3062 // PM nodes that appear more than once in the tree will have
3063 // the same depth, OSSet will refuse to add the node twice.
3064 if (inner)
3065 ok = inner->setObject(node);
3066 }
3067 if (!ok)
3068 DEBUG_LOG("Skipped PM node %s\n", node->getName());
3069 }
3070 iter->release();
3071 }
3072
3073 // debug only
3074 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
3075 {
3076 count = 0;
3077 if (inner != PLACEHOLDER)
3078 count = inner->getCount();
3079 DEBUG_LOG("Nodes at depth %u = %u\n", i, count);
3080 }
3081
3082 // strip placeholders (not all depths are populated)
3083 numWorkers = 0;
3084 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
3085 {
3086 if (inner == PLACEHOLDER)
3087 {
3088 gPMHaltArray->removeObject(i);
3089 continue;
3090 }
3091 count = inner->getCount();
3092 if (count > numWorkers)
3093 numWorkers = count;
3094 totalNodes += count;
3095 i++;
3096 }
3097
3098 if (gPMHaltArray->getCount() == 0 || !numWorkers)
3099 goto done;
3100
3101 gPMHaltBusyCount = 0;
3102 gPMHaltIdleCount = 0;
3103 gPMHaltDepth = gPMHaltArray->getCount() - 1;
3104
3105 // Create multiple workers (and threads)
3106
3107 if (numWorkers > kPMHaltMaxWorkers)
3108 numWorkers = kPMHaltMaxWorkers;
3109
3110 DEBUG_LOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
3111 totalNodes, gPMHaltArray->getCount(), numWorkers);
3112
3113 for (unsigned int i = 0; i < numWorkers; i++)
3114 workers[i] = PMHaltWorker::worker();
3115
3116 // Wait for workers to exhaust all available work
3117
3118 IOLockLock(gPMHaltLock);
3119 while (gPMHaltDepth >= 0)
3120 {
3121 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
3122
3123 waitResult = IOLockSleepDeadline(
3124 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
3125 if (THREAD_TIMED_OUT == waitResult)
3126 {
3127 AbsoluteTime now;
3128 clock_get_uptime(&now);
3129
3130 IOLockUnlock(gPMHaltLock);
3131 for (unsigned int i = 0 ; i < numWorkers; i++)
3132 {
3133 if (workers[i])
3134 PMHaltWorker::checkTimeout(workers[i], &now);
3135 }
3136 IOLockLock(gPMHaltLock);
3137 }
3138 }
3139 IOLockUnlock(gPMHaltLock);
3140
3141 // Release all workers
3142
3143 for (unsigned int i = 0; i < numWorkers; i++)
3144 {
3145 if (workers[i])
3146 workers[i]->release();
3147 // worker also retained by it's own thread
3148 }
3149
3150done:
3151 DEBUG_LOG("%s done\n", __FUNCTION__);
3152 return;
3153}
3154
3155#if DEBUG_TEST
3156// debug - exercise notifySystemShutdown()
3157bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
3158{
3159 IOPMrootDomain * root = (IOPMrootDomain *) this;
3160 notifySystemShutdown( root, kIOMessageSystemWillPowerOff );
3161 return( super::serializeProperties(s) );
3162}
3163#endif
3164
3165/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3166
3167
3168
3169#undef super
3170#define super OSObject
3171OSDefineMetaClassAndStructors(PMSettingObject, OSObject)
3172
3173void PMSettingObject::setPMSetting(const OSSymbol *type, OSObject *obj)
3174{
3175 (*func)(target, type, obj, refcon);
3176}
3177
3178/*
3179 * Static constructor/initializer for PMSettingObject
3180 */
3181PMSettingObject *PMSettingObject::pmSettingObject(
3182 IOPMrootDomain *parent_arg,
3183 IOPMSettingControllerCallback handler_arg,
3184 OSObject *target_arg,
3185 uintptr_t refcon_arg,
3186 uint32_t supportedPowerSources,
3187 const OSSymbol * settings[])
3188{
3189 uint32_t objCount = 0;
3190 PMSettingObject *pmso;
3191
3192 if( !parent_arg || !handler_arg || !settings ) return NULL;
3193
3194 // count OSSymbol entries in NULL terminated settings array
3195 while( settings[objCount] ) {
3196 objCount++;
3197 }
3198 if(0 == objCount) return NULL;
3199
3200 pmso = new PMSettingObject;
3201 if(!pmso || !pmso->init()) return NULL;
3202
3203 pmso->parent = parent_arg;
3204 pmso->func = handler_arg;
3205 pmso->target = target_arg;
3206 pmso->refcon = refcon_arg;
3207 pmso->releaseAtCount = objCount + 1; // release when it has count+1 retains
3208
3209 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount);
3210 if(pmso->publishedFeatureID) {
3211 for(unsigned int i=0; i<objCount; i++) {
3212 // Since there is now at least one listener to this setting, publish
3213 // PM root domain support for it.
3214 parent_arg->publishFeature( settings[i]->getCStringNoCopy(),
3215 supportedPowerSources, &pmso->publishedFeatureID[i] );
3216 }
3217 }
3218
3219 return pmso;
3220}
3221
3222void PMSettingObject::free(void)
3223{
3224 OSCollectionIterator *settings_iter;
3225 OSSymbol *sym;
3226 OSArray *arr;
3227 int arr_idx;
3228 int i;
3229 int objCount = releaseAtCount - 1;
3230
3231 if(publishedFeatureID) {
3232 for(i=0; i<objCount; i++) {
3233 if(0 != publishedFeatureID[i]) {
3234 parent->removePublishedFeature( publishedFeatureID[i] );
3235 }
3236 }
3237
3238 IOFree(publishedFeatureID, sizeof(uint32_t) * objCount);
3239 }
3240
3241 IORecursiveLockLock(parent->settingsCtrlLock);
3242
3243 // Search each PM settings array in the kernel.
3244 settings_iter = OSCollectionIterator::withCollection(parent->settingsCallbacks);
3245 if(settings_iter)
3246 {
3247 while(( sym = OSDynamicCast(OSSymbol, settings_iter->getNextObject()) ))
3248 {
3249 arr = (OSArray *)parent->settingsCallbacks->getObject(sym);
3250 arr_idx = arr->getNextIndexOfObject(this, 0);
3251 if(-1 != arr_idx) {
3252 // 'this' was found in the array; remove it
3253 arr->removeObject(arr_idx);
3254 }
3255 }
3256
3257 settings_iter->release();
3258 }
3259
3260 IORecursiveLockUnlock(parent->settingsCtrlLock);
3261
3262 super::free();
3263}
3264
3265void PMSettingObject::taggedRelease(const void *tag, const int when) const
3266{
3267 // We have n+1 retains - 1 per array that this PMSettingObject is a member
3268 // of, and 1 retain to ourself. When we get a release with n+1 retains
3269 // remaining, we go ahead and free ourselves, cleaning up array pointers
3270 // in free();
3271
3272 super::taggedRelease(tag, releaseAtCount);
3273}
3274
3275
3276
3277/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3278
3279#undef super
3280#define super IOService
3281
3282OSDefineMetaClassAndStructors(IORootParent, IOService)
3283
3284// This array exactly parallels the state array for the root domain.
3285// Power state changes initiated by a device can be vetoed by a client of the device, and
3286// power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
3287// so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
3288// its parent to make the change. That is the reason for this complexity.
3289
3290static IOPMPowerState patriarchPowerStates[number_of_power_states] = {
3291 {1,0,0,0,0,0,0,0,0,0,0,0}, // off
3292 {1,0,RESTART_POWER,0,0,0,0,0,0,0,0,0}, // reset
3293 {1,0,SLEEP_POWER,0,0,0,0,0,0,0,0,0}, // sleep
3294 {1,0,DOZE_POWER,0,0,0,0,0,0,0,0,0}, // doze
3295 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0} // running
3296};
3297
3298bool IORootParent::start ( IOService * nub )
3299{
3300 mostRecentChange = ON_STATE;
3301 super::start(nub);
3302 PMinit();
3303 youAreRoot();
3304 registerPowerDriver(this,patriarchPowerStates,number_of_power_states);
3305 wakeSystem();
3306 powerOverrideOnPriv();
3307 return true;
3308}
3309
3310
3311void IORootParent::shutDownSystem ( void )
3312{
3313 mostRecentChange = OFF_STATE;
3314 changePowerStateToPriv(OFF_STATE);
3315}
3316
3317
3318void IORootParent::restartSystem ( void )
3319{
3320 mostRecentChange = RESTART_STATE;
3321 changePowerStateToPriv(RESTART_STATE);
3322}
3323
3324
3325void IORootParent::sleepSystem ( void )
3326{
3327 mostRecentChange = SLEEP_STATE;
3328 changePowerStateToPriv(SLEEP_STATE);
3329}
3330
3331
3332void IORootParent::dozeSystem ( void )
3333{
3334 mostRecentChange = DOZE_STATE;
3335 changePowerStateToPriv(DOZE_STATE);
3336}
3337
3338// Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
3339// This brings the parent to doze, which allows the root to step up from sleep to doze.
3340
3341// In idle sleep, do nothing because the parent is still on and the root can freely change state.
3342
3343void IORootParent::sleepToDoze ( void )
3344{
3345 if ( mostRecentChange == SLEEP_STATE ) {
3346 changePowerStateToPriv(DOZE_STATE);
3347 }
3348}
3349
3350
3351void IORootParent::wakeSystem ( void )
3352{
3353 mostRecentChange = ON_STATE;
3354 changePowerStateToPriv(ON_STATE);
3355}
3356
3357IOReturn IORootParent::changePowerStateToPriv ( unsigned long ordinal )
3358{
3359 IOReturn ret;
3360
3361 if( (SLEEP_STATE == ordinal) && sleepSupportedPEFunction )
3362 {
3363
3364 // Determine if the machine supports sleep, or must doze.
3365 ret = getPlatform()->callPlatformFunction(
3366 sleepSupportedPEFunction, false,
3367 NULL, NULL, NULL, NULL);
3368
3369 // If the machine only supports doze, the callPlatformFunction call
3370 // boils down toIOPMrootDomain::setSleepSupported(kPCICantSleep),
3371 // otherwise nothing.
3372 }
3373
3374 return super::changePowerStateToPriv(ordinal);
3375}
3376