2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <libkern/c++/OSKext.h>
29 #include <libkern/c++/OSMetaClass.h>
30 #include <IOKit/IOWorkLoop.h>
31 #include <IOKit/IOCommandGate.h>
32 #include <IOKit/IOPlatformExpert.h>
33 #include <IOKit/IOKitDebug.h>
34 #include <IOKit/IOTimeStamp.h>
35 #include <IOKit/pwr_mgt/IOPMlog.h>
36 #include <IOKit/pwr_mgt/RootDomain.h>
37 #include <IOKit/pwr_mgt/IOPMPrivate.h>
38 #include <IOKit/IODeviceTreeSupport.h>
39 #include <IOKit/IOMessage.h>
40 #include <IOKit/IOReturn.h>
41 #include "RootDomainUserClient.h"
42 #include "IOKit/pwr_mgt/IOPowerConnection.h"
43 #include "IOPMPowerStateQueue.h"
44 #include <IOKit/IOCatalogue.h>
45 #include <IOKit/IOCommand.h> // IOServicePMPrivate
47 #include <IOKit/IOHibernatePrivate.h>
49 #include <sys/syslog.h>
50 #include <sys/sysctl.h>
52 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
53 #include "IOServicePMPrivate.h"
56 #include <mach/shared_region.h>
59 #if defined(__i386__) || defined(__x86_64__)
61 #include "IOPMrootDomainInternal.h"
65 #define kIOPMrootDomainClass "IOPMrootDomain"
67 #define LOG_PREFIX "PMRD: "
69 #define LOG(x...) do { \
70 kprintf(LOG_PREFIX x); IOLog(x); } while (false)
72 #define KLOG(x...) do { \
73 kprintf(LOG_PREFIX x); } while (false)
75 #define DLOG(x...) do { \
76 if (kIOLogPMRootDomain & gIOKitDebug) \
77 kprintf(LOG_PREFIX x); } while (false)
79 #define CHECK_THREAD_CONTEXT
80 #ifdef CHECK_THREAD_CONTEXT
81 static IOWorkLoop
* gIOPMWorkLoop
= 0;
82 #define ASSERT_GATED(x) \
84 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
85 panic("RootDomain: not inside PM gate"); \
89 #define ASSERT_GATED(x)
90 #endif /* CHECK_THREAD_CONTEXT */
92 // Event types for IOPMPowerStateQueue::submitPowerEvent()
94 kPowerEventFeatureChanged
= 1,
95 kPowerEventReceivedPowerNotification
,
96 kPowerEventSystemBootCompleted
,
97 kPowerEventSystemShutdown
,
98 kPowerEventUserDisabledSleep
,
99 kPowerEventConfigdRegisteredInterest
,
100 kPowerEventAggressivenessChanged
104 IOReturn
OSKextSystemSleepOrWake( UInt32
);
107 extern const IORegistryPlane
* gIOPowerPlane
;
109 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
110 static void wakeupClamshellTimerExpired( thread_call_param_t us
, thread_call_param_t
);
111 static void notifySystemShutdown( IOService
* root
, unsigned long event
);
112 static bool clientMessageFilter( OSObject
* object
, void * context
);
113 static void handleAggressivesFunction( thread_call_param_t param1
, thread_call_param_t param2
);
115 // "IOPMSetSleepSupported" callPlatformFunction name
116 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
118 #define kIOSleepSupportedKey "IOSleepSupported"
120 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
121 | kIOPMSupportedOnBatt \
122 | kIOPMSupportedOnUPS)
126 // not idle around autowake time, secs
127 kAutoWakePreWindow
= 45,
128 kAutoWakePostWindow
= 15
131 #define kLocalEvalClamshellCommand (1 << 15)
142 #define ON_POWER kIOPMPowerOn
143 #define RESTART_POWER kIOPMRestart
144 #define SLEEP_POWER kIOPMAuxPowerOn
145 #define DOZE_POWER kIOPMDoze
147 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
149 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
150 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
151 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
152 {1, kIOPMDoze
, kIOPMDoze
, DOZE_POWER
, 0,0,0,0,0,0,0,0},
153 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
156 // Clients eligible to receive system power messages.
158 kMessageClientNone
= 0,
160 kMessageClientConfigd
163 // Run states (R-state) defined within the ON power state.
171 // IOService in power plane can be tagged with following flags.
173 kServiceFlagGraphics
= 0x01,
174 kServiceFlagNoPowerUp
= 0x02,
175 kServiceFlagTopLevelPCI
= 0x04
178 // Flags describing R-state features and capabilities.
180 kRStateFlagNone
= 0x00000000,
181 kRStateFlagSuppressGraphics
= 0x00000001,
182 kRStateFlagSuppressMessages
= 0x00000002,
183 kRStateFlagSuppressPCICheck
= 0x00000004,
184 kRStateFlagDisableIdleSleep
= 0x00000008
187 #if ROOT_DOMAIN_RUN_STATES
189 // Table of flags for each R-state.
190 static uint32_t gRStateFlags
[ kRStateCount
] =
195 kRStateFlagSuppressGraphics
,
197 /* Maintenance wake */
198 kRStateFlagSuppressGraphics
|
199 kRStateFlagSuppressMessages
|
200 kRStateFlagSuppressPCICheck
|
201 kRStateFlagDisableIdleSleep
204 static IONotifier
* gConfigdNotifier
= 0;
206 #define kIOPMRootDomainRunStateKey "Run State"
207 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
209 #endif /* ROOT_DOMAIN_RUN_STATES */
211 // Special interest that entitles the interested client from receiving
212 // all system messages. Used by pmconfigd to support maintenance wake.
214 #define kIOPMPrivilegedPowerInterest "IOPMPrivilegedPowerInterest"
216 static IONotifier
* gSysPowerDownNotifier
= 0;
221 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
222 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
224 #define kAggressivesMinValue 1
226 static uint32_t gAggressivesState
= 0;
229 kAggressivesStateBusy
= 0x01,
230 kAggressivesStateQuickSpindown
= 0x02
233 struct AggressivesRecord
{
239 struct AggressivesRequest
{
245 AggressivesRecord record
;
250 kAggressivesRequestTypeService
= 1,
251 kAggressivesRequestTypeRecord
255 kAggressivesOptionSynchronous
= 0x00000001,
256 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
257 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
258 kAggressivesOptionQuickSpindownMask
= 0x00000300
262 kAggressivesRecordFlagModified
= 0x00000001,
263 kAggressivesRecordFlagMinValue
= 0x00000002
267 static IOPMrootDomain
* gRootDomain
;
268 static UInt32 gSleepOrShutdownPending
= 0;
269 static UInt32 gWillShutdown
= 0;
270 static uint32_t gMessageClientType
= kMessageClientNone
;
271 static UInt32 gSleepWakeUUIDIsSet
= false;
273 struct timeval gIOLastSleepTime
;
274 struct timeval gIOLastWakeTime
;
276 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
277 #define kCPUUnknownIndex 9999999
284 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
285 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
286 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
288 class PMSettingObject
: public OSObject
290 OSDeclareFinalStructors(PMSettingObject
)
292 IOPMrootDomain
*parent
;
293 IOPMSettingControllerCallback func
;
296 uint32_t *publishedFeatureID
;
299 static PMSettingObject
*pmSettingObject(
300 IOPMrootDomain
*parent_arg
,
301 IOPMSettingControllerCallback handler_arg
,
302 OSObject
*target_arg
,
303 uintptr_t refcon_arg
,
304 uint32_t supportedPowerSources
,
305 const OSSymbol
*settings
[]);
307 void setPMSetting(const OSSymbol
*type
, OSObject
*obj
);
309 void taggedRelease(const void *tag
, const int when
) const;
316 * Internal helper object for logging trace points to RTC
317 * IOPMrootDomain and only IOPMrootDomain should instantiate
318 * exactly one of these.
321 typedef void (*IOPMTracePointHandler
)(
322 void * target
, uint32_t code
, uint32_t data
);
324 class PMTraceWorker
: public OSObject
326 OSDeclareDefaultStructors(PMTraceWorker
)
328 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
330 static PMTraceWorker
*tracer( IOPMrootDomain
* );
331 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
332 void tracePoint(uint8_t phase
);
333 void traceLoginWindowPhase(uint8_t phase
);
334 int recordTopLevelPCIDevice(IOService
*);
335 void RTC_TRACE(void);
336 virtual bool serialize(OSSerialize
*s
) const;
338 IOPMTracePointHandler tracePointHandler
;
339 void * tracePointTarget
;
341 IOPMrootDomain
*owner
;
342 IOLock
*pciMappingLock
;
343 OSArray
*pciDeviceBitMappings
;
346 uint8_t loginWindowPhase
;
347 uint8_t addedToRegistry
;
349 uint32_t pciBusyBitMask
;
354 * Internal helper object for Shutdown/Restart notifications.
356 #define kPMHaltMaxWorkers 8
357 #define kPMHaltTimeoutMS 100
359 class PMHaltWorker
: public OSObject
361 OSDeclareFinalStructors( PMHaltWorker
)
364 IOService
* service
; // service being worked on
365 AbsoluteTime startTime
; // time when work started
366 int depth
; // work on nubs at this PM-tree depth
367 int visits
; // number of nodes visited (debug)
369 bool timeout
; // service took too long
371 static PMHaltWorker
* worker( void );
372 static void main( void * arg
, wait_result_t waitResult
);
373 static void work( PMHaltWorker
* me
);
374 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
375 virtual void free( void );
378 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
381 #define super IOService
382 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
386 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
388 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
391 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
393 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
396 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
398 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
401 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
403 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
406 IOReturn
rootDomainRestart ( void )
408 return gRootDomain
->restartSystem();
411 IOReturn
rootDomainShutdown ( void )
413 return gRootDomain
->shutdownSystem();
416 void IOSystemShutdownNotification ( void )
418 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
420 OSKext::willShutdown();
421 for (int i
= 0; i
< 100; i
++)
423 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
429 int sync_internal(void);
433 A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain
434 children it has, but within the constraint of the power state provided by its parent. The driver expresses its desire by
435 calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children
436 express their desires by calling requestPowerDomainState().
438 The Root Power Domain owns the policy for idle and demand sleep and doze for the system. It is a power-managed IOService just
439 like the others in the system. It implements several power states which correspond to what we see as Sleep, Doze, etc.
441 The sleep/doze policy is as follows:
442 Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards.
443 Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero.
444 The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep.
446 These three conditions are enforced using the "driver clamp" by calling changePowerStateTo(). For example, if the case is
447 opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or
448 the state of the other clamp.
450 Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item.
451 In this case the root's parent actually initiates the power state change so that the root has no choice and does not give
452 applications the opportunity to veto the change.
454 Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep. When this is true, the root's
455 children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE)
456 to hold itself on until the sleep timer expires. This timer is set for the difference between the sleep timeout slider and
457 the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel. For example, if
458 the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes,
459 when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root
460 sets its timer for 25 minutes (30 - 5). When the timer expires, it releases its clamp and now nothing is holding it awake,
463 Demand sleep is prevented when the system is booting. When preferences are transmitted by the loginwindow at the end of
464 boot, a flag is cleared, and this allows subsequent Demand Sleep.
466 The system will not Sleep, but will Doze if some object calls setSleepSupported(kPCICantSleep) during a power change to the sleep state (this can be done by the PCI Aux Power Supply drivers, Slots99, MacRISC299, etc.). This is not enforced with
467 a clamp, but sets a flag which is noticed before actually sleeping the kernel. If the flag is set, the root steps up
468 one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and
469 ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler
473 //******************************************************************************
475 IOPMrootDomain
* IOPMrootDomain::construct( void )
477 IOPMrootDomain
*root
;
479 root
= new IOPMrootDomain
;
486 //******************************************************************************
488 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
490 IOService
*rootDomain
= (IOService
*) p0
;
491 unsigned long pmRef
= (unsigned long) p1
;
493 DLOG("disk_sync_callout start\n");
496 IOHibernateSystemSleep();
499 rootDomain
->allowPowerChange(pmRef
);
500 DLOG("disk_sync_callout finish\n");
503 //******************************************************************************
505 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
507 AbsoluteTime endTime
;
510 clock_get_uptime(&endTime
);
511 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
513 SUB_ABSOLUTETIME(&endTime
, startTime
);
514 absolutetime_to_nanoseconds(endTime
, &nano
);
517 return (UInt32
)(nano
/ 1000000ULL);
520 //******************************************************************************
523 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
525 struct timeval
*swt
= (struct timeval
*)arg1
;
526 struct proc
*p
= req
->p
;
529 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
530 } else if(proc_is64bit(p
)) {
531 struct user64_timeval t
;
532 t
.tv_sec
= swt
->tv_sec
;
533 t
.tv_usec
= swt
->tv_usec
;
534 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
536 struct user32_timeval t
;
537 t
.tv_sec
= swt
->tv_sec
;
538 t
.tv_usec
= swt
->tv_usec
;
539 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
543 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
544 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
545 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
547 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
548 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
549 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
554 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
556 int new_value
, changed
;
557 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
559 if (!gWillShutdown
&& (new_value
== 1)) {
560 IOSystemShutdownNotification();
567 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
568 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
569 0, 0, sysctl_willshutdown
, "I", "");
574 sysctl_progressmeterenable
575 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
578 int new_value
, changed
;
580 error
= sysctl_io_number(req
, vc_progress_meter_enable
, sizeof(int), &new_value
, &changed
);
583 vc_enable_progressmeter(new_value
);
590 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
593 int new_value
, changed
;
595 error
= sysctl_io_number(req
, vc_progress_meter_value
, sizeof(int), &new_value
, &changed
);
598 vc_set_progressmeter(new_value
);
603 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
604 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
605 0, 0, sysctl_progressmeterenable
, "I", "");
607 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
608 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
609 0, 0, sysctl_progressmeter
, "I", "");
613 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
614 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
616 //******************************************************************************
619 //******************************************************************************
621 #define kRootDomainSettingsCount 16
623 bool IOPMrootDomain::start( IOService
* nub
)
625 OSIterator
*psIterator
;
626 OSDictionary
*tmpDict
;
631 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
632 gIOPMSettingMaintenanceWakeCalendarKey
=
633 OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
635 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
636 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
637 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
639 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
641 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
643 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
644 gIOPMSettingAutoWakeSecondsKey
,
645 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
646 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
),
647 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
648 OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
),
649 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
650 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
651 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
652 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
653 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
654 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
655 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
656 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
657 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
658 OSSymbol::withCString(kIOPMStateConsoleShutdown
)
661 queue_init(&aggressivesQueue
);
662 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
663 aggressivesData
= OSData::withCapacity(
664 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
666 featuresDictLock
= IOLockAlloc();
667 settingsCtrlLock
= IORecursiveLockAlloc();
668 setPMRootDomain(this);
670 extraSleepTimer
= thread_call_allocate(
671 idleSleepTimerExpired
,
672 (thread_call_param_t
) this);
674 clamshellWakeupIgnore
= thread_call_allocate(
675 wakeupClamshellTimerExpired
,
676 (thread_call_param_t
) this);
678 diskSyncCalloutEntry
= thread_call_allocate(
680 (thread_call_param_t
) this);
683 setProperty(kIOSleepSupportedKey
, true);
685 bzero(&pmStats
, sizeof(pmStats
));
687 pmTracer
= PMTraceWorker::tracer(this);
689 updateRunState(kRStateNormal
);
690 userDisabledAllSleep
= false;
692 sleepIsSupported
= true;
693 systemBooting
= true;
695 idleSleepTimerPending
= false;
698 clamshellIsClosed
= false;
699 clamshellExists
= false;
700 ignoringClamshell
= true;
701 ignoringClamshellOnWake
= false;
702 acAdaptorConnected
= true;
704 queuedSleepWakeUUIDString
= NULL
;
705 pmStatsAppResponses
= OSArray::withCapacity(5);
706 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
707 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
708 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
709 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
710 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
712 idxPMCPUClamshell
= kCPUUnknownIndex
;
713 idxPMCPULimitedPower
= kCPUUnknownIndex
;
715 tmpDict
= OSDictionary::withCapacity(1);
716 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
719 settingsCallbacks
= OSDictionary::withCapacity(1);
721 // Create a list of the valid PM settings that we'll relay to
722 // interested clients in setProperties() => setPMSetting()
723 allowedPMSettings
= OSArray::withObjects(
724 (const OSObject
**)settingsArr
,
725 kRootDomainSettingsCount
,
728 fPMSettingsDict
= OSDictionary::withCapacity(5);
730 PMinit(); // creates gIOPMWorkLoop
732 // Create IOPMPowerStateQueue used to queue external power
733 // events, and to handle those events on the PM work loop.
734 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
735 this, OSMemberFunctionCast(IOEventSource::Action
, this,
736 &IOPMrootDomain::dispatchPowerEvent
));
737 getPMworkloop()->addEventSource(pmPowerStateQueue
);
738 #ifdef CHECK_THREAD_CONTEXT
739 gIOPMWorkLoop
= getPMworkloop();
742 // create our power parent
743 patriarch
= new IORootParent
;
745 patriarch
->attach(this);
746 patriarch
->start(this);
747 patriarch
->addPowerChild(this);
749 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
751 // set a clamp until we sleep
752 changePowerStateToPriv(ON_STATE
);
754 // install power change handler
755 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
758 // Register for a notification when IODisplayWrangler is published
759 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
761 _displayWranglerNotifier
= addMatchingNotification(
762 gIOPublishNotification
, tmpDict
,
763 (IOServiceMatchingNotificationHandler
) &displayWranglerPublished
,
769 // Battery location published - ApplePMU support only
770 if ((tmpDict
= serviceMatching("IOPMPowerSource")))
772 _batteryPublishNotifier
= addMatchingNotification(
773 gIOPublishNotification
, tmpDict
,
774 (IOServiceMatchingNotificationHandler
) &batteryPublished
,
779 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
780 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
781 ucClassName
->release();
783 // IOBacklightDisplay can take a long time to load at boot, or it may
784 // not load at all if you're booting with clamshell closed. We publish
785 // 'DisplayDims' here redundantly to get it published early and at all.
786 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
787 if( psIterator
&& psIterator
->getNextObject() )
789 // There's at least one battery on the system, so we publish
790 // 'DisplayDims' support for the LCD.
791 publishFeature("DisplayDims");
794 psIterator
->release();
797 sysctl_register_oid(&sysctl__kern_sleeptime
);
798 sysctl_register_oid(&sysctl__kern_waketime
);
799 sysctl_register_oid(&sysctl__kern_willshutdown
);
801 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
802 sysctl_register_oid(&sysctl__kern_progressmeter
);
803 #endif /* !CONFIG_EMBEDDED */
806 IOHibernateSystemInit(this);
809 registerService(); // let clients find us
815 //******************************************************************************
818 // Receive a setProperty call
819 // The "System Boot" property means the system is completely booted.
820 //******************************************************************************
822 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
824 IOReturn return_value
= kIOReturnSuccess
;
825 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
833 const OSSymbol
*boot_complete_string
=
834 OSSymbol::withCString("System Boot Complete");
835 const OSSymbol
*sys_shutdown_string
=
836 OSSymbol::withCString("System Shutdown");
837 const OSSymbol
*stall_halt_string
=
838 OSSymbol::withCString("StallSystemAtHalt");
839 const OSSymbol
*battery_warning_disabled_string
=
840 OSSymbol::withCString("BatteryWarningsDisabled");
841 const OSSymbol
*idle_seconds_string
=
842 OSSymbol::withCString("System Idle Seconds");
844 const OSSymbol
*hibernatemode_string
=
845 OSSymbol::withCString(kIOHibernateModeKey
);
846 const OSSymbol
*hibernatefile_string
=
847 OSSymbol::withCString(kIOHibernateFileKey
);
848 const OSSymbol
*hibernatefreeratio_string
=
849 OSSymbol::withCString(kIOHibernateFreeRatioKey
);
850 const OSSymbol
*hibernatefreetime_string
=
851 OSSymbol::withCString(kIOHibernateFreeTimeKey
);
853 const OSSymbol
*sleepdisabled_string
=
854 OSSymbol::withCString("SleepDisabled");
855 const OSSymbol
*ondeck_sleepwake_uuid_string
=
856 OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
857 const OSSymbol
*loginwindow_tracepoint_string
=
858 OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
862 return_value
= kIOReturnBadArgument
;
866 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(idle_seconds_string
))))
868 setProperty(idle_seconds_string
, n
);
869 idleSeconds
= n
->unsigned32BitValue();
872 if (boot_complete_string
&& dict
->getObject(boot_complete_string
))
874 pmPowerStateQueue
->submitPowerEvent( kPowerEventSystemBootCompleted
);
877 if( battery_warning_disabled_string
878 && dict
->getObject(battery_warning_disabled_string
))
880 setProperty( battery_warning_disabled_string
,
881 dict
->getObject(battery_warning_disabled_string
));
884 if( sys_shutdown_string
885 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sys_shutdown_string
))))
887 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
890 if( stall_halt_string
891 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(stall_halt_string
))) )
893 setProperty(stall_halt_string
, b
);
897 if ( hibernatemode_string
898 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatemode_string
))))
900 setProperty(hibernatemode_string
, n
);
902 if ( hibernatefreeratio_string
903 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreeratio_string
))))
905 setProperty(hibernatefreeratio_string
, n
);
907 if ( hibernatefreetime_string
908 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreetime_string
))))
910 setProperty(hibernatefreetime_string
, n
);
912 if ( hibernatefile_string
913 && (str
= OSDynamicCast(OSString
, dict
->getObject(hibernatefile_string
))))
915 setProperty(hibernatefile_string
, str
);
919 if( sleepdisabled_string
920 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sleepdisabled_string
))) )
922 setProperty(sleepdisabled_string
, b
);
923 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
926 if (ondeck_sleepwake_uuid_string
927 && (obj
= dict
->getObject(ondeck_sleepwake_uuid_string
)))
929 // Clear the currently published UUID
930 if (kOSBooleanFalse
== obj
)
932 publishSleepWakeUUID(NULL
);
935 // Cache UUID for an upcoming sleep/wake
936 if ((str
= OSDynamicCast(OSString
, obj
)))
938 if (queuedSleepWakeUUIDString
) {
939 queuedSleepWakeUUIDString
->release();
940 queuedSleepWakeUUIDString
= NULL
;
942 queuedSleepWakeUUIDString
= str
;
943 queuedSleepWakeUUIDString
->retain();
944 DLOG("SleepWake UUID queued: %s\n",
945 queuedSleepWakeUUIDString
->getCStringNoCopy());
949 if (loginwindow_tracepoint_string
950 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(loginwindow_tracepoint_string
)))
953 pmTracer
->traceLoginWindowPhase( n
->unsigned8BitValue() );
956 // Relay our allowed PM settings onto our registered PM clients
957 for(i
= 0; i
< allowedPMSettings
->getCount(); i
++) {
959 type
= (OSSymbol
*)allowedPMSettings
->getObject(i
);
962 obj
= dict
->getObject(type
);
965 if ((gIOPMSettingAutoWakeSecondsKey
== type
) && ((n
= OSDynamicCast(OSNumber
, obj
))))
967 UInt32 rsecs
= n
->unsigned32BitValue();
969 autoWakeStart
= autoWakeEnd
= 0;
972 AbsoluteTime deadline
;
973 clock_interval_to_deadline(rsecs
+ kAutoWakePostWindow
, kSecondScale
, &deadline
);
974 autoWakeEnd
= AbsoluteTime_to_scalar(&deadline
);
975 if (rsecs
> kAutoWakePreWindow
)
976 rsecs
-= kAutoWakePreWindow
;
979 clock_interval_to_deadline(rsecs
, kSecondScale
, &deadline
);
980 autoWakeStart
= AbsoluteTime_to_scalar(&deadline
);
984 return_value
= setPMSetting(type
, obj
);
986 if(kIOReturnSuccess
!= return_value
) goto exit
;
990 if(boot_complete_string
) boot_complete_string
->release();
991 if(sys_shutdown_string
) sys_shutdown_string
->release();
992 if(stall_halt_string
) stall_halt_string
->release();
993 if (battery_warning_disabled_string
) battery_warning_disabled_string
->release();
994 if(idle_seconds_string
) idle_seconds_string
->release();
995 if(sleepdisabled_string
) sleepdisabled_string
->release();
996 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
998 if(hibernatemode_string
) hibernatemode_string
->release();
999 if(hibernatefile_string
) hibernatefile_string
->release();
1000 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1001 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1003 return return_value
;
1007 //******************************************************************************
1008 // aggressivenessChanged
1010 // We are behind the command gate to examine changes to aggressives.
1011 //******************************************************************************
1013 void IOPMrootDomain::aggressivenessChanged( void )
1015 unsigned long minutesToSleep
= 0;
1016 unsigned long minutesToDisplayDim
= 0;
1020 // Fetch latest display and system sleep slider values.
1021 getAggressiveness(kPMMinutesToSleep
, &minutesToSleep
);
1022 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
1023 DLOG("aggressiveness changed system %u, display %u\n",
1024 (uint32_t) minutesToSleep
, (uint32_t) minutesToDisplayDim
);
1026 DLOG("idle time -> %ld secs (ena %d)\n",
1027 idleSeconds
, (minutesToSleep
!= 0));
1029 if (0x7fffffff == minutesToSleep
)
1030 minutesToSleep
= idleSeconds
;
1032 // How long to wait before sleeping the system once the displays turns
1033 // off is indicated by 'extraSleepDelay'.
1035 if ( minutesToSleep
> minutesToDisplayDim
) {
1036 extraSleepDelay
= minutesToSleep
- minutesToDisplayDim
;
1039 extraSleepDelay
= 0;
1042 // system sleep timer was disabled, but not anymore.
1043 if ( (sleepSlider
== 0) && (minutesToSleep
!= 0) ) {
1047 changePowerStateToPriv(ON_STATE
);
1050 startIdleSleepTimer( idleSeconds
);
1055 // Start idle sleep timer if wrangler went to sleep
1056 // while system sleep was disabled.
1063 uint32_t minutesSinceDisplaySleep
= 0;
1064 uint32_t sleepDelay
;
1066 clock_get_uptime(&now
);
1067 if (CMP_ABSOLUTETIME(&now
, &wranglerSleepTime
) > 0)
1069 SUB_ABSOLUTETIME(&now
, &wranglerSleepTime
);
1070 absolutetime_to_nanoseconds(now
, &nanos
);
1071 minutesSinceDisplaySleep
= nanos
/ (60000000000ULL);
1074 if (extraSleepDelay
> minutesSinceDisplaySleep
)
1076 sleepDelay
= extraSleepDelay
- minutesSinceDisplaySleep
;
1080 // 1 min idle sleep.
1084 startIdleSleepTimer(sleepDelay
* 60);
1085 DLOG("display slept %u min, set idle timer to %u min\n",
1086 minutesSinceDisplaySleep
, sleepDelay
);
1091 sleepSlider
= minutesToSleep
;
1092 if ( sleepSlider
== 0 ) {
1093 cancelIdleSleepTimer();
1094 // idle sleep is now disabled
1096 // make sure we're powered
1097 patriarch
->wakeSystem();
1102 //******************************************************************************
1103 // setAggressiveness
1105 // Override IOService::setAggressiveness()
1106 //******************************************************************************
1108 IOReturn
IOPMrootDomain::setAggressiveness(
1110 unsigned long value
)
1112 return setAggressiveness( type
, value
, 0 );
1116 * Private setAggressiveness() with an internal options argument.
1118 IOReturn
IOPMrootDomain::setAggressiveness(
1120 unsigned long value
,
1121 IOOptionBits options
)
1123 AggressivesRequest
* entry
;
1124 AggressivesRequest
* request
;
1127 DLOG("setAggressiveness 0x%x = %u, options 0x%x\n",
1128 (uint32_t) type
, (uint32_t) value
, (uint32_t) options
);
1130 request
= IONew(AggressivesRequest
, 1);
1132 return kIOReturnNoMemory
;
1134 memset(request
, 0, sizeof(*request
));
1135 request
->options
= options
;
1136 request
->dataType
= kAggressivesRequestTypeRecord
;
1137 request
->data
.record
.type
= (uint32_t) type
;
1138 request
->data
.record
.value
= (uint32_t) value
;
1142 // Update disk quick spindown flag used by getAggressiveness().
1143 // Never merge requests with quick spindown flags set.
1145 if (options
& kAggressivesOptionQuickSpindownEnable
)
1146 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1147 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1148 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1151 // Coalesce requests with identical aggressives types.
1152 // Deal with callers that calls us too "aggressively".
1154 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1156 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1157 (entry
->data
.record
.type
== type
) &&
1158 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1160 entry
->data
.record
.value
= value
;
1169 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1172 AGGRESSIVES_UNLOCK();
1175 IODelete(request
, AggressivesRequest
, 1);
1177 if (options
& kAggressivesOptionSynchronous
)
1178 handleAggressivesRequests(); // not truly synchronous
1180 thread_call_enter(aggressivesThreadCall
);
1182 return kIOReturnSuccess
;
1186 //******************************************************************************
1187 // getAggressiveness
1189 // Override IOService::setAggressiveness()
1190 // Fetch the aggressiveness factor with the given type.
1191 //******************************************************************************
1193 IOReturn
IOPMrootDomain::getAggressiveness (
1195 unsigned long * outLevel
)
1201 return kIOReturnBadArgument
;
1205 // Disk quick spindown in effect, report value = 1
1207 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1208 (type
== kPMMinutesToSpinDown
))
1210 value
= kAggressivesMinValue
;
1214 // Consult the pending request queue.
1218 AggressivesRequest
* entry
;
1220 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1222 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1223 (entry
->data
.record
.type
== type
) &&
1224 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1226 value
= entry
->data
.record
.value
;
1233 // Consult the backend records.
1235 if (!source
&& aggressivesData
)
1237 AggressivesRecord
* record
;
1240 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1241 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1243 for (i
= 0; i
< count
; i
++, record
++)
1245 if (record
->type
== type
)
1247 value
= record
->value
;
1254 AGGRESSIVES_UNLOCK();
1258 DLOG("getAggressiveness 0x%x = %u, source %d\n",
1259 (uint32_t) type
, value
, source
);
1260 *outLevel
= (unsigned long) value
;
1261 return kIOReturnSuccess
;
1265 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1266 *outLevel
= 0; // default return = 0, driver may not check for error
1267 return kIOReturnInvalid
;
1272 //******************************************************************************
1273 // joinAggressiveness
1275 // Request from IOService to join future aggressiveness broadcasts.
1276 //******************************************************************************
1278 IOReturn
IOPMrootDomain::joinAggressiveness(
1279 IOService
* service
)
1281 AggressivesRequest
* request
;
1283 if (!service
|| (service
== this))
1284 return kIOReturnBadArgument
;
1286 DLOG("joinAggressiveness %s (%p)\n", service
->getName(), service
);
1288 request
= IONew(AggressivesRequest
, 1);
1290 return kIOReturnNoMemory
;
1292 service
->retain(); // released by synchronizeAggressives()
1294 memset(request
, 0, sizeof(*request
));
1295 request
->dataType
= kAggressivesRequestTypeService
;
1296 request
->data
.service
= service
;
1299 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1300 AGGRESSIVES_UNLOCK();
1302 thread_call_enter(aggressivesThreadCall
);
1304 return kIOReturnSuccess
;
1308 //******************************************************************************
1309 // handleAggressivesRequests
1311 // Backend thread processes all incoming aggressiveness requests in the queue.
1312 //******************************************************************************
1315 handleAggressivesFunction(
1316 thread_call_param_t param1
,
1317 thread_call_param_t param2
)
1321 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1325 void IOPMrootDomain::handleAggressivesRequests( void )
1327 AggressivesRecord
* start
;
1328 AggressivesRecord
* record
;
1329 AggressivesRequest
* request
;
1330 queue_head_t joinedQueue
;
1334 bool pingSelf
= false;
1338 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1339 queue_empty(&aggressivesQueue
))
1342 gAggressivesState
|= kAggressivesStateBusy
;
1343 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1344 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1349 queue_init(&joinedQueue
);
1353 // Remove request from the incoming queue in FIFO order.
1354 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1355 switch (request
->dataType
)
1357 case kAggressivesRequestTypeRecord
:
1358 // Update existing record if found.
1360 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1362 if (record
->type
== request
->data
.record
.type
)
1366 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1368 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1371 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1372 kAggressivesRecordFlagModified
);
1373 DLOG("quick spindown accelerated, was %u min\n",
1377 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1379 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1382 record
->flags
|= kAggressivesRecordFlagModified
;
1383 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1384 DLOG("disk spindown restored to %u min\n",
1388 else if (record
->value
!= request
->data
.record
.value
)
1390 record
->value
= request
->data
.record
.value
;
1391 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1394 record
->flags
|= kAggressivesRecordFlagModified
;
1401 // No matching record, append a new record.
1403 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1405 AggressivesRecord newRecord
;
1407 newRecord
.flags
= kAggressivesRecordFlagModified
;
1408 newRecord
.type
= request
->data
.record
.type
;
1409 newRecord
.value
= request
->data
.record
.value
;
1410 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1412 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1413 DLOG("disk spindown accelerated\n");
1416 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1418 // OSData may have switched to another (larger) buffer.
1419 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1420 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1424 // Finished processing the request, release it.
1425 IODelete(request
, AggressivesRequest
, 1);
1428 case kAggressivesRequestTypeService
:
1429 // synchronizeAggressives() will free request.
1430 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1434 panic("bad aggressives request type %x\n", request
->dataType
);
1437 } while (!queue_empty(&aggressivesQueue
));
1439 // Release the lock to perform work, with busy flag set.
1440 if (!queue_empty(&joinedQueue
) || broadcast
)
1442 AGGRESSIVES_UNLOCK();
1443 if (!queue_empty(&joinedQueue
))
1444 synchronizeAggressives(&joinedQueue
, start
, count
);
1446 broadcastAggressives(start
, count
);
1450 // Remove the modified flag from all records.
1451 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1453 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1454 ((record
->type
== kPMMinutesToDim
) ||
1455 (record
->type
== kPMMinutesToSleep
)))
1458 record
->flags
&= ~kAggressivesRecordFlagModified
;
1461 // Check the incoming queue again since new entries may have been
1462 // added while lock was released above.
1464 } while (!queue_empty(&aggressivesQueue
));
1466 gAggressivesState
&= ~kAggressivesStateBusy
;
1469 AGGRESSIVES_UNLOCK();
1471 // Root domain is interested in system and display sleep slider changes.
1472 // Submit a power event to handle those changes on the PM work loop.
1474 if (pingSelf
&& pmPowerStateQueue
) {
1475 pmPowerStateQueue
->submitPowerEvent( kPowerEventAggressivenessChanged
);
1480 //******************************************************************************
1481 // synchronizeAggressives
1483 // Push all known aggressiveness records to one or more IOService.
1484 //******************************************************************************
1486 void IOPMrootDomain::synchronizeAggressives(
1487 queue_head_t
* joinedQueue
,
1488 const AggressivesRecord
* array
,
1491 IOService
* service
;
1492 AggressivesRequest
* request
;
1493 const AggressivesRecord
* record
;
1497 while (!queue_empty(joinedQueue
))
1499 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1500 if (request
->dataType
== kAggressivesRequestTypeService
)
1501 service
= request
->data
.service
;
1505 IODelete(request
, AggressivesRequest
, 1);
1510 if (service
->assertPMThreadCall())
1512 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1514 value
= record
->value
;
1515 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1516 value
= kAggressivesMinValue
;
1518 DLOG("synchronizeAggressives 0x%x = %u to %s\n",
1519 record
->type
, value
, service
->getName());
1520 service
->setAggressiveness(record
->type
, value
);
1522 service
->deassertPMThreadCall();
1524 service
->release(); // retained by joinAggressiveness()
1530 //******************************************************************************
1531 // broadcastAggressives
1533 // Traverse PM tree and call setAggressiveness() for records that have changed.
1534 //******************************************************************************
1536 void IOPMrootDomain::broadcastAggressives(
1537 const AggressivesRecord
* array
,
1540 IORegistryIterator
* iter
;
1541 IORegistryEntry
* entry
;
1542 IOPowerConnection
* connect
;
1543 IOService
* service
;
1544 const AggressivesRecord
* record
;
1548 iter
= IORegistryIterator::iterateOver(
1549 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1555 while ((entry
= iter
->getNextObject()))
1557 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1558 if (!connect
|| !connect
->getReadyFlag())
1561 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1563 if (service
->assertPMThreadCall())
1565 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1567 if (record
->flags
& kAggressivesRecordFlagModified
)
1569 value
= record
->value
;
1570 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1571 value
= kAggressivesMinValue
;
1572 DLOG("broadcastAggressives %x = %u to %s\n",
1573 record
->type
, value
, service
->getName());
1574 service
->setAggressiveness(record
->type
, value
);
1577 service
->deassertPMThreadCall();
1583 while (!entry
&& !iter
->isValid());
1589 //******************************************************************************
1590 // startIdleSleepTimer
1592 //******************************************************************************
1594 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1596 AbsoluteTime deadline
;
1601 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1602 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1603 idleSleepTimerPending
= true;
1604 DLOG("idle timer set for %u seconds\n", inSeconds
);
1609 //******************************************************************************
1610 // cancelIdleSleepTimer
1612 //******************************************************************************
1614 void IOPMrootDomain::cancelIdleSleepTimer( void )
1617 if (idleSleepTimerPending
)
1619 DLOG("idle timer cancelled\n");
1620 thread_call_cancel(extraSleepTimer
);
1621 idleSleepTimerPending
= false;
1626 //******************************************************************************
1627 // idleSleepTimerExpired
1629 //******************************************************************************
1631 static void idleSleepTimerExpired(
1632 thread_call_param_t us
, thread_call_param_t
)
1634 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
1637 static void wakeupClamshellTimerExpired(
1638 thread_call_param_t us
, thread_call_param_t
)
1640 ((IOPMrootDomain
*)us
)->stopIgnoringClamshellEventsDuringWakeup();
1644 //******************************************************************************
1645 // handleSleepTimerExpiration
1647 // The time between the sleep idle timeout and the next longest one has elapsed.
1648 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1649 //******************************************************************************
1651 void IOPMrootDomain::handleSleepTimerExpiration( void )
1653 if (!getPMworkloop()->inGate())
1655 getPMworkloop()->runAction(
1656 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1657 &IOPMrootDomain::handleSleepTimerExpiration
),
1664 DLOG("sleep timer expired\n");
1667 idleSleepTimerPending
= false;
1669 clock_get_uptime(&time
);
1670 if ((AbsoluteTime_to_scalar(&time
) > autoWakeStart
) &&
1671 (AbsoluteTime_to_scalar(&time
) < autoWakeEnd
))
1673 thread_call_enter_delayed(extraSleepTimer
, *((AbsoluteTime
*) &autoWakeEnd
));
1677 // accelerate disk spin down if spin down timer is non-zero
1678 setQuickSpinDownTimeout();
1685 //******************************************************************************
1686 // stopIgnoringClamshellEventsDuringWakeup
1688 //******************************************************************************
1690 void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup( void )
1692 if (!getPMworkloop()->inGate())
1694 getPMworkloop()->runAction(
1695 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1696 &IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup
),
1703 // Allow clamshell-induced sleep now
1704 ignoringClamshellOnWake
= false;
1706 // Re-send clamshell event, in case it causes a sleep
1707 if (clamshellIsClosed
)
1708 handlePowerNotification( kLocalEvalClamshellCommand
);
1712 //******************************************************************************
1715 //******************************************************************************
1718 IOReturn
IOPMrootDomain::sleepSystem( void )
1720 return sleepSystemOptions(NULL
);
1724 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
1726 /* sleepSystem is a public function, and may be called by any kernel driver.
1727 * And that's bad - drivers should sleep the system by calling
1728 * receivePowerNotification() instead. Drivers should not use sleepSystem.
1730 * Note that user space app calls to IOPMSleepSystem() will also travel
1731 * this code path and thus be correctly identified as software sleeps.
1734 if (options
&& options
->getObject("OSSwitch"))
1737 // Log specific sleep cause for OS Switch hibernation
1738 return privateSleepSystem( kIOPMOSSwitchHibernationKey
) ;
1742 return privateSleepSystem( kIOPMSoftwareSleepKey
);
1748 IOReturn
IOPMrootDomain::privateSleepSystem( const char *sleepReason
)
1750 if ( userDisabledAllSleep
)
1752 LOG("Sleep prevented by user disable\n");
1754 /* Prevent sleep of all kinds if directed to by user space */
1755 return kIOReturnNotPermitted
;
1758 if ( systemBooting
|| systemShutdown
|| !allowSleep
)
1760 LOG("Sleep prevented by SB %d, SS %d, AS %d\n",
1761 systemBooting
, systemShutdown
, allowSleep
);
1763 // Unable to sleep because system is in the process of booting or
1764 // shutting down, or sleep has otherwise been disallowed.
1765 return kIOReturnError
;
1768 // Record sleep cause in IORegistry
1770 setProperty(kRootDomainSleepReasonKey
, sleepReason
);
1773 patriarch
->sleepSystem();
1774 return kIOReturnSuccess
;
1778 //******************************************************************************
1781 //******************************************************************************
1783 IOReturn
IOPMrootDomain::shutdownSystem( void )
1785 //patriarch->shutDownSystem();
1786 return kIOReturnUnsupported
;
1790 //******************************************************************************
1793 //******************************************************************************
1795 IOReturn
IOPMrootDomain::restartSystem( void )
1797 //patriarch->restartSystem();
1798 return kIOReturnUnsupported
;
1802 //******************************************************************************
1805 // This overrides powerChangeDone in IOService.
1807 // Menu sleep and idle sleep move us from the ON state to the SLEEP_STATE.
1809 // If we finished going to the SLEEP_STATE, and the platform is capable of
1810 // true sleep, then sleep the kernel. Otherwise switch up to the DOZE_STATE
1811 // which will keep almost everything as off as it can get.
1812 //******************************************************************************
1814 void IOPMrootDomain::powerChangeDone( unsigned long previousState
)
1817 DLOG("PowerChangeDone: %u->%u\n",
1818 (uint32_t) previousState
, (uint32_t) getPowerState());
1820 switch ( getPowerState() ) {
1822 if ( previousState
!= ON_STATE
)
1827 // re-enable this timer for next sleep
1828 cancelIdleSleepTimer();
1829 wranglerTickled
= true;
1832 clock_usec_t microsecs
;
1833 clock_get_calendar_microtime(&secs
, µsecs
);
1835 gIOLastSleepTime
.tv_sec
= secs
;
1836 gIOLastSleepTime
.tv_usec
= microsecs
;
1837 gIOLastWakeTime
.tv_sec
= 0;
1838 gIOLastWakeTime
.tv_usec
= 0;
1841 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
1843 tracePoint(kIOPMTracePointSystemHibernatePhase
);
1845 IOHibernateSystemHasSlept();
1847 LOG("System Sleep\n");
1850 tracePoint(kIOPMTracePointSystemSleepPlatformPhase
);
1852 getPlatform()->sleepKernel();
1854 // The CPU(s) are off at this point. When they're awakened by CPU interrupt,
1855 // code will resume execution here.
1857 // Now we're waking...
1858 tracePoint(kIOPMTracePointSystemWakeDriversPhase
);
1861 IOHibernateSystemWake();
1864 // sleep transition complete
1865 gSleepOrShutdownPending
= 0;
1867 // trip the reset of the calendar clock
1868 clock_wakeup_calendar();
1870 // get us some power
1871 patriarch
->wakeSystem();
1873 // Set indicator if UUID was set - allow it to be cleared.
1874 if (getProperty(kIOPMSleepWakeUUIDKey
))
1875 gSleepWakeUUIDIsSet
= true;
1877 #if !ROOT_DOMAIN_RUN_STATES
1878 tellClients(kIOMessageSystemWillPowerOn
, clientMessageFilter
);
1882 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
1886 getPlatform()->PMLog(kIOPMrootDomainClass
, kPMLogSystemWake
, 0, 0);
1889 // tell the tree we're waking
1894 #if defined(__i386__) || defined(__x86_64__)
1895 #if ROOT_DOMAIN_RUN_STATES
1896 OSString
* wakeType
= OSDynamicCast(
1897 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
1898 if (wakeType
&& wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
1900 updateRunState(kRStateMaintenance
);
1901 wranglerTickled
= false;
1904 #endif /* ROOT_DOMAIN_RUN_STATES */
1906 updateRunState(kRStateNormal
);
1909 #else /* !__i386__ && !__x86_64__ */
1910 // stay awake for at least 30 seconds
1911 startIdleSleepTimer(30);
1915 changePowerStateToPriv(ON_STATE
);
1917 updateRunState(kRStateNormal
);
1919 // allow us to step up a power state
1920 patriarch
->sleepToDoze();
1922 // ignore children's request for higher power during doze.
1923 changePowerStateWithOverrideTo(DOZE_STATE
);
1928 if ( previousState
!= DOZE_STATE
)
1930 LOG("System Doze\n");
1932 // re-enable this timer for next sleep
1933 cancelIdleSleepTimer();
1934 gSleepOrShutdownPending
= 0;
1936 // Invalidate prior activity tickles to allow wake from doze.
1937 if (wrangler
) wrangler
->changePowerStateTo(0);
1940 #if ROOT_DOMAIN_RUN_STATES
1942 // SLEEP -> ON (Maintenance)
1943 // Go back to sleep, unless cancelled by a HID event.
1945 if ((previousState
== SLEEP_STATE
) &&
1946 (runStateIndex
== kRStateMaintenance
) &&
1949 setProperty(kRootDomainSleepReasonKey
, kIOPMMaintenanceSleepKey
);
1950 changePowerStateWithOverrideTo(SLEEP_STATE
);
1953 // ON -> ON triggered by R-state changes.
1955 if ((previousState
== ON_STATE
) &&
1956 (runStateIndex
!= nextRunStateIndex
) &&
1957 (nextRunStateIndex
< kRStateCount
))
1959 LOG("R-state changed %u->%u\n",
1960 runStateIndex
, nextRunStateIndex
);
1961 updateRunState(nextRunStateIndex
);
1963 DLOG("kIOMessageSystemHasPoweredOn (%u)\n",
1964 gMessageClientType
);
1965 tellClients(kIOMessageSystemHasPoweredOn
, clientMessageFilter
);
1969 #endif /* ROOT_DOMAIN_RUN_STATES */
1974 //******************************************************************************
1977 // The Display Wrangler calls here when it switches to its highest state.
1978 // If the system is currently dozing, allow it to wake by making sure the
1979 // parent is providing power.
1980 //******************************************************************************
1982 void IOPMrootDomain::wakeFromDoze( void )
1984 if ( getPowerState() == DOZE_STATE
)
1986 tracePoint(kIOPMTracePointSystemWakeDriversPhase
);
1987 changePowerStateToPriv(ON_STATE
);
1988 patriarch
->wakeSystem();
1993 //******************************************************************************
1996 // Adds a new feature to the supported features dictionary
1997 //******************************************************************************
1999 void IOPMrootDomain::publishFeature( const char * feature
)
2001 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
2005 //******************************************************************************
2006 // publishFeature (with supported power source specified)
2008 // Adds a new feature to the supported features dictionary
2009 //******************************************************************************
2011 void IOPMrootDomain::publishFeature(
2012 const char *feature
,
2013 uint32_t supportedWhere
,
2014 uint32_t *uniqueFeatureID
)
2016 static uint16_t next_feature_id
= 500;
2018 OSNumber
*new_feature_data
= NULL
;
2019 OSNumber
*existing_feature
= NULL
;
2020 OSArray
*existing_feature_arr
= NULL
;
2021 OSObject
*osObj
= NULL
;
2022 uint32_t feature_value
= 0;
2024 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
2026 if(!supportedWhere
) {
2027 // Feature isn't supported anywhere!
2031 if(next_feature_id
> 5000) {
2032 // Far, far too many features!
2036 if(featuresDictLock
) IOLockLock(featuresDictLock
);
2038 OSDictionary
*features
=
2039 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
2041 // Create new features dict if necessary
2042 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
2043 features
= OSDictionary::withDictionary(features
);
2045 features
= OSDictionary::withCapacity(1);
2048 // Create OSNumber to track new feature
2050 next_feature_id
+= 1;
2051 if( uniqueFeatureID
) {
2052 // We don't really mind if the calling kext didn't give us a place
2053 // to stash their unique id. Many kexts don't plan to unload, and thus
2054 // have no need to remove themselves later.
2055 *uniqueFeatureID
= next_feature_id
;
2058 feature_value
= (uint32_t)next_feature_id
;
2059 feature_value
<<= 16;
2060 feature_value
+= supportedWhere
;
2062 new_feature_data
= OSNumber::withNumber(
2063 (unsigned long long)feature_value
, 32);
2065 // Does features object already exist?
2066 if( (osObj
= features
->getObject(feature
)) )
2068 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
2070 // We need to create an OSArray to hold the now 2 elements.
2071 existing_feature_arr
= OSArray::withObjects(
2072 (const OSObject
**)&existing_feature
, 1, 2);
2073 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
2075 // Add object to existing array
2076 existing_feature_arr
= OSArray::withArray(
2077 existing_feature_arr
,
2078 existing_feature_arr
->getCount() + 1);
2081 if (existing_feature_arr
)
2083 existing_feature_arr
->setObject(new_feature_data
);
2084 features
->setObject(feature
, existing_feature_arr
);
2085 existing_feature_arr
->release();
2086 existing_feature_arr
= 0;
2089 // The easy case: no previously existing features listed. We simply
2090 // set the OSNumber at key 'feature' and we're on our way.
2091 features
->setObject(feature
, new_feature_data
);
2094 new_feature_data
->release();
2096 setProperty(kRootDomainSupportedFeatures
, features
);
2098 features
->release();
2100 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
2102 // Notify EnergySaver and all those in user space so they might
2103 // re-populate their feature specific UI
2104 if(pmPowerStateQueue
) {
2105 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
2110 //******************************************************************************
2111 // removePublishedFeature
2113 // Removes previously published feature
2114 //******************************************************************************
2116 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
2118 IOReturn ret
= kIOReturnError
;
2119 uint32_t feature_value
= 0;
2120 uint16_t feature_id
= 0;
2121 bool madeAChange
= false;
2123 OSSymbol
*dictKey
= NULL
;
2124 OSCollectionIterator
*dictIterator
= NULL
;
2125 OSArray
*arrayMember
= NULL
;
2126 OSNumber
*numberMember
= NULL
;
2127 OSObject
*osObj
= NULL
;
2128 OSNumber
*osNum
= NULL
;
2129 OSArray
*arrayMemberCopy
;
2131 if(featuresDictLock
) IOLockLock(featuresDictLock
);
2133 OSDictionary
*features
=
2134 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
2136 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
2138 // Any modifications to the dictionary are made to the copy to prevent
2139 // races & crashes with userland clients. Dictionary updated
2140 // automically later.
2141 features
= OSDictionary::withDictionary(features
);
2144 ret
= kIOReturnNotFound
;
2148 // We iterate 'features' dictionary looking for an entry tagged
2149 // with 'removeFeatureID'. If found, we remove it from our tracking
2150 // structures and notify the OS via a general interest message.
2152 dictIterator
= OSCollectionIterator::withCollection(features
);
2157 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
2159 osObj
= features
->getObject(dictKey
);
2161 // Each Feature is either tracked by an OSNumber
2162 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
2164 feature_value
= numberMember
->unsigned32BitValue();
2165 feature_id
= (uint16_t)(feature_value
>> 16);
2167 if( feature_id
== (uint16_t)removeFeatureID
)
2170 features
->removeObject(dictKey
);
2175 // Or tracked by an OSArray of OSNumbers
2176 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
2178 unsigned int arrayCount
= arrayMember
->getCount();
2180 for(unsigned int i
=0; i
<arrayCount
; i
++)
2182 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
2187 feature_value
= osNum
->unsigned32BitValue();
2188 feature_id
= (uint16_t)(feature_value
>> 16);
2190 if( feature_id
== (uint16_t)removeFeatureID
)
2193 if( 1 == arrayCount
) {
2194 // If the array only contains one element, remove
2196 features
->removeObject(dictKey
);
2198 // Otherwise remove the element from a copy of the array.
2199 arrayMemberCopy
= OSArray::withArray(arrayMember
);
2200 if (arrayMemberCopy
)
2202 arrayMemberCopy
->removeObject(i
);
2203 features
->setObject(dictKey
, arrayMemberCopy
);
2204 arrayMemberCopy
->release();
2215 dictIterator
->release();
2219 ret
= kIOReturnSuccess
;
2221 setProperty(kRootDomainSupportedFeatures
, features
);
2223 // Notify EnergySaver and all those in user space so they might
2224 // re-populate their feature specific UI
2225 if(pmPowerStateQueue
) {
2226 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
2229 ret
= kIOReturnNotFound
;
2233 if(features
) features
->release();
2234 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
2239 //******************************************************************************
2240 // announcePowerSourceChange
2242 // Notifies "interested parties" that the battery state has changed
2243 //******************************************************************************
2245 void IOPMrootDomain::announcePowerSourceChange( void )
2248 IORegistryEntry
*_batteryRegEntry
= (IORegistryEntry
*) getProperty("BatteryEntry");
2250 // (if possible) re-publish power source state under IOPMrootDomain;
2251 // only do so if the battery controller publishes an IOResource
2252 // defining battery location. Called from ApplePMU battery driver.
2254 if(_batteryRegEntry
)
2257 batt_info
= (OSArray
*) _batteryRegEntry
->getProperty(kIOBatteryInfoKey
);
2259 setProperty(kIOBatteryInfoKey
, batt_info
);
2265 //******************************************************************************
2266 // setPMSetting (private)
2268 // Internal helper to relay PM settings changes from user space to individual
2269 // drivers. Should be called only by IOPMrootDomain::setProperties.
2270 //******************************************************************************
2272 IOReturn
IOPMrootDomain::setPMSetting(
2273 const OSSymbol
*type
,
2276 OSArray
*arr
= NULL
;
2277 PMSettingObject
*p_obj
= NULL
;
2281 if(NULL
== type
) return kIOReturnBadArgument
;
2283 IORecursiveLockLock(settingsCtrlLock
);
2285 fPMSettingsDict
->setObject(type
, obj
);
2287 arr
= (OSArray
*)settingsCallbacks
->getObject(type
);
2288 if(NULL
== arr
) goto exit
;
2289 count
= arr
->getCount();
2290 for(i
=0; i
<count
; i
++) {
2291 p_obj
= (PMSettingObject
*)OSDynamicCast(PMSettingObject
, arr
->getObject(i
));
2292 if(p_obj
) p_obj
->setPMSetting(type
, obj
);
2296 IORecursiveLockUnlock(settingsCtrlLock
);
2297 return kIOReturnSuccess
;
2301 //******************************************************************************
2302 // copyPMSetting (public)
2304 // Allows kexts to safely read setting values, without being subscribed to
2306 //******************************************************************************
2308 OSObject
* IOPMrootDomain::copyPMSetting(
2309 OSSymbol
*whichSetting
)
2311 OSObject
*obj
= NULL
;
2313 if(!whichSetting
) return NULL
;
2315 IORecursiveLockLock(settingsCtrlLock
);
2316 obj
= fPMSettingsDict
->getObject(whichSetting
);
2320 IORecursiveLockUnlock(settingsCtrlLock
);
2326 //******************************************************************************
2327 // registerPMSettingController (public)
2329 // direct wrapper to registerPMSettingController with uint32_t power source arg
2330 //******************************************************************************
2332 IOReturn
IOPMrootDomain::registerPMSettingController(
2333 const OSSymbol
* settings
[],
2334 IOPMSettingControllerCallback func
,
2339 return registerPMSettingController(
2341 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
2342 func
, target
, refcon
, handle
);
2346 //******************************************************************************
2347 // registerPMSettingController (public)
2349 // Kexts may register for notifications when a particular setting is changed.
2350 // A list of settings is available in IOPM.h.
2352 // * settings - An OSArray containing OSSymbols. Caller should populate this
2353 // array with a list of settings caller wants notifications from.
2354 // * func - A C function callback of the type IOPMSettingControllerCallback
2355 // * target - caller may provide an OSObject *, which PM will pass as an
2356 // target to calls to "func"
2357 // * refcon - caller may provide an void *, which PM will pass as an
2358 // argument to calls to "func"
2359 // * handle - This is a return argument. We will populate this pointer upon
2360 // call success. Hold onto this and pass this argument to
2361 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
2363 // kIOReturnSuccess on success
2364 //******************************************************************************
2366 IOReturn
IOPMrootDomain::registerPMSettingController(
2367 const OSSymbol
* settings
[],
2368 uint32_t supportedPowerSources
,
2369 IOPMSettingControllerCallback func
,
2374 PMSettingObject
*pmso
= NULL
;
2375 OSArray
*list
= NULL
;
2376 IOReturn ret
= kIOReturnSuccess
;
2379 if( NULL
== settings
||
2383 return kIOReturnBadArgument
;
2386 pmso
= PMSettingObject::pmSettingObject(
2387 (IOPMrootDomain
*)this, func
, target
,
2388 refcon
, supportedPowerSources
, settings
);
2391 ret
= kIOReturnInternalError
;
2392 goto bail_no_unlock
;
2395 IORecursiveLockLock(settingsCtrlLock
);
2396 for(i
=0; settings
[i
]; i
++)
2398 list
= (OSArray
*)settingsCallbacks
->getObject(settings
[i
]);
2400 // New array of callbacks for this setting
2401 list
= OSArray::withCapacity(1);
2402 settingsCallbacks
->setObject(settings
[i
], list
);
2406 // Add caller to the callback list
2407 list
->setObject(pmso
);
2410 IORecursiveLockUnlock(settingsCtrlLock
);
2412 ret
= kIOReturnSuccess
;
2414 // Track this instance by its OSData ptr from now on
2418 if(kIOReturnSuccess
!= ret
)
2420 // Error return case
2421 if(pmso
) pmso
->release();
2422 if(handle
) *handle
= NULL
;
2428 //******************************************************************************
2429 // sleepOnClamshellClosed
2431 // contains the logic to determine if the system should sleep when the clamshell
2433 //******************************************************************************
2435 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2437 DLOG("clamshell state %d, EX %d, IG %d, IW %d, DT %d, AC %d\n",
2438 clamshellIsClosed
, clamshellExists
, ignoringClamshell
,
2439 ignoringClamshellOnWake
, desktopMode
, acAdaptorConnected
);
2441 return ( !ignoringClamshell
2442 && !ignoringClamshellOnWake
2443 && !(desktopMode
&& acAdaptorConnected
) );
2446 void IOPMrootDomain::sendClientClamshellNotification( void )
2448 /* Only broadcast clamshell alert if clamshell exists. */
2449 if (!clamshellExists
)
2452 setProperty(kAppleClamshellStateKey
,
2453 clamshellIsClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
2455 setProperty(kAppleClamshellCausesSleepKey
,
2456 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
2458 /* Argument to message is a bitfiel of
2459 * ( kClamshellStateBit | kClamshellSleepBit )
2461 messageClients(kIOPMMessageClamshellStateChange
,
2462 (void *) ( (clamshellIsClosed
? kClamshellStateBit
: 0)
2463 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
2467 //******************************************************************************
2468 // informCPUStateChange
2470 // Call into PM CPU code so that CPU power savings may dynamically adjust for
2471 // running on battery, with the lid closed, etc.
2473 // informCPUStateChange is a no-op on non x86 systems
2474 // only x86 has explicit support in the IntelCPUPowerManagement kext
2475 //******************************************************************************
2477 void IOPMrootDomain::informCPUStateChange(
2481 #if defined(__i386__) || defined(__x86_64__)
2483 pmioctlVariableInfo_t varInfoStruct
;
2485 const char *varNameStr
= NULL
;
2486 int32_t *varIndex
= NULL
;
2488 if (kInformAC
== type
) {
2489 varNameStr
= kIOPMRootDomainBatPowerCString
;
2490 varIndex
= &idxPMCPULimitedPower
;
2491 } else if (kInformLid
== type
) {
2492 varNameStr
= kIOPMRootDomainLidCloseCString
;
2493 varIndex
= &idxPMCPUClamshell
;
2498 // Set the new value!
2499 // pmCPUControl will assign us a new ID if one doesn't exist yet
2500 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
2501 varInfoStruct
.varID
= *varIndex
;
2502 varInfoStruct
.varType
= vBool
;
2503 varInfoStruct
.varInitValue
= value
;
2504 varInfoStruct
.varCurValue
= value
;
2505 strncpy( (char *)varInfoStruct
.varName
,
2506 (const char *)varNameStr
,
2507 strlen(varNameStr
) + 1 );
2510 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
2512 // pmCPU only assigns numerical id's when a new varName is specified
2514 && (*varIndex
== kCPUUnknownIndex
))
2516 // pmCPUControl has assigned us a new variable ID.
2517 // Let's re-read the structure we just SET to learn that ID.
2518 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
2522 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
2523 *varIndex
= varInfoStruct
.varID
;
2529 #endif /* __i386__ || __x86_64__ */
2533 //******************************************************************************
2534 // dispatchPowerEvent
2536 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
2537 //******************************************************************************
2539 void IOPMrootDomain::dispatchPowerEvent(
2540 uint32_t event
, void * arg0
, void * arg1
)
2542 DLOG("power event %x args %p %p\n", event
, arg0
, arg1
);
2547 case kPowerEventFeatureChanged
:
2548 messageClients(kIOPMMessageFeatureChange
, this);
2551 case kPowerEventReceivedPowerNotification
:
2552 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
2555 case kPowerEventSystemBootCompleted
:
2558 systemBooting
= false;
2561 // If lid is closed, re-send lid closed notification
2562 // now that booting is complete.
2563 if( clamshellIsClosed
)
2565 handlePowerNotification(kLocalEvalClamshellCommand
);
2570 case kPowerEventSystemShutdown
:
2571 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
2573 /* We set systemShutdown = true during shutdown
2574 to prevent sleep at unexpected times while loginwindow is trying
2575 to shutdown apps and while the OS is trying to transition to
2578 Set to true during shutdown, as soon as loginwindow shows
2579 the "shutdown countdown dialog", through individual app
2580 termination, and through black screen kernel shutdown.
2582 LOG("systemShutdown true\n");
2583 systemShutdown
= true;
2586 A shutdown was initiated, but then the shutdown
2587 was cancelled, clearing systemShutdown to false here.
2589 LOG("systemShutdown false\n");
2590 systemShutdown
= false;
2594 case kPowerEventUserDisabledSleep
:
2595 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
2598 #if ROOT_DOMAIN_RUN_STATES
2599 case kPowerEventConfigdRegisteredInterest
:
2600 if (gConfigdNotifier
)
2602 gConfigdNotifier
->release();
2603 gConfigdNotifier
= 0;
2607 gConfigdNotifier
= (IONotifier
*) arg0
;
2612 case kPowerEventAggressivenessChanged
:
2613 aggressivenessChanged();
2619 //******************************************************************************
2620 // systemPowerEventOccurred
2622 // The power controller is notifying us of a hardware-related power management
2623 // event that we must handle.
2625 // systemPowerEventOccurred covers the same functionality that
2626 // receivePowerNotification does; it simply provides a richer API for conveying
2627 // more information.
2628 //******************************************************************************
2630 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
2631 const OSSymbol
*event
,
2634 IOReturn attempt
= kIOReturnSuccess
;
2635 OSNumber
*newNumber
= NULL
;
2638 return kIOReturnBadArgument
;
2640 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
2642 return kIOReturnInternalError
;
2644 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
2646 newNumber
->release();
2651 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
2652 const OSSymbol
*event
,
2655 OSDictionary
*thermalsDict
= NULL
;
2656 bool shouldUpdate
= true;
2658 if (!event
|| !value
)
2659 return kIOReturnBadArgument
;
2662 // We reuse featuresDict Lock because it already exists and guards
2663 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
2664 // of stepping on that lock.
2665 if (featuresDictLock
) IOLockLock(featuresDictLock
);
2667 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
2669 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
2670 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
2672 thermalsDict
= OSDictionary::withCapacity(1);
2675 if (!thermalsDict
) {
2676 shouldUpdate
= false;
2680 thermalsDict
->setObject (event
, value
);
2682 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
2684 thermalsDict
->release();
2688 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
2691 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
2693 return kIOReturnSuccess
;
2697 //******************************************************************************
2698 // receivePowerNotification
2700 // The power controller is notifying us of a hardware-related power management
2701 // event that we must handle. This may be a result of an 'environment' interrupt
2702 // from the power mgt micro.
2703 //******************************************************************************
2705 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
2707 pmPowerStateQueue
->submitPowerEvent(
2708 kPowerEventReceivedPowerNotification
, (void *) msg
);
2709 return kIOReturnSuccess
;
2712 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
2714 bool eval_clamshell
= false;
2719 * Local (IOPMrootDomain only) eval clamshell command
2721 if (msg
& kLocalEvalClamshellCommand
)
2723 eval_clamshell
= true;
2729 if (msg
& kIOPMOverTemp
)
2731 LOG("PowerManagement emergency overtemp signal. Going to sleep!");
2732 privateSleepSystem (kIOPMThermalEmergencySleepKey
);
2737 * PMU Processor Speed Change
2739 if (msg
& kIOPMProcessorSpeedChange
)
2741 IOService
*pmu
= waitForService(serviceMatching("ApplePMU"));
2742 pmu
->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
2743 getPlatform()->sleepKernel();
2744 pmu
->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
2751 if (msg
& kIOPMSleepNow
)
2753 privateSleepSystem (kIOPMSoftwareSleepKey
);
2759 if (msg
& kIOPMPowerEmergency
)
2761 privateSleepSystem (kIOPMLowPowerSleepKey
);
2767 if (msg
& kIOPMClamshellOpened
)
2769 // Received clamshel open message from clamshell controlling driver
2770 // Update our internal state and tell general interest clients
2771 clamshellIsClosed
= false;
2772 clamshellExists
= true;
2775 informCPUStateChange(kInformLid
, 0);
2777 // Tell general interest clients
2778 sendClientClamshellNotification();
2783 * Send the clamshell interest notification since the lid is closing.
2785 if (msg
& kIOPMClamshellClosed
)
2787 // Received clamshel open message from clamshell controlling driver
2788 // Update our internal state and tell general interest clients
2789 clamshellIsClosed
= true;
2790 clamshellExists
= true;
2793 informCPUStateChange(kInformLid
, 1);
2795 // Tell general interest clients
2796 sendClientClamshellNotification();
2798 // And set eval_clamshell = so we can attempt
2799 eval_clamshell
= true;
2803 * Set Desktop mode (sent from graphics)
2805 * -> reevaluate lid state
2807 if (msg
& kIOPMSetDesktopMode
)
2809 desktopMode
= (0 != (msg
& kIOPMSetValue
));
2810 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
2812 sendClientClamshellNotification();
2814 // Re-evaluate the lid state
2815 if( clamshellIsClosed
)
2817 eval_clamshell
= true;
2822 * AC Adaptor connected
2824 * -> reevaluate lid state
2826 if (msg
& kIOPMSetACAdaptorConnected
)
2828 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
2829 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
2832 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
2834 // Tell BSD if AC is connected
2835 // 0 == external power source; 1 == on battery
2836 post_sys_powersource(acAdaptorConnected
? 0:1);
2838 sendClientClamshellNotification();
2840 // Re-evaluate the lid state
2841 if( clamshellIsClosed
)
2843 eval_clamshell
= true;
2848 * Enable Clamshell (external display disappear)
2850 * -> reevaluate lid state
2852 if (msg
& kIOPMEnableClamshell
)
2854 // Re-evaluate the lid state
2855 // System should sleep on external display disappearance
2856 // in lid closed operation.
2857 if( clamshellIsClosed
&& (true == ignoringClamshell
) )
2859 eval_clamshell
= true;
2862 ignoringClamshell
= false;
2864 sendClientClamshellNotification();
2868 * Disable Clamshell (external display appeared)
2869 * We don't bother re-evaluating clamshell state. If the system is awake,
2870 * the lid is probably open.
2872 if (msg
& kIOPMDisableClamshell
)
2874 ignoringClamshell
= true;
2876 sendClientClamshellNotification();
2880 * Evaluate clamshell and SLEEP if appropiate
2882 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
2887 privateSleepSystem (kIOPMClamshellSleepKey
);
2893 if (msg
& kIOPMPowerButton
)
2895 // toggle state of sleep/wake
2897 if ( getPowerState() == DOZE_STATE
)
2900 // yes, tell the tree we're waking
2903 // wake the Display Wrangler
2907 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
2908 // Check that power button sleep is enabled
2910 if( kOSBooleanTrue
!= getProperty(pbs
))
2911 privateSleepSystem (kIOPMPowerButtonSleepKey
);
2920 if ( (msg
& kIOPMAllowSleep
) && !allowSleep
)
2930 if (msg
& kIOPMPreventSleep
) {
2933 if ( getPowerState() == DOZE_STATE
) {
2935 // yes, tell the tree we're waking
2939 // wake the Display Wrangler
2943 // make sure we have power to clamp
2944 patriarch
->wakeSystem();
2950 //******************************************************************************
2951 // getSleepSupported
2953 //******************************************************************************
2955 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
2957 return( platformSleepSupport
);
2961 //******************************************************************************
2962 // setSleepSupported
2964 //******************************************************************************
2966 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
2968 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
2969 OSBitOrAtomic(flags
, &platformSleepSupport
);
2973 //******************************************************************************
2974 // requestPowerDomainState
2976 // The root domain intercepts this call to the superclass.
2977 // Called on the PM work loop thread.
2979 // If the clamp bit is not set in the desire, then the child doesn't need the power
2980 // state it's requesting; it just wants it. The root ignores desires but not needs.
2981 // If the clamp bit is not set, the root takes it that the child can tolerate no
2982 // power and interprets the request accordingly. If all children can thus tolerate
2983 // no power, we are on our way to idle sleep.
2984 //******************************************************************************
2986 IOReturn
IOPMrootDomain::requestPowerDomainState (
2987 IOPMPowerFlags desiredFlags
,
2988 IOPowerConnection
* whichChild
,
2989 unsigned long specification
)
2993 IOPowerConnection
*connection
;
2994 IOPMPowerFlags powerRequestFlag
= 0;
2995 IOPMPowerFlags editedDesire
;
2999 if (kIOLogPMRootDomain
& gIOKitDebug
)
3001 IOService
* powerChild
=
3002 (IOService
*) whichChild
->getChildEntry(gIOPowerPlane
);
3003 DLOG("child %p, flags %lx, spec %lx - %s\n",
3004 powerChild
, desiredFlags
, specification
,
3005 powerChild
? powerChild
->getName() : "?");
3008 // Force the child's input power requirements to 0 unless the prevent
3009 // idle-sleep flag is set. No input power flags map to our state 0.
3010 // Our power clamp (deviceDesire) keeps the minimum power state at 2.
3012 if (desiredFlags
& kIOPMPreventIdleSleep
)
3013 editedDesire
= kIOPMPreventIdleSleep
| kIOPMPowerOn
;
3017 // Recompute sleep supported flag (doze if not supported)
3018 sleepIsSupported
= true;
3020 iter
= getChildIterator(gIOPowerPlane
);
3023 while ( (next
= iter
->getNextObject()) )
3025 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
3027 // Ignore child that are in the process of joining.
3028 if (connection
->getReadyFlag() == false)
3031 // Is this connection attached to the child that called
3032 // requestPowerDomainState()?
3034 if (connection
== whichChild
)
3036 // OR in the child's input power requirements.
3037 powerRequestFlag
|= editedDesire
;
3039 if ( desiredFlags
& kIOPMPreventSystemSleep
)
3040 sleepIsSupported
= false;
3044 if (kIOLogPMRootDomain
& gIOKitDebug
)
3046 IOService
* powerChild
=
3047 (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
3048 DLOG("child %p, state %ld, noIdle %d, noSleep %d - %s\n",
3050 connection
->getDesiredDomainState(),
3051 connection
->getPreventIdleSleepFlag(),
3052 connection
->getPreventSystemSleepFlag(),
3053 powerChild
? powerChild
->getName() : "?");
3056 // OR in the child's desired power state (0 or ON_STATE).
3057 powerRequestFlag
|= connection
->getDesiredDomainState();
3059 if ( connection
->getPreventSystemSleepFlag() )
3060 sleepIsSupported
= false;
3067 DLOG("childPowerFlags 0x%lx, extraSleepDelay %ld\n",
3068 powerRequestFlag
, extraSleepDelay
);
3070 if ( !powerRequestFlag
&& !systemBooting
)
3075 changePowerStateToPriv(ON_STATE
);
3078 // stay awake for at least idleSeconds
3079 startIdleSleepTimer(idleSeconds
);
3082 else if (!extraSleepDelay
&& !idleSleepTimerPending
)
3088 // Drop our power clamp to SLEEP_STATE when all children became idle,
3089 // and the system sleep and display sleep values are equal.
3093 // If our power clamp has already dropped to SLEEP_STATE, and no child
3094 // is keeping us at ON_STATE, then this will trigger idle sleep.
3096 editedDesire
|= (desiredFlags
& kIOPMPreventSystemSleep
);
3098 return super::requestPowerDomainState(
3099 editedDesire
, whichChild
, specification
);
3103 //******************************************************************************
3104 // handlePlatformHaltRestart
3106 //******************************************************************************
3108 struct HaltRestartApplierContext
{
3109 IOPMrootDomain
* RootDomain
;
3110 unsigned long PowerState
;
3111 IOPMPowerFlags PowerFlags
;
3117 platformHaltRestartApplier( OSObject
* object
, void * context
)
3119 IOPowerStateChangeNotification notify
;
3120 HaltRestartApplierContext
* ctx
;
3121 AbsoluteTime startTime
;
3124 ctx
= (HaltRestartApplierContext
*) context
;
3126 memset(¬ify
, 0, sizeof(notify
));
3127 notify
.powerRef
= (void *)ctx
->Counter
;
3128 notify
.returnValue
= 0;
3129 notify
.stateNumber
= ctx
->PowerState
;
3130 notify
.stateFlags
= ctx
->PowerFlags
;
3132 clock_get_uptime(&startTime
);
3133 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
3134 deltaTime
= computeDeltaTimeMS(&startTime
);
3136 if ((deltaTime
> kPMHaltTimeoutMS
) || (gIOKitDebug
& kIOLogDebugPower
))
3138 _IOServiceInterestNotifier
* notifier
;
3139 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
3141 // IOService children of IOPMrootDomain are not instrumented.
3142 // Only IORootParent currently falls under that group.
3146 KLOG("%s handler %p took %u ms\n",
3147 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ?
3148 "PowerOff" : "Restart",
3149 notifier
->handler
, (uint32_t) deltaTime
);
3156 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
3158 HaltRestartApplierContext ctx
;
3159 AbsoluteTime startTime
;
3162 memset(&ctx
, 0, sizeof(ctx
));
3163 ctx
.RootDomain
= this;
3165 clock_get_uptime(&startTime
);
3169 case kPEUPSDelayHaltCPU
:
3170 ctx
.PowerState
= OFF_STATE
;
3171 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
3175 ctx
.PowerState
= RESTART_STATE
;
3176 ctx
.MessageType
= kIOMessageSystemWillRestart
;
3183 // Notify legacy clients
3184 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
3186 // For UPS shutdown leave File Server Mode intact, otherwise turn it off.
3187 if (kPEUPSDelayHaltCPU
!= pe_type
)
3189 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
3190 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
3193 setPMSetting(setting
, num
);
3199 // Notify in power tree order
3200 notifySystemShutdown(this, ctx
.MessageType
);
3202 deltaTime
= computeDeltaTimeMS(&startTime
);
3203 KLOG("%s all drivers took %u ms\n",
3204 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ?
3205 "PowerOff" : "Restart",
3206 (uint32_t) deltaTime
);
3210 //******************************************************************************
3213 //******************************************************************************
3215 IONotifier
* IOPMrootDomain::registerInterest(
3216 const OSSymbol
* typeOfInterest
,
3217 IOServiceInterestHandler handler
,
3218 void * target
, void * ref
)
3220 IONotifier
* notifier
;
3223 isConfigd
= typeOfInterest
&&
3224 typeOfInterest
->isEqualTo(kIOPMPrivilegedPowerInterest
);
3227 typeOfInterest
= gIOAppPowerStateInterest
;
3229 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
3231 #if ROOT_DOMAIN_RUN_STATES
3232 if (isConfigd
&& notifier
&& pmPowerStateQueue
)
3235 if (pmPowerStateQueue
->submitPowerEvent(
3236 kPowerEventConfigdRegisteredInterest
, notifier
) == false)
3237 notifier
->release();
3244 static bool clientMessageFilter( OSObject
* object
, void * arg
)
3246 #if ROOT_DOMAIN_RUN_STATES
3247 #if LOG_INTEREST_CLIENTS
3248 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
3252 switch (gMessageClientType
)
3254 case kMessageClientNone
:
3258 case kMessageClientAll
:
3262 case kMessageClientConfigd
:
3263 allow
= ((object
== (OSObject
*) gConfigdNotifier
) ||
3264 (object
== (OSObject
*) gSysPowerDownNotifier
));
3268 #if LOG_INTEREST_CLIENTS
3270 DLOG("system message %x to %p\n",
3271 context
->msgType
, object
);
3281 //******************************************************************************
3284 // We override the superclass implementation so we can send a different message
3285 // type to the client or application being notified.
3286 //******************************************************************************
3288 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
3292 DLOG("tellChangeDown %u->%u, R-state %u\n",
3293 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3295 switch ( stateNum
) {
3299 if (!ignoreChangeDown
)
3301 // Direct callout into OSKext so it can disable kext unloads
3302 // during sleep/wake to prevent deadlocks.
3303 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
3305 if ( (SLEEP_STATE
== stateNum
) && sleepSupportedPEFunction
)
3307 // Reset PCI prevent sleep flag before calling platform driver.
3308 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
3310 // Skip PCI check for maintenance sleep.
3311 if ((runStateFlags
& kRStateFlagSuppressPCICheck
) == 0)
3313 // Determine if the machine supports sleep, or must doze.
3314 getPlatform()->callPlatformFunction(
3315 sleepSupportedPEFunction
, false,
3316 NULL
, NULL
, NULL
, NULL
);
3319 // If the machine only supports doze, the callPlatformFunction call
3320 // boils down to IOPMrootDomain::setSleepSupported(kPCICantSleep),
3321 // otherwise nothing.
3324 // Update canSleep and kIOSleepSupportedKey property so drivers
3325 // can tell if platform is going to sleep versus doze.
3332 if (!sleepIsSupported
)
3334 if (platformSleepSupport
& kPCICantSleep
)
3336 setProperty(kIOSleepSupportedKey
, canSleep
);
3337 DLOG("canSleep %d\n", canSleep
);
3339 // Publish the new sleep-wake UUID
3340 publishSleepWakeUUID(true);
3342 // Two change downs are sent by IOServicePM. Ignore the 2nd.
3343 ignoreChangeDown
= true;
3345 tracePoint( kIOPMTracePointSystemSleepAppsPhase
);
3348 DLOG("kIOMessageSystemWillSleep (%d)\n", gMessageClientType
);
3349 done
= super::tellClientsWithResponse(
3350 kIOMessageSystemWillSleep
, clientMessageFilter
);
3354 done
= super::tellChangeDown(stateNum
);
3361 //******************************************************************************
3364 // We override the superclass implementation so we can send a different message
3365 // type to the client or application being notified.
3367 // This must be idle sleep since we don't ask during any other power change.
3368 //******************************************************************************
3370 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
3372 DLOG("askChangeDown %u->%u, R-state %u\n",
3373 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3374 DLOG("kIOMessageCanSystemSleep (%d)\n", gMessageClientType
);
3376 return super::tellClientsWithResponse(
3377 kIOMessageCanSystemSleep
,
3378 clientMessageFilter
);
3382 //******************************************************************************
3385 // Notify registered applications and kernel clients that we are not dropping
3388 // We override the superclass implementation so we can send a different message
3389 // type to the client or application being notified.
3391 // This must be a vetoed idle sleep, since no other power change can be vetoed.
3392 //******************************************************************************
3394 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
3396 DLOG("tellNoChangeDown %u->%u, R-state %u\n",
3397 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3399 // Sleep canceled, clear the sleep trace point.
3400 tracePoint(kIOPMTracePointSystemUp
);
3402 if (idleSeconds
&& !wrangler
)
3404 // stay awake for at least idleSeconds
3406 startIdleSleepTimer(idleSeconds
);
3408 DLOG("kIOMessageSystemWillNotSleep (%d)\n", gMessageClientType
);
3409 return tellClients(kIOMessageSystemWillNotSleep
, clientMessageFilter
);
3413 //******************************************************************************
3416 // Notify registered applications and kernel clients that we are raising power.
3418 // We override the superclass implementation so we can send a different message
3419 // type to the client or application being notified.
3420 //******************************************************************************
3422 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
3424 OSData
*publishPMStats
= NULL
;
3426 DLOG("tellChangeUp %u->%u, R-state %u\n",
3427 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3429 ignoreChangeDown
= false;
3431 if ( stateNum
== ON_STATE
)
3433 // Direct callout into OSKext so it can disable kext unloads
3434 // during sleep/wake to prevent deadlocks.
3435 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
3437 if (getPowerState() == ON_STATE
)
3439 // this is a quick wake from aborted sleep
3440 if (idleSeconds
&& !wrangler
)
3442 // stay awake for at least idleSeconds
3444 startIdleSleepTimer(idleSeconds
);
3446 DLOG("kIOMessageSystemWillPowerOn (%d)\n", gMessageClientType
);
3447 tellClients(kIOMessageSystemWillPowerOn
, clientMessageFilter
);
3452 IOHibernateSystemPostWake();
3456 tracePoint(kIOPMTracePointSystemWakeAppsPhase
);
3457 publishPMStats
= OSData::withBytes(&pmStats
, sizeof(pmStats
));
3458 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
3459 publishPMStats
->release();
3460 bzero(&pmStats
, sizeof(pmStats
));
3462 if (pmStatsAppResponses
)
3464 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
3465 pmStatsAppResponses
->release();
3466 pmStatsAppResponses
= OSArray::withCapacity(5);
3469 DLOG("kIOMessageSystemHasPoweredOn (%d)\n", gMessageClientType
);
3470 tellClients(kIOMessageSystemHasPoweredOn
, clientMessageFilter
);
3472 tracePoint(kIOPMTracePointSystemUp
);
3477 //******************************************************************************
3480 //******************************************************************************
3482 void IOPMrootDomain::reportUserInput( void )
3489 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
3492 wrangler
= (IOService
*) iter
->getNextObject();
3498 wrangler
->activityTickle(0,0);
3503 //******************************************************************************
3504 // setQuickSpinDownTimeout
3506 //******************************************************************************
3508 void IOPMrootDomain::setQuickSpinDownTimeout( void )
3512 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
3516 //******************************************************************************
3517 // restoreUserSpinDownTimeout
3519 //******************************************************************************
3521 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
3525 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
3529 //******************************************************************************
3530 // changePowerStateTo & changePowerStateToPriv
3532 // Override of these methods for logging purposes.
3533 //******************************************************************************
3535 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3537 return kIOReturnUnsupported
; // ignored
3540 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3542 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3544 if ( (getPowerState() == DOZE_STATE
) && (ordinal
!= ON_STATE
) )
3546 return kIOReturnSuccess
;
3549 if ( (userDisabledAllSleep
|| systemBooting
|| systemShutdown
) &&
3550 (ordinal
== SLEEP_STATE
) )
3552 DLOG("SLEEP rejected, forced to ON state (UD %d, SB %d, SS %d)\n",
3553 userDisabledAllSleep
, systemBooting
, systemShutdown
);
3555 super::changePowerStateToPriv(ON_STATE
);
3558 return super::changePowerStateToPriv(ordinal
);
3562 //******************************************************************************
3565 //******************************************************************************
3567 void IOPMrootDomain::updateRunState( uint32_t inRunState
)
3569 #if ROOT_DOMAIN_RUN_STATES
3570 if (inRunState
< kRStateCount
)
3572 runStateIndex
= nextRunStateIndex
= inRunState
;
3573 runStateFlags
= gRStateFlags
[inRunState
];
3576 kIOPMRootDomainRunStateKey
,
3577 (unsigned long long) inRunState
, 32);
3583 #if ROOT_DOMAIN_RUN_STATES
3584 //******************************************************************************
3585 // tagPowerPlaneService
3587 // Running on PM work loop thread.
3588 //******************************************************************************
3590 void IOPMrootDomain::tagPowerPlaneService(
3591 IOService
* service
,
3592 uint32_t * rdFlags
)
3596 if (service
->getProperty("IOPMStrictTreeOrder") ||
3597 service
->metaCast("IODisplayWrangler") ||
3598 OSDynamicCast(OSNumber
,
3599 service
->getProperty("IOPMUnattendedWakePowerState")))
3601 *rdFlags
|= kServiceFlagGraphics
;
3602 DLOG("tagged device %s %x\n", service
->getName(), *rdFlags
);
3605 // Locate the first PCI host bridge.
3606 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
3608 IOService
* provider
= service
->getProvider();
3609 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
3610 provider
->inPlane(gIODTPlane
))
3612 pciHostBridgeDevice
= provider
;
3613 DLOG("PMTrace found PCI host bridge %s->%s\n",
3614 provider
->getName(), service
->getName());
3618 // Tag top-level PCI devices. The order of PMinit() call does not
3619 // change across boots and is used as the PCI bit number.
3620 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
3622 // Would prefer to check built-in property, but tagPowerPlaneService()
3623 // is called before pciDevice->registerService().
3624 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
3625 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
3627 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
3630 // Save the assigned bit for fast lookup.
3632 *rdFlags
|= (kServiceFlagTopLevelPCI
| (bit
<< 8));
3639 //******************************************************************************
3640 // handleActivityTickleForService
3642 // Called by IOService::activityTickle() for a tickle that is requesting the
3643 // service to raise power state. Called from driver thread.
3644 //******************************************************************************
3646 void IOPMrootDomain::handleActivityTickleForService( IOService
* service
)
3648 // Tickle directed to IODisplayWrangler while graphics is disabled.
3649 // Bring graphics online.
3651 if ((service
== wrangler
) &&
3652 (runStateIndex
> kRStateNormal
) &&
3653 (false == wranglerTickled
))
3655 DLOG("display wrangler tickled\n");
3656 wranglerTickled
= true;
3657 synchronizePowerTree();
3662 //******************************************************************************
3663 // handlePowerChangeStartForService
3665 // Running on PM work loop thread.
3666 //******************************************************************************
3668 void IOPMrootDomain::handlePowerChangeStartForService(
3669 IOService
* service
,
3671 uint32_t newPowerState
,
3672 uint32_t changeFlags
)
3674 if (service
== this)
3676 uint32_t currentPowerState
= (uint32_t) getPowerState();
3677 uint32_t nextRunStateFlags
;
3679 assert(nextRunStateIndex
< kRStateCount
);
3680 nextRunStateFlags
= gRStateFlags
[nextRunStateIndex
];
3682 gMessageClientType
= kMessageClientNone
;
3684 // Transition towards or away from ON power state.
3686 if ((currentPowerState
!= newPowerState
) &&
3687 ((ON_STATE
== newPowerState
) || (ON_STATE
== currentPowerState
)))
3689 if ((runStateFlags
& kRStateFlagSuppressMessages
) == 0)
3690 gMessageClientType
= kMessageClientAll
;
3692 gMessageClientType
= kMessageClientConfigd
;
3695 // Transition caused by deassertion of system notification suppression.
3697 if ((ON_STATE
== newPowerState
) &&
3698 (ON_STATE
== currentPowerState
) &&
3699 ((runStateFlags
^ nextRunStateFlags
) & kRStateFlagSuppressMessages
))
3701 gMessageClientType
= kMessageClientAll
;
3704 if (ON_STATE
== newPowerState
)
3706 DLOG("kIOMessageSystemWillPowerOn (%d)\n",
3707 gMessageClientType
);
3708 tellClients(kIOMessageSystemWillPowerOn
, clientMessageFilter
);
3711 if (SLEEP_STATE
== newPowerState
)
3713 tracePoint(kIOPMTracePointSleepStarted
);
3717 if (*rdFlags
& kServiceFlagTopLevelPCI
)
3719 pmTracer
->tracePCIPowerChange(
3720 PMTraceWorker::kPowerChangeStart
,
3721 service
, changeFlags
,
3722 (*rdFlags
>> 8) & 0xff);
3727 //******************************************************************************
3728 // handlePowerChangeDoneForService
3730 // Running on PM work loop thread.
3731 //******************************************************************************
3733 void IOPMrootDomain::handlePowerChangeDoneForService(
3734 IOService
* service
,
3736 uint32_t newPowerState
,
3737 uint32_t changeFlags
)
3739 if (*rdFlags
& kServiceFlagTopLevelPCI
)
3741 pmTracer
->tracePCIPowerChange(
3742 PMTraceWorker::kPowerChangeCompleted
,
3743 service
, changeFlags
,
3744 (*rdFlags
>> 8) & 0xff);
3749 //******************************************************************************
3750 // overridePowerStateForService
3752 // Runs on PM work loop thread.
3753 //******************************************************************************
3755 void IOPMrootDomain::overridePowerStateForService(
3756 IOService
* service
,
3758 unsigned long * powerState
,
3759 uint32_t changeFlags
)
3761 uint32_t inPowerState
= (uint32_t) *powerState
;
3763 if ((service
== this) && (inPowerState
== ON_STATE
) &&
3764 (changeFlags
& kIOPMSynchronize
))
3766 DLOG("sync root domain %u->%u\n",
3767 (uint32_t) getPowerState(), inPowerState
);
3769 // Root Domain is in a reduced R-state, and a HID tickle has
3770 // requested a PM tree sync. Begin R-state transition.
3772 if (runStateIndex
!= kRStateNormal
)
3774 nextRunStateIndex
= kRStateNormal
;
3776 kIOPMRootDomainRunStateKey
,
3777 (unsigned long long) kRStateNormal
, 32);
3781 if (*rdFlags
& kServiceFlagGraphics
)
3783 DLOG("graphics device %s %u->%u (flags 0x%x)\n",
3784 service
->getName(), (uint32_t) service
->getPowerState(),
3785 inPowerState
, changeFlags
);
3787 if (inPowerState
== 0)
3789 // Graphics device is powering down, apply limit preventing
3790 // device from powering back up later unless we consent.
3792 if ((*rdFlags
& kServiceFlagNoPowerUp
) == 0)
3794 *rdFlags
|= kServiceFlagNoPowerUp
;
3795 DLOG("asserted power limit for %s\n",
3796 service
->getName());
3801 uint32_t nextRunStateFlags
;
3803 assert(nextRunStateIndex
< kRStateCount
);
3804 nextRunStateFlags
= gRStateFlags
[nextRunStateIndex
];
3806 // Graphics device is powering up. Release power limit at the
3807 // did-change machine state.
3809 if (changeFlags
& kIOPMSynchronize
)
3811 if ((runStateFlags
& kRStateFlagSuppressGraphics
) &&
3812 ((nextRunStateFlags
& kRStateFlagSuppressGraphics
) == 0) &&
3813 (changeFlags
& kIOPMDomainDidChange
))
3815 // Woke up without graphics power, but
3816 // HID event has tickled display wrangler.
3817 *rdFlags
&= ~kServiceFlagNoPowerUp
;
3818 DLOG("removed power limit for %s\n",
3819 service
->getName());
3822 else if ((runStateFlags
& kRStateFlagSuppressGraphics
) == 0)
3824 *rdFlags
&= ~kServiceFlagNoPowerUp
;
3827 if (*rdFlags
& kServiceFlagNoPowerUp
)
3829 DLOG("limited %s to power state 0\n",
3830 service
->getName());
3838 //******************************************************************************
3839 // setMaintenanceWakeCalendar
3841 //******************************************************************************
3843 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
3844 const IOPMCalendarStruct
* calendar
)
3850 return kIOReturnBadArgument
;
3852 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
3854 return kIOReturnNoMemory
;
3856 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
3861 #endif /* ROOT_DOMAIN_RUN_STATES */
3864 //******************************************************************************
3865 // sysPowerDownHandler
3867 // Receives a notification when the RootDomain changes state.
3869 // Allows us to take action on system sleep, power down, and restart after
3870 // applications have received their power change notifications and replied,
3871 // but before drivers have powered down. We perform a vfs sync on power down.
3872 //******************************************************************************
3874 IOReturn
IOPMrootDomain::sysPowerDownHandler( void * target
, void * refCon
,
3875 UInt32 messageType
, IOService
* service
,
3876 void * messageArgument
, vm_size_t argSize
)
3879 IOPowerStateChangeNotification
*params
= (IOPowerStateChangeNotification
*) messageArgument
;
3880 IOPMrootDomain
*rootDomain
= OSDynamicCast(IOPMrootDomain
, service
);
3882 DLOG("sysPowerDownHandler message %x\n", (uint32_t) messageType
);
3885 return kIOReturnUnsupported
;
3887 switch (messageType
) {
3888 case kIOMessageSystemWillSleep
:
3889 // Interested applications have been notified of an impending power
3890 // change and have acked (when applicable).
3891 // This is our chance to save whatever state we can before powering
3893 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3896 // We will ack within 20 seconds
3897 params
->returnValue
= 20 * 1000 * 1000;
3899 if (gIOHibernateState
)
3900 params
->returnValue
+= gIOHibernateFreeTime
* 1000; //add in time we could spend freeing pages
3903 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
3905 // Purposely delay the ack and hope that shutdown occurs quickly.
3906 // Another option is not to schedule the thread and wait for
3908 AbsoluteTime deadline
;
3909 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
3910 thread_call_enter1_delayed( rootDomain
->diskSyncCalloutEntry
,
3911 (thread_call_param_t
)params
->powerRef
,
3915 thread_call_enter1(rootDomain
->diskSyncCalloutEntry
, (thread_call_param_t
)params
->powerRef
);
3916 ret
= kIOReturnSuccess
;
3919 case kIOMessageSystemWillPowerOff
:
3920 case kIOMessageSystemWillRestart
:
3921 ret
= kIOReturnUnsupported
;
3925 ret
= kIOReturnUnsupported
;
3931 //******************************************************************************
3932 // publishSleepWakeUUID
3935 //******************************************************************************
3936 void IOPMrootDomain::publishSleepWakeUUID( bool shouldPublish
)
3940 if (queuedSleepWakeUUIDString
)
3942 if (OSCompareAndSwap(/*old*/ true, /*new*/ false, &gSleepWakeUUIDIsSet
))
3944 // Upon wake, it takes some time for userland to invalidate the
3945 // UUID. If another sleep is initiated during that period, force
3946 // a CLEAR message to balance the upcoming SET message.
3948 messageClients( kIOPMMessageSleepWakeUUIDChange
,
3949 kIOPMMessageSleepWakeUUIDCleared
);
3951 DLOG("SleepWake UUID forced clear\n");
3954 setProperty(kIOPMSleepWakeUUIDKey
, queuedSleepWakeUUIDString
);
3955 DLOG("SleepWake UUID published: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3956 queuedSleepWakeUUIDString
->release();
3957 queuedSleepWakeUUIDString
= NULL
;
3958 messageClients(kIOPMMessageSleepWakeUUIDChange
,
3959 kIOPMMessageSleepWakeUUIDSet
);
3962 if (OSCompareAndSwap(/*old*/ true, /*new*/ false, &gSleepWakeUUIDIsSet
))
3964 DLOG("SleepWake UUID cleared\n");
3965 removeProperty(kIOPMSleepWakeUUIDKey
);
3966 messageClients(kIOPMMessageSleepWakeUUIDChange
,
3967 kIOPMMessageSleepWakeUUIDCleared
);
3973 //******************************************************************************
3974 // displayWranglerNotification
3976 // Receives a notification when the IODisplayWrangler changes state.
3978 // Allows us to take action on display dim/undim.
3980 // When the display sleeps we:
3981 // - Start the idle sleep timer
3982 // - set the quick spin down timeout
3984 // On wake from display sleep:
3985 // - Cancel the idle sleep timer
3986 // - restore the user's chosen spindown timer from the "quick" spin down value
3987 //******************************************************************************
3989 IOReturn
IOPMrootDomain::displayWranglerNotification(
3990 void * target
, void * refCon
,
3991 UInt32 messageType
, IOService
* service
,
3992 void * messageArgument
, vm_size_t argSize
)
3995 int displayPowerState
;
3996 IOPowerStateChangeNotification
* params
=
3997 (IOPowerStateChangeNotification
*) messageArgument
;
3999 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
4000 (messageType
!= kIOMessageDeviceHasPoweredOn
))
4001 return kIOReturnUnsupported
;
4005 return kIOReturnUnsupported
;
4007 displayPowerState
= params
->stateNumber
;
4008 DLOG("DisplayWrangler message 0x%x, new power state %d\n",
4009 (uint32_t) messageType
, displayPowerState
);
4011 switch (messageType
) {
4012 case kIOMessageDeviceWillPowerOff
:
4014 // The display wrangler has dropped power because of idle display sleep
4015 // or force system sleep.
4020 // 1 Not visible to user
4021 // 0 Not visible to user
4023 if (gRootDomain
->wranglerAsleep
|| (displayPowerState
> 2))
4026 // Record the time the display wrangler went to sleep.
4028 gRootDomain
->wranglerAsleep
= true;
4029 clock_get_uptime(&gRootDomain
->wranglerSleepTime
);
4031 // We start a timer here if the System Sleep timer is greater than the
4032 // Display Sleep timer. We kick off this timer when the display sleeps.
4034 // Note that, although Display Dim timings may change adaptively accordingly
4035 // to the user's activity patterns, Display Sleep _always_ occurs at the
4036 // specified interval since last user activity.
4038 if ( gRootDomain
->extraSleepDelay
)
4040 gRootDomain
->startIdleSleepTimer(gRootDomain
->extraSleepDelay
* 60);
4042 else if ( gRootDomain
->sleepSlider
)
4044 // Accelerate disk spindown if system sleep and display sleep
4045 // sliders are set to the same value (e.g. both set to 5 min),
4046 // and display is about to go dark. Check that spin down timer
4047 // is non-zero (zero = never spin down) and system sleep is
4048 // not set to never sleep.
4050 gRootDomain
->setQuickSpinDownTimeout();
4055 case kIOMessageDeviceHasPoweredOn
:
4057 // The display wrangler has powered on either because of user activity
4058 // or wake from sleep/doze.
4060 if ( 4 != displayPowerState
)
4063 gRootDomain
->wranglerAsleep
= false;
4064 gRootDomain
->adjustPowerState();
4065 gRootDomain
->cancelIdleSleepTimer();
4067 // Change the spindown value back to the user's selection from our
4068 // accelerated setting.
4069 gRootDomain
->restoreUserSpinDownTimeout();
4077 return kIOReturnUnsupported
;
4081 //******************************************************************************
4082 // displayWranglerPublished
4084 // Receives a notification when the IODisplayWrangler is published.
4085 // When it's published we install a power state change handler.
4086 //******************************************************************************
4088 bool IOPMrootDomain::displayWranglerPublished(
4091 IOService
* newService
)
4097 gRootDomain
->wrangler
= newService
;
4099 // we found the display wrangler, now install a handler
4100 if( !gRootDomain
->wrangler
->registerInterest( gIOGeneralInterest
,
4101 &displayWranglerNotification
, target
, 0) )
4110 //******************************************************************************
4113 // Notification on battery class IOPowerSource appearance
4114 //******************************************************************************
4116 bool IOPMrootDomain::batteryPublished(
4119 IOService
* resourceService
)
4121 // rdar://2936060&4435589
4122 // All laptops have dimmable LCD displays
4123 // All laptops have batteries
4124 // So if this machine has a battery, publish the fact that the backlight
4125 // supports dimming.
4126 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
4132 //******************************************************************************
4135 // Some condition that affects our wake/sleep/doze decision has changed.
4137 // If the sleep slider is in the off position, we cannot sleep or doze.
4138 // If the enclosure is open, we cannot sleep or doze.
4139 // If the system is still booting, we cannot sleep or doze.
4141 // In those circumstances, we prevent sleep and doze by holding power on with
4142 // changePowerStateToPriv(ON).
4144 // If the above conditions do not exist, and also the sleep timer has expired,
4145 // we allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
4146 // changePowerStateToPriv(DOZE) depending on whether or not we already know the
4147 // platform cannot sleep.
4149 // In this case, sleep or doze will either occur immediately or at the next time
4150 // that no children are holding the system out of idle sleep via the
4151 // kIOPMPreventIdleSleep flag in their power state arrays.
4152 //******************************************************************************
4154 void IOPMrootDomain::adjustPowerState( void )
4156 DLOG("adjustPowerState "
4157 "PS %u, ASAP %d, SL %ld, AS %d, SB %d, SS %d, UD %d\n",
4158 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
,
4159 allowSleep
, systemBooting
, systemShutdown
, userDisabledAllSleep
);
4163 if ( (sleepSlider
== 0)
4167 || userDisabledAllSleep
4168 || (runStateFlags
& kRStateFlagDisableIdleSleep
) )
4170 changePowerStateToPriv(ON_STATE
);
4174 /* Convenient place to run any code at idle sleep time
4175 * IOPMrootDomain initiates an idle sleep here
4177 * Set last sleep cause accordingly.
4179 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
4182 changePowerStateToPriv(SLEEP_STATE
);
4187 void IOPMrootDomain::pmStatsRecordEvent(
4189 AbsoluteTime timestamp
)
4191 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
4192 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
4196 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
4198 absolutetime_to_nanoseconds(timestamp
, &nsec
);
4200 switch (eventIndex
) {
4201 case kIOPMStatsHibernateImageWrite
:
4203 pmStats
.hibWrite
.start
= nsec
;
4205 pmStats
.hibWrite
.stop
= nsec
;
4208 delta
= pmStats
.hibWrite
.stop
- pmStats
.hibWrite
.start
;
4209 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
4212 case kIOPMStatsHibernateImageRead
:
4214 pmStats
.hibRead
.start
= nsec
;
4216 pmStats
.hibRead
.stop
= nsec
;
4219 delta
= pmStats
.hibRead
.stop
- pmStats
.hibRead
.start
;
4220 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
4227 * Appends a record of the application response to
4228 * IOPMrootDomain::pmStatsAppResponses
4230 void IOPMrootDomain::pmStatsRecordApplicationResponse(
4231 const OSSymbol
*response
,
4237 OSDictionary
*responseDescription
= NULL
;
4238 OSNumber
*delayNum
= NULL
;
4239 OSNumber
*pidNum
= NULL
;
4240 OSNumber
*msgNum
= NULL
;
4241 const OSSymbol
*appname
;
4242 const OSSymbol
*entryName
;
4243 OSObject
*entryType
;
4246 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
4250 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
4252 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
4253 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
4254 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
))
4256 OSNumber
* entryValue
;
4257 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
4258 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
4259 entryValue
->setValue(delay_ms
);
4264 responseDescription
= OSDictionary::withCapacity(5);
4265 if (responseDescription
)
4268 responseDescription
->setObject(_statsResponseTypeKey
, response
);
4271 if (messageType
!= 0) {
4272 msgNum
= OSNumber::withNumber(messageType
, 32);
4274 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
4279 if (name
&& (strlen(name
) > 0))
4281 appname
= OSSymbol::withCString(name
);
4283 responseDescription
->setObject(_statsNameKey
, appname
);
4288 if (app_pid
!= -1) {
4289 pidNum
= OSNumber::withNumber(app_pid
, 32);
4291 responseDescription
->setObject(_statsPIDKey
, pidNum
);
4296 delayNum
= OSNumber::withNumber(delay_ms
, 32);
4298 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
4299 delayNum
->release();
4302 if (pmStatsAppResponses
) {
4303 pmStatsAppResponses
->setObject(responseDescription
);
4306 responseDescription
->release();
4312 //******************************************************************************
4313 // TracePoint support
4315 //******************************************************************************
4317 #define kIOPMRegisterNVRAMTracePointHandlerKey \
4318 "IOPMRegisterNVRAMTracePointHandler"
4320 IOReturn
IOPMrootDomain::callPlatformFunction(
4321 const OSSymbol
* functionName
,
4322 bool waitForFunction
,
4323 void * param1
, void * param2
,
4324 void * param3
, void * param4
)
4326 if (pmTracer
&& functionName
&&
4327 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
4328 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
4330 uint32_t tracePointPhases
, tracePointPCI
;
4331 uint64_t statusCode
;
4333 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
4334 pmTracer
->tracePointTarget
= (void *) param2
;
4335 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
4336 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
4337 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
4338 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
4340 LOG("Sleep failure code 0x%08x 0x%08x\n",
4341 tracePointPCI
, tracePointPhases
);
4343 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
4344 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
4346 return kIOReturnSuccess
;
4349 return super::callPlatformFunction(
4350 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
4353 void IOPMrootDomain::tracePoint( uint8_t point
)
4355 pmTracer
->tracePoint(point
);
4358 //******************************************************************************
4359 // PMTraceWorker Class
4361 //******************************************************************************
4364 #define super OSObject
4365 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
4367 #define kPMBestGuessPCIDevicesCount 25
4368 #define kPMMaxRTCBitfieldSize 32
4370 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
4374 me
= OSTypeAlloc( PMTraceWorker
);
4375 if (!me
|| !me
->init())
4380 DLOG("PMTraceWorker %p\n", me
);
4382 // Note that we cannot instantiate the PCI device -> bit mappings here, since
4383 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
4384 // this dictionary lazily.
4386 me
->pciDeviceBitMappings
= NULL
;
4387 me
->pciMappingLock
= IOLockAlloc();
4388 me
->tracePhase
= kIOPMTracePointSystemUp
;
4389 me
->loginWindowPhase
= 0;
4390 me
->pciBusyBitMask
= 0;
4394 void PMTraceWorker::RTC_TRACE(void)
4396 if (tracePointHandler
&& tracePointTarget
)
4400 wordA
= tracePhase
; // destined for bits 24-31
4402 wordA
|= loginWindowPhase
; // destined for bits 16-23
4405 tracePointHandler( tracePointTarget
, pciBusyBitMask
, wordA
);
4406 DLOG("RTC_TRACE wrote 0x%08x 0x%08x\n", pciBusyBitMask
, wordA
);
4410 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
4412 const OSSymbol
* deviceName
;
4415 IOLockLock(pciMappingLock
);
4417 if (!pciDeviceBitMappings
)
4419 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
4420 if (!pciDeviceBitMappings
)
4424 // Check for bitmask overflow.
4425 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
4428 if ((deviceName
= pciDevice
->copyName()) &&
4429 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
4430 pciDeviceBitMappings
->setObject(deviceName
))
4432 index
= pciDeviceBitMappings
->getCount() - 1;
4433 DLOG("PMTrace PCI array: set object %s => %d\n",
4434 deviceName
->getCStringNoCopy(), index
);
4437 deviceName
->release();
4438 if (!addedToRegistry
&& (index
>= 0))
4439 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
4442 IOLockUnlock(pciMappingLock
);
4446 bool PMTraceWorker::serialize(OSSerialize
*s
) const
4449 if (pciDeviceBitMappings
)
4451 IOLockLock(pciMappingLock
);
4452 ok
= pciDeviceBitMappings
->serialize(s
);
4453 IOLockUnlock(pciMappingLock
);
4458 void PMTraceWorker::tracePoint(uint8_t phase
)
4462 DLOG("IOPMrootDomain: trace point 0x%02x\n", tracePhase
);
4466 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
4468 loginWindowPhase
= phase
;
4470 DLOG("IOPMrootDomain: loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
4474 void PMTraceWorker::tracePCIPowerChange(
4475 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
4478 uint32_t expectedFlag
;
4480 // Ignore PCI changes outside of system sleep/wake.
4481 if ((kIOPMTracePointSystemSleepDriversPhase
!= tracePhase
) &&
4482 (kIOPMTracePointSystemWakeDriversPhase
!= tracePhase
))
4485 // Only record the WillChange transition when going to sleep,
4486 // and the DidChange on the way up.
4487 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
4488 expectedFlag
= (kIOPMTracePointSystemSleepDriversPhase
== tracePhase
) ?
4489 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
4490 if (changeFlags
!= expectedFlag
)
4493 // Mark this device off in our bitfield
4494 if (bitNum
< kPMMaxRTCBitfieldSize
)
4496 bitMask
= (1 << bitNum
);
4498 if (kPowerChangeStart
== type
)
4500 pciBusyBitMask
|= bitMask
;
4501 DLOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
4502 service
->getName(), bitNum
, bitMask
, pciBusyBitMask
);
4506 pciBusyBitMask
&= ~bitMask
;
4507 DLOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
4508 service
->getName(), bitNum
, bitMask
, pciBusyBitMask
);
4516 //******************************************************************************
4517 // PMHaltWorker Class
4519 //******************************************************************************
4521 static unsigned int gPMHaltBusyCount
;
4522 static unsigned int gPMHaltIdleCount
;
4523 static int gPMHaltDepth
;
4524 static unsigned long gPMHaltEvent
;
4525 static IOLock
* gPMHaltLock
= 0;
4526 static OSArray
* gPMHaltArray
= 0;
4527 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
4529 PMHaltWorker
* PMHaltWorker::worker( void )
4535 me
= OSTypeAlloc( PMHaltWorker
);
4536 if (!me
|| !me
->init())
4539 me
->lock
= IOLockAlloc();
4543 DLOG("PMHaltWorker %p\n", me
);
4544 me
->retain(); // thread holds extra retain
4545 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
4550 thread_deallocate(thread
);
4555 if (me
) me
->release();
4559 void PMHaltWorker::free( void )
4561 DLOG("PMHaltWorker free %p\n", this);
4567 return OSObject::free();
4570 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
4572 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
4574 IOLockLock( gPMHaltLock
);
4576 me
->depth
= gPMHaltDepth
;
4577 IOLockUnlock( gPMHaltLock
);
4579 while (me
->depth
>= 0)
4581 PMHaltWorker::work( me
);
4583 IOLockLock( gPMHaltLock
);
4584 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
4586 // This is the last thread to finish work on this level,
4587 // inform everyone to start working on next lower level.
4589 me
->depth
= gPMHaltDepth
;
4590 gPMHaltIdleCount
= 0;
4591 thread_wakeup((event_t
) &gPMHaltIdleCount
);
4595 // One or more threads are still working on this level,
4596 // this thread must wait.
4597 me
->depth
= gPMHaltDepth
- 1;
4599 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
4600 } while (me
->depth
!= gPMHaltDepth
);
4602 IOLockUnlock( gPMHaltLock
);
4605 // No more work to do, terminate thread
4606 DLOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
4607 thread_wakeup( &gPMHaltDepth
);
4611 void PMHaltWorker::work( PMHaltWorker
* me
)
4613 IOService
* service
;
4615 AbsoluteTime startTime
;
4624 // Claim an unit of work from the shared pool
4625 IOLockLock( gPMHaltLock
);
4626 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
4629 service
= (IOService
*)inner
->getAnyObject();
4633 inner
->removeObject(service
);
4636 IOLockUnlock( gPMHaltLock
);
4638 break; // no more work at this depth
4640 clock_get_uptime(&startTime
);
4642 if (!service
->isInactive() &&
4643 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
4645 IOLockLock(me
->lock
);
4646 me
->startTime
= startTime
;
4647 me
->service
= service
;
4648 me
->timeout
= false;
4649 IOLockUnlock(me
->lock
);
4651 service
->systemWillShutdown( gPMHaltEvent
);
4653 // Wait for driver acknowledgement
4654 IOLockLock(me
->lock
);
4655 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
4657 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
4660 timeout
= me
->timeout
;
4661 IOLockUnlock(me
->lock
);
4664 deltaTime
= computeDeltaTimeMS(&startTime
);
4665 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
4666 (gIOKitDebug
& (kIOLogDebugPower
| kIOLogPMRootDomain
)))
4668 KLOG("%s driver %s (%p) took %u ms\n",
4669 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
4670 "PowerOff" : "Restart",
4671 service
->getName(), service
,
4672 (uint32_t) deltaTime
);
4680 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
4683 AbsoluteTime startTime
;
4684 AbsoluteTime endTime
;
4688 IOLockLock(me
->lock
);
4689 if (me
->service
&& !me
->timeout
)
4691 startTime
= me
->startTime
;
4693 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
4695 SUB_ABSOLUTETIME(&endTime
, &startTime
);
4696 absolutetime_to_nanoseconds(endTime
, &nano
);
4698 if (nano
> 3000000000ULL)
4701 LOG("%s still waiting on %s\n",
4702 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
4703 "PowerOff" : "Restart",
4704 me
->service
->getName());
4707 IOLockUnlock(me
->lock
);
4711 //******************************************************************************
4712 // acknowledgeSystemWillShutdown
4714 // Acknowledgement from drivers that they have prepared for shutdown/restart.
4715 //******************************************************************************
4717 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
4719 PMHaltWorker
* worker
;
4725 //DLOG("%s acknowledged\n", from->getName());
4726 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
4729 worker
= (PMHaltWorker
*) prop
;
4730 IOLockLock(worker
->lock
);
4731 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
4732 thread_wakeup((event_t
) worker
);
4733 IOLockUnlock(worker
->lock
);
4738 DLOG("%s acknowledged without worker property\n",
4744 //******************************************************************************
4745 // notifySystemShutdown
4747 // Notify all objects in PM tree that system will shutdown or restart
4748 //******************************************************************************
4751 notifySystemShutdown( IOService
* root
, unsigned long event
)
4753 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
4754 IORegistryIterator
* iter
;
4755 IORegistryEntry
* entry
;
4758 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
4759 AbsoluteTime deadline
;
4760 unsigned int totalNodes
= 0;
4762 unsigned int rootDepth
;
4763 unsigned int numWorkers
;
4769 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
4771 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
4773 // Iterate the entire PM tree starting from root
4775 rootDepth
= root
->getDepth( gIOPowerPlane
);
4776 if (!rootDepth
) goto done
;
4778 // debug - for repeated test runs
4779 while (PMHaltWorker::metaClass
->getInstanceCount())
4784 gPMHaltArray
= OSArray::withCapacity(40);
4785 if (!gPMHaltArray
) goto done
;
4788 gPMHaltArray
->flushCollection();
4792 gPMHaltLock
= IOLockAlloc();
4793 if (!gPMHaltLock
) goto done
;
4796 if (!gPMHaltClientAcknowledgeKey
)
4798 gPMHaltClientAcknowledgeKey
=
4799 OSSymbol::withCStringNoCopy("PMShutdown");
4800 if (!gPMHaltClientAcknowledgeKey
) goto done
;
4803 gPMHaltEvent
= event
;
4805 // Depth-first walk of PM plane
4807 iter
= IORegistryIterator::iterateOver(
4808 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
4812 while ((entry
= iter
->getNextObject()))
4814 node
= OSDynamicCast(IOService
, entry
);
4819 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
4822 depth
= node
->getDepth( gIOPowerPlane
);
4823 if (depth
<= rootDepth
)
4828 // adjust to zero based depth
4829 depth
-= (rootDepth
+ 1);
4831 // gPMHaltArray is an array of containers, each container
4832 // refers to nodes with the same depth.
4834 count
= gPMHaltArray
->getCount();
4835 while (depth
>= count
)
4837 // expand array and insert placeholders
4838 gPMHaltArray
->setObject(PLACEHOLDER
);
4841 count
= gPMHaltArray
->getCount();
4844 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
4845 if (inner
== PLACEHOLDER
)
4847 inner
= OSSet::withCapacity(40);
4850 gPMHaltArray
->replaceObject(depth
, inner
);
4855 // PM nodes that appear more than once in the tree will have
4856 // the same depth, OSSet will refuse to add the node twice.
4858 ok
= inner
->setObject(node
);
4861 DLOG("Skipped PM node %s\n", node
->getName());
4867 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
4870 if (inner
!= PLACEHOLDER
)
4871 count
= inner
->getCount();
4872 DLOG("Nodes at depth %u = %u\n", i
, count
);
4875 // strip placeholders (not all depths are populated)
4877 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
4879 if (inner
== PLACEHOLDER
)
4881 gPMHaltArray
->removeObject(i
);
4884 count
= inner
->getCount();
4885 if (count
> numWorkers
)
4887 totalNodes
+= count
;
4891 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
4894 gPMHaltBusyCount
= 0;
4895 gPMHaltIdleCount
= 0;
4896 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
4898 // Create multiple workers (and threads)
4900 if (numWorkers
> kPMHaltMaxWorkers
)
4901 numWorkers
= kPMHaltMaxWorkers
;
4903 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
4904 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
4906 for (unsigned int i
= 0; i
< numWorkers
; i
++)
4907 workers
[i
] = PMHaltWorker::worker();
4909 // Wait for workers to exhaust all available work
4911 IOLockLock(gPMHaltLock
);
4912 while (gPMHaltDepth
>= 0)
4914 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
4916 waitResult
= IOLockSleepDeadline(
4917 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
4918 if (THREAD_TIMED_OUT
== waitResult
)
4921 clock_get_uptime(&now
);
4923 IOLockUnlock(gPMHaltLock
);
4924 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
4927 PMHaltWorker::checkTimeout(workers
[i
], &now
);
4929 IOLockLock(gPMHaltLock
);
4932 IOLockUnlock(gPMHaltLock
);
4934 // Release all workers
4936 for (unsigned int i
= 0; i
< numWorkers
; i
++)
4939 workers
[i
]->release();
4940 // worker also retained by it's own thread
4944 DLOG("%s done\n", __FUNCTION__
);
4949 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4953 #define super OSObject
4954 OSDefineMetaClassAndFinalStructors(PMSettingObject
, OSObject
)
4956 void PMSettingObject::setPMSetting(const OSSymbol
*type
, OSObject
*obj
)
4958 (*func
)(target
, type
, obj
, refcon
);
4962 * Static constructor/initializer for PMSettingObject
4964 PMSettingObject
*PMSettingObject::pmSettingObject(
4965 IOPMrootDomain
*parent_arg
,
4966 IOPMSettingControllerCallback handler_arg
,
4967 OSObject
*target_arg
,
4968 uintptr_t refcon_arg
,
4969 uint32_t supportedPowerSources
,
4970 const OSSymbol
* settings
[])
4972 uint32_t objCount
= 0;
4973 PMSettingObject
*pmso
;
4975 if( !parent_arg
|| !handler_arg
|| !settings
) return NULL
;
4977 // count OSSymbol entries in NULL terminated settings array
4978 while( settings
[objCount
] ) {
4981 if(0 == objCount
) return NULL
;
4983 pmso
= new PMSettingObject
;
4984 if(!pmso
|| !pmso
->init()) return NULL
;
4986 pmso
->parent
= parent_arg
;
4987 pmso
->func
= handler_arg
;
4988 pmso
->target
= target_arg
;
4989 pmso
->refcon
= refcon_arg
;
4990 pmso
->releaseAtCount
= objCount
+ 1; // release when it has count+1 retains
4992 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount
);
4993 if(pmso
->publishedFeatureID
) {
4994 for(unsigned int i
=0; i
<objCount
; i
++) {
4995 // Since there is now at least one listener to this setting, publish
4996 // PM root domain support for it.
4997 parent_arg
->publishFeature( settings
[i
]->getCStringNoCopy(),
4998 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
5005 void PMSettingObject::free(void)
5007 OSCollectionIterator
*settings_iter
;
5012 int objCount
= releaseAtCount
- 1;
5014 if(publishedFeatureID
) {
5015 for(i
=0; i
<objCount
; i
++) {
5016 if(0 != publishedFeatureID
[i
]) {
5017 parent
->removePublishedFeature( publishedFeatureID
[i
] );
5021 IOFree(publishedFeatureID
, sizeof(uint32_t) * objCount
);
5024 IORecursiveLockLock(parent
->settingsCtrlLock
);
5026 // Search each PM settings array in the kernel.
5027 settings_iter
= OSCollectionIterator::withCollection(parent
->settingsCallbacks
);
5030 while(( sym
= OSDynamicCast(OSSymbol
, settings_iter
->getNextObject()) ))
5032 arr
= (OSArray
*)parent
->settingsCallbacks
->getObject(sym
);
5033 arr_idx
= arr
->getNextIndexOfObject(this, 0);
5035 // 'this' was found in the array; remove it
5036 arr
->removeObject(arr_idx
);
5040 settings_iter
->release();
5043 IORecursiveLockUnlock(parent
->settingsCtrlLock
);
5048 void PMSettingObject::taggedRelease(const void *tag
, const int when
) const
5050 // We have n+1 retains - 1 per array that this PMSettingObject is a member
5051 // of, and 1 retain to ourself. When we get a release with n+1 retains
5052 // remaining, we go ahead and free ourselves, cleaning up array pointers
5055 super::taggedRelease(tag
, releaseAtCount
);
5060 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5063 #define super IOService
5065 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
5067 // This array exactly parallels the state array for the root domain.
5068 // Power state changes initiated by a device can be vetoed by a client of the device, and
5069 // power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
5070 // so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
5071 // its parent to make the change. That is the reason for this complexity.
5073 static IOPMPowerState patriarchPowerStates
[NUM_POWER_STATES
] =
5075 {1,0,0,0,0,0,0,0,0,0,0,0}, // off (not used)
5076 {1,0,RESTART_POWER
,0,0,0,0,0,0,0,0,0}, // reset (not used)
5077 {1,0,SLEEP_POWER
,0,0,0,0,0,0,0,0,0}, // sleep
5078 {1,0,DOZE_POWER
,0,0,0,0,0,0,0,0,0}, // doze
5079 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0}, // running
5082 bool IORootParent::start( IOService
* nub
)
5084 mostRecentChange
= ON_STATE
;
5086 attachToParent( getRegistryRoot(), gIOPowerPlane
);
5088 registerPowerDriver(this, patriarchPowerStates
, NUM_POWER_STATES
);
5090 powerOverrideOnPriv();
5094 void IORootParent::shutDownSystem( void )
5098 void IORootParent::restartSystem( void )
5102 void IORootParent::sleepSystem( void )
5104 mostRecentChange
= SLEEP_STATE
;
5105 changePowerStateToPriv(SLEEP_STATE
);
5108 void IORootParent::dozeSystem( void )
5110 mostRecentChange
= DOZE_STATE
;
5111 changePowerStateToPriv(DOZE_STATE
);
5114 // Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
5115 // This brings the parent to doze, which allows the root to step up from sleep to doze.
5117 // In idle sleep, do nothing because the parent is still on and the root can freely change state.
5119 void IORootParent::sleepToDoze( void )
5121 if ( mostRecentChange
== SLEEP_STATE
) {
5122 changePowerStateToPriv(DOZE_STATE
);
5126 void IORootParent::wakeSystem( void )
5128 mostRecentChange
= ON_STATE
;
5129 changePowerStateToPriv(ON_STATE
);