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 tracePoint(kIOPMTracePointSleepStarted
);
1775 patriarch
->sleepSystem();
1776 return kIOReturnSuccess
;
1780 //******************************************************************************
1783 //******************************************************************************
1785 IOReturn
IOPMrootDomain::shutdownSystem( void )
1787 //patriarch->shutDownSystem();
1788 return kIOReturnUnsupported
;
1792 //******************************************************************************
1795 //******************************************************************************
1797 IOReturn
IOPMrootDomain::restartSystem( void )
1799 //patriarch->restartSystem();
1800 return kIOReturnUnsupported
;
1804 //******************************************************************************
1807 // This overrides powerChangeDone in IOService.
1809 // Menu sleep and idle sleep move us from the ON state to the SLEEP_STATE.
1811 // If we finished going to the SLEEP_STATE, and the platform is capable of
1812 // true sleep, then sleep the kernel. Otherwise switch up to the DOZE_STATE
1813 // which will keep almost everything as off as it can get.
1814 //******************************************************************************
1816 void IOPMrootDomain::powerChangeDone( unsigned long previousState
)
1819 DLOG("PowerChangeDone: %u->%u\n",
1820 (uint32_t) previousState
, (uint32_t) getPowerState());
1822 switch ( getPowerState() ) {
1824 if ( previousState
!= ON_STATE
)
1829 // re-enable this timer for next sleep
1830 cancelIdleSleepTimer();
1831 wranglerTickled
= true;
1834 clock_usec_t microsecs
;
1835 clock_get_calendar_microtime(&secs
, µsecs
);
1837 gIOLastSleepTime
.tv_sec
= secs
;
1838 gIOLastSleepTime
.tv_usec
= microsecs
;
1839 gIOLastWakeTime
.tv_sec
= 0;
1840 gIOLastWakeTime
.tv_usec
= 0;
1843 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
1845 tracePoint(kIOPMTracePointSystemHibernatePhase
);
1847 IOHibernateSystemHasSlept();
1849 LOG("System Sleep\n");
1852 tracePoint(kIOPMTracePointSystemSleepPlatformPhase
);
1854 getPlatform()->sleepKernel();
1856 // The CPU(s) are off at this point. When they're awakened by CPU interrupt,
1857 // code will resume execution here.
1859 // Now we're waking...
1860 tracePoint(kIOPMTracePointSystemWakeDriversPhase
);
1863 IOHibernateSystemWake();
1866 // sleep transition complete
1867 gSleepOrShutdownPending
= 0;
1869 // trip the reset of the calendar clock
1870 clock_wakeup_calendar();
1872 // get us some power
1873 patriarch
->wakeSystem();
1875 // Set indicator if UUID was set - allow it to be cleared.
1876 if (getProperty(kIOPMSleepWakeUUIDKey
))
1877 gSleepWakeUUIDIsSet
= true;
1879 #if !ROOT_DOMAIN_RUN_STATES
1880 tellClients(kIOMessageSystemWillPowerOn
, clientMessageFilter
);
1884 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
1888 getPlatform()->PMLog(kIOPMrootDomainClass
, kPMLogSystemWake
, 0, 0);
1891 // tell the tree we're waking
1896 #if defined(__i386__) || defined(__x86_64__)
1897 #if ROOT_DOMAIN_RUN_STATES
1898 OSString
* wakeType
= OSDynamicCast(
1899 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
1900 if (wakeType
&& wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
1902 updateRunState(kRStateMaintenance
);
1903 wranglerTickled
= false;
1906 #endif /* ROOT_DOMAIN_RUN_STATES */
1908 updateRunState(kRStateNormal
);
1911 #else /* !__i386__ && !__x86_64__ */
1912 // stay awake for at least 30 seconds
1913 startIdleSleepTimer(30);
1917 changePowerStateToPriv(ON_STATE
);
1919 updateRunState(kRStateNormal
);
1921 // allow us to step up a power state
1922 patriarch
->sleepToDoze();
1924 // ignore children's request for higher power during doze.
1925 changePowerStateWithOverrideTo(DOZE_STATE
);
1930 if ( previousState
!= DOZE_STATE
)
1932 LOG("System Doze\n");
1934 // re-enable this timer for next sleep
1935 cancelIdleSleepTimer();
1936 gSleepOrShutdownPending
= 0;
1938 // Invalidate prior activity tickles to allow wake from doze.
1939 if (wrangler
) wrangler
->changePowerStateTo(0);
1942 #if ROOT_DOMAIN_RUN_STATES
1944 // SLEEP -> ON (Maintenance)
1945 // Go back to sleep, unless cancelled by a HID event.
1947 if ((previousState
== SLEEP_STATE
) &&
1948 (runStateIndex
== kRStateMaintenance
) &&
1951 setProperty(kRootDomainSleepReasonKey
, kIOPMMaintenanceSleepKey
);
1952 changePowerStateWithOverrideTo(SLEEP_STATE
);
1955 // ON -> ON triggered by R-state changes.
1957 if ((previousState
== ON_STATE
) &&
1958 (runStateIndex
!= nextRunStateIndex
) &&
1959 (nextRunStateIndex
< kRStateCount
))
1961 LOG("R-state changed %u->%u\n",
1962 runStateIndex
, nextRunStateIndex
);
1963 updateRunState(nextRunStateIndex
);
1965 DLOG("kIOMessageSystemHasPoweredOn (%u)\n",
1966 gMessageClientType
);
1967 tellClients(kIOMessageSystemHasPoweredOn
, clientMessageFilter
);
1971 #endif /* ROOT_DOMAIN_RUN_STATES */
1976 //******************************************************************************
1979 // The Display Wrangler calls here when it switches to its highest state.
1980 // If the system is currently dozing, allow it to wake by making sure the
1981 // parent is providing power.
1982 //******************************************************************************
1984 void IOPMrootDomain::wakeFromDoze( void )
1986 if ( getPowerState() == DOZE_STATE
)
1988 changePowerStateToPriv(ON_STATE
);
1989 patriarch
->wakeSystem();
1994 //******************************************************************************
1997 // Adds a new feature to the supported features dictionary
1998 //******************************************************************************
2000 void IOPMrootDomain::publishFeature( const char * feature
)
2002 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
2006 //******************************************************************************
2007 // publishFeature (with supported power source specified)
2009 // Adds a new feature to the supported features dictionary
2010 //******************************************************************************
2012 void IOPMrootDomain::publishFeature(
2013 const char *feature
,
2014 uint32_t supportedWhere
,
2015 uint32_t *uniqueFeatureID
)
2017 static uint16_t next_feature_id
= 500;
2019 OSNumber
*new_feature_data
= NULL
;
2020 OSNumber
*existing_feature
= NULL
;
2021 OSArray
*existing_feature_arr
= NULL
;
2022 OSObject
*osObj
= NULL
;
2023 uint32_t feature_value
= 0;
2025 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
2027 if(!supportedWhere
) {
2028 // Feature isn't supported anywhere!
2032 if(next_feature_id
> 5000) {
2033 // Far, far too many features!
2037 if(featuresDictLock
) IOLockLock(featuresDictLock
);
2039 OSDictionary
*features
=
2040 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
2042 // Create new features dict if necessary
2043 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
2044 features
= OSDictionary::withDictionary(features
);
2046 features
= OSDictionary::withCapacity(1);
2049 // Create OSNumber to track new feature
2051 next_feature_id
+= 1;
2052 if( uniqueFeatureID
) {
2053 // We don't really mind if the calling kext didn't give us a place
2054 // to stash their unique id. Many kexts don't plan to unload, and thus
2055 // have no need to remove themselves later.
2056 *uniqueFeatureID
= next_feature_id
;
2059 feature_value
= (uint32_t)next_feature_id
;
2060 feature_value
<<= 16;
2061 feature_value
+= supportedWhere
;
2063 new_feature_data
= OSNumber::withNumber(
2064 (unsigned long long)feature_value
, 32);
2066 // Does features object already exist?
2067 if( (osObj
= features
->getObject(feature
)) )
2069 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
2071 // We need to create an OSArray to hold the now 2 elements.
2072 existing_feature_arr
= OSArray::withObjects(
2073 (const OSObject
**)&existing_feature
, 1, 2);
2074 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
2076 // Add object to existing array
2077 existing_feature_arr
= OSArray::withArray(
2078 existing_feature_arr
,
2079 existing_feature_arr
->getCount() + 1);
2082 if (existing_feature_arr
)
2084 existing_feature_arr
->setObject(new_feature_data
);
2085 features
->setObject(feature
, existing_feature_arr
);
2086 existing_feature_arr
->release();
2087 existing_feature_arr
= 0;
2090 // The easy case: no previously existing features listed. We simply
2091 // set the OSNumber at key 'feature' and we're on our way.
2092 features
->setObject(feature
, new_feature_data
);
2095 new_feature_data
->release();
2097 setProperty(kRootDomainSupportedFeatures
, features
);
2099 features
->release();
2101 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
2103 // Notify EnergySaver and all those in user space so they might
2104 // re-populate their feature specific UI
2105 if(pmPowerStateQueue
) {
2106 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
2111 //******************************************************************************
2112 // removePublishedFeature
2114 // Removes previously published feature
2115 //******************************************************************************
2117 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
2119 IOReturn ret
= kIOReturnError
;
2120 uint32_t feature_value
= 0;
2121 uint16_t feature_id
= 0;
2122 bool madeAChange
= false;
2124 OSSymbol
*dictKey
= NULL
;
2125 OSCollectionIterator
*dictIterator
= NULL
;
2126 OSArray
*arrayMember
= NULL
;
2127 OSNumber
*numberMember
= NULL
;
2128 OSObject
*osObj
= NULL
;
2129 OSNumber
*osNum
= NULL
;
2130 OSArray
*arrayMemberCopy
;
2132 if(featuresDictLock
) IOLockLock(featuresDictLock
);
2134 OSDictionary
*features
=
2135 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
2137 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
2139 // Any modifications to the dictionary are made to the copy to prevent
2140 // races & crashes with userland clients. Dictionary updated
2141 // automically later.
2142 features
= OSDictionary::withDictionary(features
);
2145 ret
= kIOReturnNotFound
;
2149 // We iterate 'features' dictionary looking for an entry tagged
2150 // with 'removeFeatureID'. If found, we remove it from our tracking
2151 // structures and notify the OS via a general interest message.
2153 dictIterator
= OSCollectionIterator::withCollection(features
);
2158 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
2160 osObj
= features
->getObject(dictKey
);
2162 // Each Feature is either tracked by an OSNumber
2163 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
2165 feature_value
= numberMember
->unsigned32BitValue();
2166 feature_id
= (uint16_t)(feature_value
>> 16);
2168 if( feature_id
== (uint16_t)removeFeatureID
)
2171 features
->removeObject(dictKey
);
2176 // Or tracked by an OSArray of OSNumbers
2177 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
2179 unsigned int arrayCount
= arrayMember
->getCount();
2181 for(unsigned int i
=0; i
<arrayCount
; i
++)
2183 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
2188 feature_value
= osNum
->unsigned32BitValue();
2189 feature_id
= (uint16_t)(feature_value
>> 16);
2191 if( feature_id
== (uint16_t)removeFeatureID
)
2194 if( 1 == arrayCount
) {
2195 // If the array only contains one element, remove
2197 features
->removeObject(dictKey
);
2199 // Otherwise remove the element from a copy of the array.
2200 arrayMemberCopy
= OSArray::withArray(arrayMember
);
2201 if (arrayMemberCopy
)
2203 arrayMemberCopy
->removeObject(i
);
2204 features
->setObject(dictKey
, arrayMemberCopy
);
2205 arrayMemberCopy
->release();
2216 dictIterator
->release();
2220 ret
= kIOReturnSuccess
;
2222 setProperty(kRootDomainSupportedFeatures
, features
);
2224 // Notify EnergySaver and all those in user space so they might
2225 // re-populate their feature specific UI
2226 if(pmPowerStateQueue
) {
2227 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
2230 ret
= kIOReturnNotFound
;
2234 if(features
) features
->release();
2235 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
2240 //******************************************************************************
2241 // announcePowerSourceChange
2243 // Notifies "interested parties" that the battery state has changed
2244 //******************************************************************************
2246 void IOPMrootDomain::announcePowerSourceChange( void )
2249 IORegistryEntry
*_batteryRegEntry
= (IORegistryEntry
*) getProperty("BatteryEntry");
2251 // (if possible) re-publish power source state under IOPMrootDomain;
2252 // only do so if the battery controller publishes an IOResource
2253 // defining battery location. Called from ApplePMU battery driver.
2255 if(_batteryRegEntry
)
2258 batt_info
= (OSArray
*) _batteryRegEntry
->getProperty(kIOBatteryInfoKey
);
2260 setProperty(kIOBatteryInfoKey
, batt_info
);
2266 //******************************************************************************
2267 // setPMSetting (private)
2269 // Internal helper to relay PM settings changes from user space to individual
2270 // drivers. Should be called only by IOPMrootDomain::setProperties.
2271 //******************************************************************************
2273 IOReturn
IOPMrootDomain::setPMSetting(
2274 const OSSymbol
*type
,
2277 OSArray
*arr
= NULL
;
2278 PMSettingObject
*p_obj
= NULL
;
2282 if(NULL
== type
) return kIOReturnBadArgument
;
2284 IORecursiveLockLock(settingsCtrlLock
);
2286 fPMSettingsDict
->setObject(type
, obj
);
2288 arr
= (OSArray
*)settingsCallbacks
->getObject(type
);
2289 if(NULL
== arr
) goto exit
;
2290 count
= arr
->getCount();
2291 for(i
=0; i
<count
; i
++) {
2292 p_obj
= (PMSettingObject
*)OSDynamicCast(PMSettingObject
, arr
->getObject(i
));
2293 if(p_obj
) p_obj
->setPMSetting(type
, obj
);
2297 IORecursiveLockUnlock(settingsCtrlLock
);
2298 return kIOReturnSuccess
;
2302 //******************************************************************************
2303 // copyPMSetting (public)
2305 // Allows kexts to safely read setting values, without being subscribed to
2307 //******************************************************************************
2309 OSObject
* IOPMrootDomain::copyPMSetting(
2310 OSSymbol
*whichSetting
)
2312 OSObject
*obj
= NULL
;
2314 if(!whichSetting
) return NULL
;
2316 IORecursiveLockLock(settingsCtrlLock
);
2317 obj
= fPMSettingsDict
->getObject(whichSetting
);
2321 IORecursiveLockUnlock(settingsCtrlLock
);
2327 //******************************************************************************
2328 // registerPMSettingController (public)
2330 // direct wrapper to registerPMSettingController with uint32_t power source arg
2331 //******************************************************************************
2333 IOReturn
IOPMrootDomain::registerPMSettingController(
2334 const OSSymbol
* settings
[],
2335 IOPMSettingControllerCallback func
,
2340 return registerPMSettingController(
2342 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
2343 func
, target
, refcon
, handle
);
2347 //******************************************************************************
2348 // registerPMSettingController (public)
2350 // Kexts may register for notifications when a particular setting is changed.
2351 // A list of settings is available in IOPM.h.
2353 // * settings - An OSArray containing OSSymbols. Caller should populate this
2354 // array with a list of settings caller wants notifications from.
2355 // * func - A C function callback of the type IOPMSettingControllerCallback
2356 // * target - caller may provide an OSObject *, which PM will pass as an
2357 // target to calls to "func"
2358 // * refcon - caller may provide an void *, which PM will pass as an
2359 // argument to calls to "func"
2360 // * handle - This is a return argument. We will populate this pointer upon
2361 // call success. Hold onto this and pass this argument to
2362 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
2364 // kIOReturnSuccess on success
2365 //******************************************************************************
2367 IOReturn
IOPMrootDomain::registerPMSettingController(
2368 const OSSymbol
* settings
[],
2369 uint32_t supportedPowerSources
,
2370 IOPMSettingControllerCallback func
,
2375 PMSettingObject
*pmso
= NULL
;
2376 OSArray
*list
= NULL
;
2377 IOReturn ret
= kIOReturnSuccess
;
2380 if( NULL
== settings
||
2384 return kIOReturnBadArgument
;
2387 pmso
= PMSettingObject::pmSettingObject(
2388 (IOPMrootDomain
*)this, func
, target
,
2389 refcon
, supportedPowerSources
, settings
);
2392 ret
= kIOReturnInternalError
;
2393 goto bail_no_unlock
;
2396 IORecursiveLockLock(settingsCtrlLock
);
2397 for(i
=0; settings
[i
]; i
++)
2399 list
= (OSArray
*)settingsCallbacks
->getObject(settings
[i
]);
2401 // New array of callbacks for this setting
2402 list
= OSArray::withCapacity(1);
2403 settingsCallbacks
->setObject(settings
[i
], list
);
2407 // Add caller to the callback list
2408 list
->setObject(pmso
);
2411 IORecursiveLockUnlock(settingsCtrlLock
);
2413 ret
= kIOReturnSuccess
;
2415 // Track this instance by its OSData ptr from now on
2419 if(kIOReturnSuccess
!= ret
)
2421 // Error return case
2422 if(pmso
) pmso
->release();
2423 if(handle
) *handle
= NULL
;
2429 //******************************************************************************
2430 // sleepOnClamshellClosed
2432 // contains the logic to determine if the system should sleep when the clamshell
2434 //******************************************************************************
2436 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2438 DLOG("clamshell state %d, EX %d, IG %d, IW %d, DT %d, AC %d\n",
2439 clamshellIsClosed
, clamshellExists
, ignoringClamshell
,
2440 ignoringClamshellOnWake
, desktopMode
, acAdaptorConnected
);
2442 return ( !ignoringClamshell
2443 && !ignoringClamshellOnWake
2444 && !(desktopMode
&& acAdaptorConnected
) );
2447 void IOPMrootDomain::sendClientClamshellNotification( void )
2449 /* Only broadcast clamshell alert if clamshell exists. */
2450 if (!clamshellExists
)
2453 setProperty(kAppleClamshellStateKey
,
2454 clamshellIsClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
2456 setProperty(kAppleClamshellCausesSleepKey
,
2457 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
2459 /* Argument to message is a bitfiel of
2460 * ( kClamshellStateBit | kClamshellSleepBit )
2462 messageClients(kIOPMMessageClamshellStateChange
,
2463 (void *) ( (clamshellIsClosed
? kClamshellStateBit
: 0)
2464 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
2468 //******************************************************************************
2469 // informCPUStateChange
2471 // Call into PM CPU code so that CPU power savings may dynamically adjust for
2472 // running on battery, with the lid closed, etc.
2474 // informCPUStateChange is a no-op on non x86 systems
2475 // only x86 has explicit support in the IntelCPUPowerManagement kext
2476 //******************************************************************************
2478 void IOPMrootDomain::informCPUStateChange(
2482 #if defined(__i386__) || defined(__x86_64__)
2484 pmioctlVariableInfo_t varInfoStruct
;
2486 const char *varNameStr
= NULL
;
2487 int32_t *varIndex
= NULL
;
2489 if (kInformAC
== type
) {
2490 varNameStr
= kIOPMRootDomainBatPowerCString
;
2491 varIndex
= &idxPMCPULimitedPower
;
2492 } else if (kInformLid
== type
) {
2493 varNameStr
= kIOPMRootDomainLidCloseCString
;
2494 varIndex
= &idxPMCPUClamshell
;
2499 // Set the new value!
2500 // pmCPUControl will assign us a new ID if one doesn't exist yet
2501 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
2502 varInfoStruct
.varID
= *varIndex
;
2503 varInfoStruct
.varType
= vBool
;
2504 varInfoStruct
.varInitValue
= value
;
2505 varInfoStruct
.varCurValue
= value
;
2506 strncpy( (char *)varInfoStruct
.varName
,
2507 (const char *)varNameStr
,
2508 strlen(varNameStr
) + 1 );
2511 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
2513 // pmCPU only assigns numerical id's when a new varName is specified
2515 && (*varIndex
== kCPUUnknownIndex
))
2517 // pmCPUControl has assigned us a new variable ID.
2518 // Let's re-read the structure we just SET to learn that ID.
2519 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
2523 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
2524 *varIndex
= varInfoStruct
.varID
;
2530 #endif /* __i386__ || __x86_64__ */
2534 //******************************************************************************
2535 // dispatchPowerEvent
2537 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
2538 //******************************************************************************
2540 void IOPMrootDomain::dispatchPowerEvent(
2541 uint32_t event
, void * arg0
, void * arg1
)
2543 DLOG("power event %x args %p %p\n", event
, arg0
, arg1
);
2548 case kPowerEventFeatureChanged
:
2549 messageClients(kIOPMMessageFeatureChange
, this);
2552 case kPowerEventReceivedPowerNotification
:
2553 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
2556 case kPowerEventSystemBootCompleted
:
2559 systemBooting
= false;
2562 // If lid is closed, re-send lid closed notification
2563 // now that booting is complete.
2564 if( clamshellIsClosed
)
2566 handlePowerNotification(kLocalEvalClamshellCommand
);
2571 case kPowerEventSystemShutdown
:
2572 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
2574 /* We set systemShutdown = true during shutdown
2575 to prevent sleep at unexpected times while loginwindow is trying
2576 to shutdown apps and while the OS is trying to transition to
2579 Set to true during shutdown, as soon as loginwindow shows
2580 the "shutdown countdown dialog", through individual app
2581 termination, and through black screen kernel shutdown.
2583 LOG("systemShutdown true\n");
2584 systemShutdown
= true;
2587 A shutdown was initiated, but then the shutdown
2588 was cancelled, clearing systemShutdown to false here.
2590 LOG("systemShutdown false\n");
2591 systemShutdown
= false;
2595 case kPowerEventUserDisabledSleep
:
2596 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
2599 #if ROOT_DOMAIN_RUN_STATES
2600 case kPowerEventConfigdRegisteredInterest
:
2601 if (gConfigdNotifier
)
2603 gConfigdNotifier
->release();
2604 gConfigdNotifier
= 0;
2608 gConfigdNotifier
= (IONotifier
*) arg0
;
2613 case kPowerEventAggressivenessChanged
:
2614 aggressivenessChanged();
2620 //******************************************************************************
2621 // systemPowerEventOccurred
2623 // The power controller is notifying us of a hardware-related power management
2624 // event that we must handle.
2626 // systemPowerEventOccurred covers the same functionality that
2627 // receivePowerNotification does; it simply provides a richer API for conveying
2628 // more information.
2629 //******************************************************************************
2631 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
2632 const OSSymbol
*event
,
2635 IOReturn attempt
= kIOReturnSuccess
;
2636 OSNumber
*newNumber
= NULL
;
2639 return kIOReturnBadArgument
;
2641 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
2643 return kIOReturnInternalError
;
2645 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
2647 newNumber
->release();
2652 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
2653 const OSSymbol
*event
,
2656 OSDictionary
*thermalsDict
= NULL
;
2657 bool shouldUpdate
= true;
2659 if (!event
|| !value
)
2660 return kIOReturnBadArgument
;
2663 // We reuse featuresDict Lock because it already exists and guards
2664 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
2665 // of stepping on that lock.
2666 if (featuresDictLock
) IOLockLock(featuresDictLock
);
2668 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
2670 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
2671 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
2673 thermalsDict
= OSDictionary::withCapacity(1);
2676 if (!thermalsDict
) {
2677 shouldUpdate
= false;
2681 thermalsDict
->setObject (event
, value
);
2683 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
2685 thermalsDict
->release();
2689 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
2692 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
2694 return kIOReturnSuccess
;
2698 //******************************************************************************
2699 // receivePowerNotification
2701 // The power controller is notifying us of a hardware-related power management
2702 // event that we must handle. This may be a result of an 'environment' interrupt
2703 // from the power mgt micro.
2704 //******************************************************************************
2706 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
2708 pmPowerStateQueue
->submitPowerEvent(
2709 kPowerEventReceivedPowerNotification
, (void *) msg
);
2710 return kIOReturnSuccess
;
2713 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
2715 bool eval_clamshell
= false;
2720 * Local (IOPMrootDomain only) eval clamshell command
2722 if (msg
& kLocalEvalClamshellCommand
)
2724 eval_clamshell
= true;
2730 if (msg
& kIOPMOverTemp
)
2732 LOG("PowerManagement emergency overtemp signal. Going to sleep!");
2733 privateSleepSystem (kIOPMThermalEmergencySleepKey
);
2738 * PMU Processor Speed Change
2740 if (msg
& kIOPMProcessorSpeedChange
)
2742 IOService
*pmu
= waitForService(serviceMatching("ApplePMU"));
2743 pmu
->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
2744 getPlatform()->sleepKernel();
2745 pmu
->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
2752 if (msg
& kIOPMSleepNow
)
2754 privateSleepSystem (kIOPMSoftwareSleepKey
);
2760 if (msg
& kIOPMPowerEmergency
)
2762 privateSleepSystem (kIOPMLowPowerSleepKey
);
2768 if (msg
& kIOPMClamshellOpened
)
2770 // Received clamshel open message from clamshell controlling driver
2771 // Update our internal state and tell general interest clients
2772 clamshellIsClosed
= false;
2773 clamshellExists
= true;
2776 informCPUStateChange(kInformLid
, 0);
2778 // Tell general interest clients
2779 sendClientClamshellNotification();
2784 * Send the clamshell interest notification since the lid is closing.
2786 if (msg
& kIOPMClamshellClosed
)
2788 // Received clamshel open message from clamshell controlling driver
2789 // Update our internal state and tell general interest clients
2790 clamshellIsClosed
= true;
2791 clamshellExists
= true;
2794 informCPUStateChange(kInformLid
, 1);
2796 // Tell general interest clients
2797 sendClientClamshellNotification();
2799 // And set eval_clamshell = so we can attempt
2800 eval_clamshell
= true;
2804 * Set Desktop mode (sent from graphics)
2806 * -> reevaluate lid state
2808 if (msg
& kIOPMSetDesktopMode
)
2810 desktopMode
= (0 != (msg
& kIOPMSetValue
));
2811 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
2813 sendClientClamshellNotification();
2815 // Re-evaluate the lid state
2816 if( clamshellIsClosed
)
2818 eval_clamshell
= true;
2823 * AC Adaptor connected
2825 * -> reevaluate lid state
2827 if (msg
& kIOPMSetACAdaptorConnected
)
2829 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
2830 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
2833 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
2835 // Tell BSD if AC is connected
2836 // 0 == external power source; 1 == on battery
2837 post_sys_powersource(acAdaptorConnected
? 0:1);
2839 sendClientClamshellNotification();
2841 // Re-evaluate the lid state
2842 if( clamshellIsClosed
)
2844 eval_clamshell
= true;
2849 * Enable Clamshell (external display disappear)
2851 * -> reevaluate lid state
2853 if (msg
& kIOPMEnableClamshell
)
2855 // Re-evaluate the lid state
2856 // System should sleep on external display disappearance
2857 // in lid closed operation.
2858 if( clamshellIsClosed
&& (true == ignoringClamshell
) )
2860 eval_clamshell
= true;
2863 ignoringClamshell
= false;
2865 sendClientClamshellNotification();
2869 * Disable Clamshell (external display appeared)
2870 * We don't bother re-evaluating clamshell state. If the system is awake,
2871 * the lid is probably open.
2873 if (msg
& kIOPMDisableClamshell
)
2875 ignoringClamshell
= true;
2877 sendClientClamshellNotification();
2881 * Evaluate clamshell and SLEEP if appropiate
2883 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
2888 privateSleepSystem (kIOPMClamshellSleepKey
);
2894 if (msg
& kIOPMPowerButton
)
2896 // toggle state of sleep/wake
2898 if ( getPowerState() == DOZE_STATE
)
2901 // yes, tell the tree we're waking
2904 // wake the Display Wrangler
2908 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
2909 // Check that power button sleep is enabled
2911 if( kOSBooleanTrue
!= getProperty(pbs
))
2912 privateSleepSystem (kIOPMPowerButtonSleepKey
);
2921 if ( (msg
& kIOPMAllowSleep
) && !allowSleep
)
2931 if (msg
& kIOPMPreventSleep
) {
2934 if ( getPowerState() == DOZE_STATE
) {
2936 // yes, tell the tree we're waking
2940 // wake the Display Wrangler
2944 // make sure we have power to clamp
2945 patriarch
->wakeSystem();
2951 //******************************************************************************
2952 // getSleepSupported
2954 //******************************************************************************
2956 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
2958 return( platformSleepSupport
);
2962 //******************************************************************************
2963 // setSleepSupported
2965 //******************************************************************************
2967 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
2969 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
2970 OSBitOrAtomic(flags
, &platformSleepSupport
);
2974 //******************************************************************************
2975 // requestPowerDomainState
2977 // The root domain intercepts this call to the superclass.
2978 // Called on the PM work loop thread.
2980 // If the clamp bit is not set in the desire, then the child doesn't need the power
2981 // state it's requesting; it just wants it. The root ignores desires but not needs.
2982 // If the clamp bit is not set, the root takes it that the child can tolerate no
2983 // power and interprets the request accordingly. If all children can thus tolerate
2984 // no power, we are on our way to idle sleep.
2985 //******************************************************************************
2987 IOReturn
IOPMrootDomain::requestPowerDomainState (
2988 IOPMPowerFlags desiredFlags
,
2989 IOPowerConnection
* whichChild
,
2990 unsigned long specification
)
2994 IOPowerConnection
*connection
;
2995 IOPMPowerFlags powerRequestFlag
= 0;
2996 IOPMPowerFlags editedDesire
;
3000 if (kIOLogPMRootDomain
& gIOKitDebug
)
3002 IOService
* powerChild
=
3003 (IOService
*) whichChild
->getChildEntry(gIOPowerPlane
);
3004 DLOG("child %p, flags %lx, spec %lx - %s\n",
3005 powerChild
, desiredFlags
, specification
,
3006 powerChild
? powerChild
->getName() : "?");
3009 // Force the child's input power requirements to 0 unless the prevent
3010 // idle-sleep flag is set. No input power flags map to our state 0.
3011 // Our power clamp (deviceDesire) keeps the minimum power state at 2.
3013 if (desiredFlags
& kIOPMPreventIdleSleep
)
3014 editedDesire
= kIOPMPreventIdleSleep
| kIOPMPowerOn
;
3018 // Recompute sleep supported flag (doze if not supported)
3019 sleepIsSupported
= true;
3021 iter
= getChildIterator(gIOPowerPlane
);
3024 while ( (next
= iter
->getNextObject()) )
3026 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
3028 // Ignore child that are in the process of joining.
3029 if (connection
->getReadyFlag() == false)
3032 // Is this connection attached to the child that called
3033 // requestPowerDomainState()?
3035 if (connection
== whichChild
)
3037 // OR in the child's input power requirements.
3038 powerRequestFlag
|= editedDesire
;
3040 if ( desiredFlags
& kIOPMPreventSystemSleep
)
3041 sleepIsSupported
= false;
3045 if (kIOLogPMRootDomain
& gIOKitDebug
)
3047 IOService
* powerChild
=
3048 (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
3049 DLOG("child %p, state %ld, noIdle %d, noSleep %d - %s\n",
3051 connection
->getDesiredDomainState(),
3052 connection
->getPreventIdleSleepFlag(),
3053 connection
->getPreventSystemSleepFlag(),
3054 powerChild
? powerChild
->getName() : "?");
3057 // OR in the child's desired power state (0 or ON_STATE).
3058 powerRequestFlag
|= connection
->getDesiredDomainState();
3060 if ( connection
->getPreventSystemSleepFlag() )
3061 sleepIsSupported
= false;
3068 DLOG("childPowerFlags 0x%lx, extraSleepDelay %ld\n",
3069 powerRequestFlag
, extraSleepDelay
);
3071 if ( !powerRequestFlag
&& !systemBooting
)
3076 changePowerStateToPriv(ON_STATE
);
3079 // stay awake for at least idleSeconds
3080 startIdleSleepTimer(idleSeconds
);
3083 else if (!extraSleepDelay
&& !idleSleepTimerPending
)
3089 // Drop our power clamp to SLEEP_STATE when all children became idle,
3090 // and the system sleep and display sleep values are equal.
3094 // If our power clamp has already dropped to SLEEP_STATE, and no child
3095 // is keeping us at ON_STATE, then this will trigger idle sleep.
3097 editedDesire
|= (desiredFlags
& kIOPMPreventSystemSleep
);
3099 return super::requestPowerDomainState(
3100 editedDesire
, whichChild
, specification
);
3104 //******************************************************************************
3105 // handlePlatformHaltRestart
3107 //******************************************************************************
3109 struct HaltRestartApplierContext
{
3110 IOPMrootDomain
* RootDomain
;
3111 unsigned long PowerState
;
3112 IOPMPowerFlags PowerFlags
;
3118 platformHaltRestartApplier( OSObject
* object
, void * context
)
3120 IOPowerStateChangeNotification notify
;
3121 HaltRestartApplierContext
* ctx
;
3122 AbsoluteTime startTime
;
3125 ctx
= (HaltRestartApplierContext
*) context
;
3127 memset(¬ify
, 0, sizeof(notify
));
3128 notify
.powerRef
= (void *)ctx
->Counter
;
3129 notify
.returnValue
= 0;
3130 notify
.stateNumber
= ctx
->PowerState
;
3131 notify
.stateFlags
= ctx
->PowerFlags
;
3133 clock_get_uptime(&startTime
);
3134 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
3135 deltaTime
= computeDeltaTimeMS(&startTime
);
3137 if ((deltaTime
> kPMHaltTimeoutMS
) || (gIOKitDebug
& kIOLogDebugPower
))
3139 _IOServiceInterestNotifier
* notifier
;
3140 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
3142 // IOService children of IOPMrootDomain are not instrumented.
3143 // Only IORootParent currently falls under that group.
3147 KLOG("%s handler %p took %u ms\n",
3148 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ?
3149 "PowerOff" : "Restart",
3150 notifier
->handler
, (uint32_t) deltaTime
);
3157 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
3159 HaltRestartApplierContext ctx
;
3160 AbsoluteTime startTime
;
3163 memset(&ctx
, 0, sizeof(ctx
));
3164 ctx
.RootDomain
= this;
3166 clock_get_uptime(&startTime
);
3170 case kPEUPSDelayHaltCPU
:
3171 ctx
.PowerState
= OFF_STATE
;
3172 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
3176 ctx
.PowerState
= RESTART_STATE
;
3177 ctx
.MessageType
= kIOMessageSystemWillRestart
;
3184 // Notify legacy clients
3185 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
3187 // For UPS shutdown leave File Server Mode intact, otherwise turn it off.
3188 if (kPEUPSDelayHaltCPU
!= pe_type
)
3190 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
3191 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
3194 setPMSetting(setting
, num
);
3200 // Notify in power tree order
3201 notifySystemShutdown(this, ctx
.MessageType
);
3203 deltaTime
= computeDeltaTimeMS(&startTime
);
3204 KLOG("%s all drivers took %u ms\n",
3205 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ?
3206 "PowerOff" : "Restart",
3207 (uint32_t) deltaTime
);
3211 //******************************************************************************
3214 //******************************************************************************
3216 IONotifier
* IOPMrootDomain::registerInterest(
3217 const OSSymbol
* typeOfInterest
,
3218 IOServiceInterestHandler handler
,
3219 void * target
, void * ref
)
3221 IONotifier
* notifier
;
3224 isConfigd
= typeOfInterest
&&
3225 typeOfInterest
->isEqualTo(kIOPMPrivilegedPowerInterest
);
3228 typeOfInterest
= gIOAppPowerStateInterest
;
3230 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
3232 #if ROOT_DOMAIN_RUN_STATES
3233 if (isConfigd
&& notifier
&& pmPowerStateQueue
)
3236 if (pmPowerStateQueue
->submitPowerEvent(
3237 kPowerEventConfigdRegisteredInterest
, notifier
) == false)
3238 notifier
->release();
3245 static bool clientMessageFilter( OSObject
* object
, void * arg
)
3247 #if ROOT_DOMAIN_RUN_STATES
3248 #if LOG_INTEREST_CLIENTS
3249 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
3253 switch (gMessageClientType
)
3255 case kMessageClientNone
:
3259 case kMessageClientAll
:
3263 case kMessageClientConfigd
:
3264 allow
= ((object
== (OSObject
*) gConfigdNotifier
) ||
3265 (object
== (OSObject
*) gSysPowerDownNotifier
));
3269 #if LOG_INTEREST_CLIENTS
3271 DLOG("system message %x to %p\n",
3272 context
->msgType
, object
);
3282 //******************************************************************************
3285 // We override the superclass implementation so we can send a different message
3286 // type to the client or application being notified.
3287 //******************************************************************************
3289 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
3293 DLOG("tellChangeDown %u->%u, R-state %u\n",
3294 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3296 switch ( stateNum
) {
3300 if (!ignoreChangeDown
)
3302 // Direct callout into OSKext so it can disable kext unloads
3303 // during sleep/wake to prevent deadlocks.
3304 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
3306 if ( (SLEEP_STATE
== stateNum
) && sleepSupportedPEFunction
)
3308 // Reset PCI prevent sleep flag before calling platform driver.
3309 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
3311 // Skip PCI check for maintenance sleep.
3312 if ((runStateFlags
& kRStateFlagSuppressPCICheck
) == 0)
3314 // Determine if the machine supports sleep, or must doze.
3315 getPlatform()->callPlatformFunction(
3316 sleepSupportedPEFunction
, false,
3317 NULL
, NULL
, NULL
, NULL
);
3320 // If the machine only supports doze, the callPlatformFunction call
3321 // boils down to IOPMrootDomain::setSleepSupported(kPCICantSleep),
3322 // otherwise nothing.
3325 // Update canSleep and kIOSleepSupportedKey property so drivers
3326 // can tell if platform is going to sleep versus doze.
3333 if (!sleepIsSupported
)
3335 if (platformSleepSupport
& kPCICantSleep
)
3337 setProperty(kIOSleepSupportedKey
, canSleep
);
3338 DLOG("canSleep %d\n", canSleep
);
3340 // Publish the new sleep-wake UUID
3341 publishSleepWakeUUID(true);
3343 // Two change downs are sent by IOServicePM. Ignore the 2nd.
3344 ignoreChangeDown
= true;
3346 tracePoint( kIOPMTracePointSystemSleepAppsPhase
);
3349 DLOG("kIOMessageSystemWillSleep (%d)\n", gMessageClientType
);
3350 done
= super::tellClientsWithResponse(
3351 kIOMessageSystemWillSleep
, clientMessageFilter
);
3355 done
= super::tellChangeDown(stateNum
);
3362 //******************************************************************************
3365 // We override the superclass implementation so we can send a different message
3366 // type to the client or application being notified.
3368 // This must be idle sleep since we don't ask during any other power change.
3369 //******************************************************************************
3371 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
3373 DLOG("askChangeDown %u->%u, R-state %u\n",
3374 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3375 DLOG("kIOMessageCanSystemSleep (%d)\n", gMessageClientType
);
3377 return super::tellClientsWithResponse(
3378 kIOMessageCanSystemSleep
,
3379 clientMessageFilter
);
3383 //******************************************************************************
3386 // Notify registered applications and kernel clients that we are not dropping
3389 // We override the superclass implementation so we can send a different message
3390 // type to the client or application being notified.
3392 // This must be a vetoed idle sleep, since no other power change can be vetoed.
3393 //******************************************************************************
3395 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
3397 DLOG("tellNoChangeDown %u->%u, R-state %u\n",
3398 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3400 // Sleep canceled, clear the sleep trace point.
3401 tracePoint(kIOPMTracePointSystemUp
);
3403 if (idleSeconds
&& !wrangler
)
3405 // stay awake for at least idleSeconds
3407 startIdleSleepTimer(idleSeconds
);
3409 DLOG("kIOMessageSystemWillNotSleep (%d)\n", gMessageClientType
);
3410 return tellClients(kIOMessageSystemWillNotSleep
, clientMessageFilter
);
3414 //******************************************************************************
3417 // Notify registered applications and kernel clients that we are raising power.
3419 // We override the superclass implementation so we can send a different message
3420 // type to the client or application being notified.
3421 //******************************************************************************
3423 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
3425 OSData
*publishPMStats
= NULL
;
3427 DLOG("tellChangeUp %u->%u, R-state %u\n",
3428 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3430 ignoreChangeDown
= false;
3432 if ( stateNum
== ON_STATE
)
3434 // Direct callout into OSKext so it can disable kext unloads
3435 // during sleep/wake to prevent deadlocks.
3436 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
3438 if (getPowerState() == ON_STATE
)
3440 // this is a quick wake from aborted sleep
3441 if (idleSeconds
&& !wrangler
)
3443 // stay awake for at least idleSeconds
3445 startIdleSleepTimer(idleSeconds
);
3447 DLOG("kIOMessageSystemWillPowerOn (%d)\n", gMessageClientType
);
3448 tellClients(kIOMessageSystemWillPowerOn
, clientMessageFilter
);
3453 IOHibernateSystemPostWake();
3457 tracePoint(kIOPMTracePointSystemWakeAppsPhase
);
3458 publishPMStats
= OSData::withBytes(&pmStats
, sizeof(pmStats
));
3459 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
3460 publishPMStats
->release();
3461 bzero(&pmStats
, sizeof(pmStats
));
3463 if (pmStatsAppResponses
)
3465 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
3466 pmStatsAppResponses
->release();
3467 pmStatsAppResponses
= OSArray::withCapacity(5);
3470 DLOG("kIOMessageSystemHasPoweredOn (%d)\n", gMessageClientType
);
3471 tellClients(kIOMessageSystemHasPoweredOn
, clientMessageFilter
);
3473 tracePoint(kIOPMTracePointSystemUp
);
3478 //******************************************************************************
3481 //******************************************************************************
3483 void IOPMrootDomain::reportUserInput( void )
3490 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
3493 wrangler
= (IOService
*) iter
->getNextObject();
3499 wrangler
->activityTickle(0,0);
3504 //******************************************************************************
3505 // setQuickSpinDownTimeout
3507 //******************************************************************************
3509 void IOPMrootDomain::setQuickSpinDownTimeout( void )
3513 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
3517 //******************************************************************************
3518 // restoreUserSpinDownTimeout
3520 //******************************************************************************
3522 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
3526 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
3530 //******************************************************************************
3531 // changePowerStateTo & changePowerStateToPriv
3533 // Override of these methods for logging purposes.
3534 //******************************************************************************
3536 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3538 return kIOReturnUnsupported
; // ignored
3541 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3543 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3545 if ( (getPowerState() == DOZE_STATE
) && (ordinal
!= ON_STATE
) )
3547 return kIOReturnSuccess
;
3550 if ( (userDisabledAllSleep
|| systemBooting
|| systemShutdown
) &&
3551 (ordinal
== SLEEP_STATE
) )
3553 DLOG("SLEEP rejected, forced to ON state (UD %d, SB %d, SS %d)\n",
3554 userDisabledAllSleep
, systemBooting
, systemShutdown
);
3556 super::changePowerStateToPriv(ON_STATE
);
3559 return super::changePowerStateToPriv(ordinal
);
3563 //******************************************************************************
3566 //******************************************************************************
3568 void IOPMrootDomain::updateRunState( uint32_t inRunState
)
3570 #if ROOT_DOMAIN_RUN_STATES
3571 if (inRunState
< kRStateCount
)
3573 runStateIndex
= nextRunStateIndex
= inRunState
;
3574 runStateFlags
= gRStateFlags
[inRunState
];
3577 kIOPMRootDomainRunStateKey
,
3578 (unsigned long long) inRunState
, 32);
3584 #if ROOT_DOMAIN_RUN_STATES
3585 //******************************************************************************
3586 // tagPowerPlaneService
3588 // Running on PM work loop thread.
3589 //******************************************************************************
3591 void IOPMrootDomain::tagPowerPlaneService(
3592 IOService
* service
,
3593 uint32_t * rdFlags
)
3597 if (service
->getProperty("IOPMStrictTreeOrder") ||
3598 service
->metaCast("IODisplayWrangler") ||
3599 OSDynamicCast(OSNumber
,
3600 service
->getProperty("IOPMUnattendedWakePowerState")))
3602 *rdFlags
|= kServiceFlagGraphics
;
3603 DLOG("tagged device %s %x\n", service
->getName(), *rdFlags
);
3606 // Locate the first PCI host bridge.
3607 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
3609 IOService
* provider
= service
->getProvider();
3610 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
3611 provider
->inPlane(gIODTPlane
))
3613 pciHostBridgeDevice
= provider
;
3614 DLOG("PMTrace found PCI host bridge %s->%s\n",
3615 provider
->getName(), service
->getName());
3619 // Tag top-level PCI devices. The order of PMinit() call does not
3620 // change across boots and is used as the PCI bit number.
3621 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
3623 // Would prefer to check built-in property, but tagPowerPlaneService()
3624 // is called before pciDevice->registerService().
3625 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
3626 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
3628 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
3631 // Save the assigned bit for fast lookup.
3633 *rdFlags
|= (kServiceFlagTopLevelPCI
| (bit
<< 8));
3640 //******************************************************************************
3641 // handleActivityTickleForService
3643 // Called by IOService::activityTickle() for a tickle that is requesting the
3644 // service to raise power state. Called from driver thread.
3645 //******************************************************************************
3647 void IOPMrootDomain::handleActivityTickleForService( IOService
* service
)
3649 // Tickle directed to IODisplayWrangler while graphics is disabled.
3650 // Bring graphics online.
3652 if ((service
== wrangler
) &&
3653 (runStateIndex
> kRStateNormal
) &&
3654 (false == wranglerTickled
))
3656 DLOG("display wrangler tickled\n");
3657 wranglerTickled
= true;
3658 synchronizePowerTree();
3663 //******************************************************************************
3664 // handlePowerChangeStartForService
3666 // Running on PM work loop thread.
3667 //******************************************************************************
3669 void IOPMrootDomain::handlePowerChangeStartForService(
3670 IOService
* service
,
3672 uint32_t newPowerState
,
3673 uint32_t changeFlags
)
3675 if (service
== this)
3677 uint32_t currentPowerState
= (uint32_t) getPowerState();
3678 uint32_t nextRunStateFlags
;
3680 assert(nextRunStateIndex
< kRStateCount
);
3681 nextRunStateFlags
= gRStateFlags
[nextRunStateIndex
];
3683 gMessageClientType
= kMessageClientNone
;
3685 // Transition towards or away from ON power state.
3687 if ((currentPowerState
!= newPowerState
) &&
3688 ((ON_STATE
== newPowerState
) || (ON_STATE
== currentPowerState
)))
3690 if ((runStateFlags
& kRStateFlagSuppressMessages
) == 0)
3691 gMessageClientType
= kMessageClientAll
;
3693 gMessageClientType
= kMessageClientConfigd
;
3696 // Transition caused by deassertion of system notification suppression.
3698 if ((ON_STATE
== newPowerState
) &&
3699 (ON_STATE
== currentPowerState
) &&
3700 ((runStateFlags
^ nextRunStateFlags
) & kRStateFlagSuppressMessages
))
3702 gMessageClientType
= kMessageClientAll
;
3705 if (ON_STATE
== newPowerState
)
3707 DLOG("kIOMessageSystemWillPowerOn (%d)\n",
3708 gMessageClientType
);
3709 tellClients(kIOMessageSystemWillPowerOn
, clientMessageFilter
);
3713 if (*rdFlags
& kServiceFlagTopLevelPCI
)
3715 pmTracer
->tracePCIPowerChange(
3716 PMTraceWorker::kPowerChangeStart
,
3717 service
, changeFlags
,
3718 (*rdFlags
>> 8) & 0xff);
3723 //******************************************************************************
3724 // handlePowerChangeDoneForService
3726 // Running on PM work loop thread.
3727 //******************************************************************************
3729 void IOPMrootDomain::handlePowerChangeDoneForService(
3730 IOService
* service
,
3732 uint32_t newPowerState
,
3733 uint32_t changeFlags
)
3735 if (*rdFlags
& kServiceFlagTopLevelPCI
)
3737 pmTracer
->tracePCIPowerChange(
3738 PMTraceWorker::kPowerChangeCompleted
,
3739 service
, changeFlags
,
3740 (*rdFlags
>> 8) & 0xff);
3745 //******************************************************************************
3746 // overridePowerStateForService
3748 // Runs on PM work loop thread.
3749 //******************************************************************************
3751 void IOPMrootDomain::overridePowerStateForService(
3752 IOService
* service
,
3754 unsigned long * powerState
,
3755 uint32_t changeFlags
)
3757 uint32_t inPowerState
= (uint32_t) *powerState
;
3759 if ((service
== this) && (inPowerState
== ON_STATE
) &&
3760 (changeFlags
& kIOPMSynchronize
))
3762 DLOG("sync root domain %u->%u\n",
3763 (uint32_t) getPowerState(), inPowerState
);
3765 // Root Domain is in a reduced R-state, and a HID tickle has
3766 // requested a PM tree sync. Begin R-state transition.
3768 if (runStateIndex
!= kRStateNormal
)
3770 nextRunStateIndex
= kRStateNormal
;
3772 kIOPMRootDomainRunStateKey
,
3773 (unsigned long long) kRStateNormal
, 32);
3777 if (*rdFlags
& kServiceFlagGraphics
)
3779 DLOG("graphics device %s %u->%u (flags 0x%x)\n",
3780 service
->getName(), (uint32_t) service
->getPowerState(),
3781 inPowerState
, changeFlags
);
3783 if (inPowerState
== 0)
3785 // Graphics device is powering down, apply limit preventing
3786 // device from powering back up later unless we consent.
3788 if ((*rdFlags
& kServiceFlagNoPowerUp
) == 0)
3790 *rdFlags
|= kServiceFlagNoPowerUp
;
3791 DLOG("asserted power limit for %s\n",
3792 service
->getName());
3797 uint32_t nextRunStateFlags
;
3799 assert(nextRunStateIndex
< kRStateCount
);
3800 nextRunStateFlags
= gRStateFlags
[nextRunStateIndex
];
3802 // Graphics device is powering up. Release power limit at the
3803 // did-change machine state.
3805 if (changeFlags
& kIOPMSynchronize
)
3807 if ((runStateFlags
& kRStateFlagSuppressGraphics
) &&
3808 ((nextRunStateFlags
& kRStateFlagSuppressGraphics
) == 0) &&
3809 (changeFlags
& kIOPMDomainDidChange
))
3811 // Woke up without graphics power, but
3812 // HID event has tickled display wrangler.
3813 *rdFlags
&= ~kServiceFlagNoPowerUp
;
3814 DLOG("removed power limit for %s\n",
3815 service
->getName());
3818 else if ((runStateFlags
& kRStateFlagSuppressGraphics
) == 0)
3820 *rdFlags
&= ~kServiceFlagNoPowerUp
;
3823 if (*rdFlags
& kServiceFlagNoPowerUp
)
3825 DLOG("limited %s to power state 0\n",
3826 service
->getName());
3834 //******************************************************************************
3835 // setMaintenanceWakeCalendar
3837 //******************************************************************************
3839 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
3840 const IOPMCalendarStruct
* calendar
)
3846 return kIOReturnBadArgument
;
3848 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
3850 return kIOReturnNoMemory
;
3852 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
3857 #endif /* ROOT_DOMAIN_RUN_STATES */
3860 //******************************************************************************
3861 // sysPowerDownHandler
3863 // Receives a notification when the RootDomain changes state.
3865 // Allows us to take action on system sleep, power down, and restart after
3866 // applications have received their power change notifications and replied,
3867 // but before drivers have powered down. We perform a vfs sync on power down.
3868 //******************************************************************************
3870 IOReturn
IOPMrootDomain::sysPowerDownHandler( void * target
, void * refCon
,
3871 UInt32 messageType
, IOService
* service
,
3872 void * messageArgument
, vm_size_t argSize
)
3875 IOPowerStateChangeNotification
*params
= (IOPowerStateChangeNotification
*) messageArgument
;
3876 IOPMrootDomain
*rootDomain
= OSDynamicCast(IOPMrootDomain
, service
);
3878 DLOG("sysPowerDownHandler message %x\n", (uint32_t) messageType
);
3881 return kIOReturnUnsupported
;
3883 switch (messageType
) {
3884 case kIOMessageSystemWillSleep
:
3885 // Interested applications have been notified of an impending power
3886 // change and have acked (when applicable).
3887 // This is our chance to save whatever state we can before powering
3889 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3892 // We will ack within 20 seconds
3893 params
->returnValue
= 20 * 1000 * 1000;
3895 if (gIOHibernateState
)
3896 params
->returnValue
+= gIOHibernateFreeTime
* 1000; //add in time we could spend freeing pages
3899 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
3901 // Purposely delay the ack and hope that shutdown occurs quickly.
3902 // Another option is not to schedule the thread and wait for
3904 AbsoluteTime deadline
;
3905 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
3906 thread_call_enter1_delayed( rootDomain
->diskSyncCalloutEntry
,
3907 (thread_call_param_t
)params
->powerRef
,
3911 thread_call_enter1(rootDomain
->diskSyncCalloutEntry
, (thread_call_param_t
)params
->powerRef
);
3912 ret
= kIOReturnSuccess
;
3915 case kIOMessageSystemWillPowerOff
:
3916 case kIOMessageSystemWillRestart
:
3917 ret
= kIOReturnUnsupported
;
3921 ret
= kIOReturnUnsupported
;
3927 //******************************************************************************
3928 // publishSleepWakeUUID
3931 //******************************************************************************
3932 void IOPMrootDomain::publishSleepWakeUUID( bool shouldPublish
)
3936 if (queuedSleepWakeUUIDString
)
3938 if (OSCompareAndSwap(/*old*/ true, /*new*/ false, &gSleepWakeUUIDIsSet
))
3940 // Upon wake, it takes some time for userland to invalidate the
3941 // UUID. If another sleep is initiated during that period, force
3942 // a CLEAR message to balance the upcoming SET message.
3944 messageClients( kIOPMMessageSleepWakeUUIDChange
,
3945 kIOPMMessageSleepWakeUUIDCleared
);
3947 DLOG("SleepWake UUID forced clear\n");
3950 setProperty(kIOPMSleepWakeUUIDKey
, queuedSleepWakeUUIDString
);
3951 DLOG("SleepWake UUID published: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3952 queuedSleepWakeUUIDString
->release();
3953 queuedSleepWakeUUIDString
= NULL
;
3954 messageClients(kIOPMMessageSleepWakeUUIDChange
,
3955 kIOPMMessageSleepWakeUUIDSet
);
3958 if (OSCompareAndSwap(/*old*/ true, /*new*/ false, &gSleepWakeUUIDIsSet
))
3960 DLOG("SleepWake UUID cleared\n");
3961 removeProperty(kIOPMSleepWakeUUIDKey
);
3962 messageClients(kIOPMMessageSleepWakeUUIDChange
,
3963 kIOPMMessageSleepWakeUUIDCleared
);
3969 //******************************************************************************
3970 // displayWranglerNotification
3972 // Receives a notification when the IODisplayWrangler changes state.
3974 // Allows us to take action on display dim/undim.
3976 // When the display sleeps we:
3977 // - Start the idle sleep timer
3978 // - set the quick spin down timeout
3980 // On wake from display sleep:
3981 // - Cancel the idle sleep timer
3982 // - restore the user's chosen spindown timer from the "quick" spin down value
3983 //******************************************************************************
3985 IOReturn
IOPMrootDomain::displayWranglerNotification(
3986 void * target
, void * refCon
,
3987 UInt32 messageType
, IOService
* service
,
3988 void * messageArgument
, vm_size_t argSize
)
3991 int displayPowerState
;
3992 IOPowerStateChangeNotification
* params
=
3993 (IOPowerStateChangeNotification
*) messageArgument
;
3995 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
3996 (messageType
!= kIOMessageDeviceHasPoweredOn
))
3997 return kIOReturnUnsupported
;
4001 return kIOReturnUnsupported
;
4003 displayPowerState
= params
->stateNumber
;
4004 DLOG("DisplayWrangler message 0x%x, new power state %d\n",
4005 (uint32_t) messageType
, displayPowerState
);
4007 switch (messageType
) {
4008 case kIOMessageDeviceWillPowerOff
:
4010 // The display wrangler has dropped power because of idle display sleep
4011 // or force system sleep.
4016 // 1 Not visible to user
4017 // 0 Not visible to user
4019 if (gRootDomain
->wranglerAsleep
|| (displayPowerState
> 2))
4022 // Record the time the display wrangler went to sleep.
4024 gRootDomain
->wranglerAsleep
= true;
4025 clock_get_uptime(&gRootDomain
->wranglerSleepTime
);
4027 // We start a timer here if the System Sleep timer is greater than the
4028 // Display Sleep timer. We kick off this timer when the display sleeps.
4030 // Note that, although Display Dim timings may change adaptively accordingly
4031 // to the user's activity patterns, Display Sleep _always_ occurs at the
4032 // specified interval since last user activity.
4034 if ( gRootDomain
->extraSleepDelay
)
4036 gRootDomain
->startIdleSleepTimer(gRootDomain
->extraSleepDelay
* 60);
4038 else if ( gRootDomain
->sleepSlider
)
4040 // Accelerate disk spindown if system sleep and display sleep
4041 // sliders are set to the same value (e.g. both set to 5 min),
4042 // and display is about to go dark. Check that spin down timer
4043 // is non-zero (zero = never spin down) and system sleep is
4044 // not set to never sleep.
4046 gRootDomain
->setQuickSpinDownTimeout();
4051 case kIOMessageDeviceHasPoweredOn
:
4053 // The display wrangler has powered on either because of user activity
4054 // or wake from sleep/doze.
4056 if ( 4 != displayPowerState
)
4059 gRootDomain
->wranglerAsleep
= false;
4060 gRootDomain
->adjustPowerState();
4061 gRootDomain
->cancelIdleSleepTimer();
4063 // Change the spindown value back to the user's selection from our
4064 // accelerated setting.
4065 gRootDomain
->restoreUserSpinDownTimeout();
4073 return kIOReturnUnsupported
;
4077 //******************************************************************************
4078 // displayWranglerPublished
4080 // Receives a notification when the IODisplayWrangler is published.
4081 // When it's published we install a power state change handler.
4082 //******************************************************************************
4084 bool IOPMrootDomain::displayWranglerPublished(
4087 IOService
* newService
)
4093 gRootDomain
->wrangler
= newService
;
4095 // we found the display wrangler, now install a handler
4096 if( !gRootDomain
->wrangler
->registerInterest( gIOGeneralInterest
,
4097 &displayWranglerNotification
, target
, 0) )
4106 //******************************************************************************
4109 // Notification on battery class IOPowerSource appearance
4110 //******************************************************************************
4112 bool IOPMrootDomain::batteryPublished(
4115 IOService
* resourceService
)
4117 // rdar://2936060&4435589
4118 // All laptops have dimmable LCD displays
4119 // All laptops have batteries
4120 // So if this machine has a battery, publish the fact that the backlight
4121 // supports dimming.
4122 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
4128 //******************************************************************************
4131 // Some condition that affects our wake/sleep/doze decision has changed.
4133 // If the sleep slider is in the off position, we cannot sleep or doze.
4134 // If the enclosure is open, we cannot sleep or doze.
4135 // If the system is still booting, we cannot sleep or doze.
4137 // In those circumstances, we prevent sleep and doze by holding power on with
4138 // changePowerStateToPriv(ON).
4140 // If the above conditions do not exist, and also the sleep timer has expired,
4141 // we allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
4142 // changePowerStateToPriv(DOZE) depending on whether or not we already know the
4143 // platform cannot sleep.
4145 // In this case, sleep or doze will either occur immediately or at the next time
4146 // that no children are holding the system out of idle sleep via the
4147 // kIOPMPreventIdleSleep flag in their power state arrays.
4148 //******************************************************************************
4150 void IOPMrootDomain::adjustPowerState( void )
4152 DLOG("adjustPowerState "
4153 "PS %u, ASAP %d, SL %ld, AS %d, SB %d, SS %d, UD %d\n",
4154 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
,
4155 allowSleep
, systemBooting
, systemShutdown
, userDisabledAllSleep
);
4159 if ( (sleepSlider
== 0)
4163 || userDisabledAllSleep
4164 || (runStateFlags
& kRStateFlagDisableIdleSleep
) )
4166 changePowerStateToPriv(ON_STATE
);
4170 /* Convenient place to run any code at idle sleep time
4171 * IOPMrootDomain initiates an idle sleep here
4173 * Set last sleep cause accordingly.
4175 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
4177 tracePoint(kIOPMTracePointSleepStarted
);
4180 changePowerStateToPriv(SLEEP_STATE
);
4185 void IOPMrootDomain::pmStatsRecordEvent(
4187 AbsoluteTime timestamp
)
4189 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
4190 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
4194 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
4196 absolutetime_to_nanoseconds(timestamp
, &nsec
);
4198 switch (eventIndex
) {
4199 case kIOPMStatsHibernateImageWrite
:
4201 pmStats
.hibWrite
.start
= nsec
;
4203 pmStats
.hibWrite
.stop
= nsec
;
4206 delta
= pmStats
.hibWrite
.stop
- pmStats
.hibWrite
.start
;
4207 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
4210 case kIOPMStatsHibernateImageRead
:
4212 pmStats
.hibRead
.start
= nsec
;
4214 pmStats
.hibRead
.stop
= nsec
;
4217 delta
= pmStats
.hibRead
.stop
- pmStats
.hibRead
.start
;
4218 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
4225 * Appends a record of the application response to
4226 * IOPMrootDomain::pmStatsAppResponses
4228 void IOPMrootDomain::pmStatsRecordApplicationResponse(
4229 const OSSymbol
*response
,
4235 OSDictionary
*responseDescription
= NULL
;
4236 OSNumber
*delayNum
= NULL
;
4237 OSNumber
*pidNum
= NULL
;
4238 OSNumber
*msgNum
= NULL
;
4239 const OSSymbol
*appname
;
4240 const OSSymbol
*entryName
;
4241 OSObject
*entryType
;
4244 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
4248 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
4250 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
4251 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
4252 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
))
4254 OSNumber
* entryValue
;
4255 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
4256 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
4257 entryValue
->setValue(delay_ms
);
4262 responseDescription
= OSDictionary::withCapacity(5);
4263 if (responseDescription
)
4266 responseDescription
->setObject(_statsResponseTypeKey
, response
);
4269 if (messageType
!= 0) {
4270 msgNum
= OSNumber::withNumber(messageType
, 32);
4272 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
4277 if (name
&& (strlen(name
) > 0))
4279 appname
= OSSymbol::withCString(name
);
4281 responseDescription
->setObject(_statsNameKey
, appname
);
4286 if (app_pid
!= -1) {
4287 pidNum
= OSNumber::withNumber(app_pid
, 32);
4289 responseDescription
->setObject(_statsPIDKey
, pidNum
);
4294 delayNum
= OSNumber::withNumber(delay_ms
, 32);
4296 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
4297 delayNum
->release();
4300 if (pmStatsAppResponses
) {
4301 pmStatsAppResponses
->setObject(responseDescription
);
4304 responseDescription
->release();
4310 //******************************************************************************
4311 // TracePoint support
4313 //******************************************************************************
4315 #define kIOPMRegisterNVRAMTracePointHandlerKey \
4316 "IOPMRegisterNVRAMTracePointHandler"
4318 IOReturn
IOPMrootDomain::callPlatformFunction(
4319 const OSSymbol
* functionName
,
4320 bool waitForFunction
,
4321 void * param1
, void * param2
,
4322 void * param3
, void * param4
)
4324 if (pmTracer
&& functionName
&&
4325 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
4326 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
4328 uint32_t tracePointPhases
, tracePointPCI
;
4329 uint64_t statusCode
;
4331 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
4332 pmTracer
->tracePointTarget
= (void *) param2
;
4333 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
4334 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
4335 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
4336 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
4338 LOG("Sleep failure code 0x%08x 0x%08x\n",
4339 tracePointPCI
, tracePointPhases
);
4341 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
4342 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
4344 return kIOReturnSuccess
;
4347 return super::callPlatformFunction(
4348 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
4351 void IOPMrootDomain::tracePoint( uint8_t point
)
4353 pmTracer
->tracePoint(point
);
4356 //******************************************************************************
4357 // PMTraceWorker Class
4359 //******************************************************************************
4362 #define super OSObject
4363 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
4365 #define kPMBestGuessPCIDevicesCount 25
4366 #define kPMMaxRTCBitfieldSize 32
4368 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
4372 me
= OSTypeAlloc( PMTraceWorker
);
4373 if (!me
|| !me
->init())
4378 DLOG("PMTraceWorker %p\n", me
);
4380 // Note that we cannot instantiate the PCI device -> bit mappings here, since
4381 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
4382 // this dictionary lazily.
4384 me
->pciDeviceBitMappings
= NULL
;
4385 me
->pciMappingLock
= IOLockAlloc();
4386 me
->tracePhase
= kIOPMTracePointSystemUp
;
4387 me
->loginWindowPhase
= 0;
4388 me
->pciBusyBitMask
= 0;
4392 void PMTraceWorker::RTC_TRACE(void)
4394 if (tracePointHandler
&& tracePointTarget
)
4398 wordA
= tracePhase
; // destined for bits 24-31
4400 wordA
|= loginWindowPhase
; // destined for bits 16-23
4403 tracePointHandler( tracePointTarget
, pciBusyBitMask
, wordA
);
4404 DLOG("RTC_TRACE wrote 0x%08x 0x%08x\n", pciBusyBitMask
, wordA
);
4408 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
4410 const OSSymbol
* deviceName
;
4413 IOLockLock(pciMappingLock
);
4415 if (!pciDeviceBitMappings
)
4417 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
4418 if (!pciDeviceBitMappings
)
4422 // Check for bitmask overflow.
4423 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
4426 if ((deviceName
= pciDevice
->copyName()) &&
4427 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
4428 pciDeviceBitMappings
->setObject(deviceName
))
4430 index
= pciDeviceBitMappings
->getCount() - 1;
4431 DLOG("PMTrace PCI array: set object %s => %d\n",
4432 deviceName
->getCStringNoCopy(), index
);
4435 deviceName
->release();
4436 if (!addedToRegistry
&& (index
>= 0))
4437 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
4440 IOLockUnlock(pciMappingLock
);
4444 bool PMTraceWorker::serialize(OSSerialize
*s
) const
4447 if (pciDeviceBitMappings
)
4449 IOLockLock(pciMappingLock
);
4450 ok
= pciDeviceBitMappings
->serialize(s
);
4451 IOLockUnlock(pciMappingLock
);
4456 void PMTraceWorker::tracePoint(uint8_t phase
)
4460 DLOG("IOPMrootDomain: trace point 0x%02x\n", tracePhase
);
4464 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
4466 loginWindowPhase
= phase
;
4468 DLOG("IOPMrootDomain: loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
4472 void PMTraceWorker::tracePCIPowerChange(
4473 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
4476 uint32_t expectedFlag
;
4478 // Ignore PCI changes outside of system sleep/wake.
4479 if ((kIOPMTracePointSystemSleepDriversPhase
!= tracePhase
) &&
4480 (kIOPMTracePointSystemWakeDriversPhase
!= tracePhase
))
4483 // Only record the WillChange transition when going to sleep,
4484 // and the DidChange on the way up.
4485 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
4486 expectedFlag
= (kIOPMTracePointSystemSleepDriversPhase
== tracePhase
) ?
4487 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
4488 if (changeFlags
!= expectedFlag
)
4491 // Mark this device off in our bitfield
4492 if (bitNum
< kPMMaxRTCBitfieldSize
)
4494 bitMask
= (1 << bitNum
);
4496 if (kPowerChangeStart
== type
)
4498 pciBusyBitMask
|= bitMask
;
4499 DLOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
4500 service
->getName(), bitNum
, bitMask
, pciBusyBitMask
);
4504 pciBusyBitMask
&= ~bitMask
;
4505 DLOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
4506 service
->getName(), bitNum
, bitMask
, pciBusyBitMask
);
4514 //******************************************************************************
4515 // PMHaltWorker Class
4517 //******************************************************************************
4519 static unsigned int gPMHaltBusyCount
;
4520 static unsigned int gPMHaltIdleCount
;
4521 static int gPMHaltDepth
;
4522 static unsigned long gPMHaltEvent
;
4523 static IOLock
* gPMHaltLock
= 0;
4524 static OSArray
* gPMHaltArray
= 0;
4525 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
4527 PMHaltWorker
* PMHaltWorker::worker( void )
4533 me
= OSTypeAlloc( PMHaltWorker
);
4534 if (!me
|| !me
->init())
4537 me
->lock
= IOLockAlloc();
4541 DLOG("PMHaltWorker %p\n", me
);
4542 me
->retain(); // thread holds extra retain
4543 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
4548 thread_deallocate(thread
);
4553 if (me
) me
->release();
4557 void PMHaltWorker::free( void )
4559 DLOG("PMHaltWorker free %p\n", this);
4565 return OSObject::free();
4568 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
4570 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
4572 IOLockLock( gPMHaltLock
);
4574 me
->depth
= gPMHaltDepth
;
4575 IOLockUnlock( gPMHaltLock
);
4577 while (me
->depth
>= 0)
4579 PMHaltWorker::work( me
);
4581 IOLockLock( gPMHaltLock
);
4582 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
4584 // This is the last thread to finish work on this level,
4585 // inform everyone to start working on next lower level.
4587 me
->depth
= gPMHaltDepth
;
4588 gPMHaltIdleCount
= 0;
4589 thread_wakeup((event_t
) &gPMHaltIdleCount
);
4593 // One or more threads are still working on this level,
4594 // this thread must wait.
4595 me
->depth
= gPMHaltDepth
- 1;
4597 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
4598 } while (me
->depth
!= gPMHaltDepth
);
4600 IOLockUnlock( gPMHaltLock
);
4603 // No more work to do, terminate thread
4604 DLOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
4605 thread_wakeup( &gPMHaltDepth
);
4609 void PMHaltWorker::work( PMHaltWorker
* me
)
4611 IOService
* service
;
4613 AbsoluteTime startTime
;
4622 // Claim an unit of work from the shared pool
4623 IOLockLock( gPMHaltLock
);
4624 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
4627 service
= (IOService
*)inner
->getAnyObject();
4631 inner
->removeObject(service
);
4634 IOLockUnlock( gPMHaltLock
);
4636 break; // no more work at this depth
4638 clock_get_uptime(&startTime
);
4640 if (!service
->isInactive() &&
4641 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
4643 IOLockLock(me
->lock
);
4644 me
->startTime
= startTime
;
4645 me
->service
= service
;
4646 me
->timeout
= false;
4647 IOLockUnlock(me
->lock
);
4649 service
->systemWillShutdown( gPMHaltEvent
);
4651 // Wait for driver acknowledgement
4652 IOLockLock(me
->lock
);
4653 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
4655 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
4658 timeout
= me
->timeout
;
4659 IOLockUnlock(me
->lock
);
4662 deltaTime
= computeDeltaTimeMS(&startTime
);
4663 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
4664 (gIOKitDebug
& (kIOLogDebugPower
| kIOLogPMRootDomain
)))
4666 KLOG("%s driver %s (%p) took %u ms\n",
4667 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
4668 "PowerOff" : "Restart",
4669 service
->getName(), service
,
4670 (uint32_t) deltaTime
);
4678 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
4681 AbsoluteTime startTime
;
4682 AbsoluteTime endTime
;
4686 IOLockLock(me
->lock
);
4687 if (me
->service
&& !me
->timeout
)
4689 startTime
= me
->startTime
;
4691 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
4693 SUB_ABSOLUTETIME(&endTime
, &startTime
);
4694 absolutetime_to_nanoseconds(endTime
, &nano
);
4696 if (nano
> 3000000000ULL)
4699 LOG("%s still waiting on %s\n",
4700 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
4701 "PowerOff" : "Restart",
4702 me
->service
->getName());
4705 IOLockUnlock(me
->lock
);
4709 //******************************************************************************
4710 // acknowledgeSystemWillShutdown
4712 // Acknowledgement from drivers that they have prepared for shutdown/restart.
4713 //******************************************************************************
4715 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
4717 PMHaltWorker
* worker
;
4723 //DLOG("%s acknowledged\n", from->getName());
4724 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
4727 worker
= (PMHaltWorker
*) prop
;
4728 IOLockLock(worker
->lock
);
4729 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
4730 thread_wakeup((event_t
) worker
);
4731 IOLockUnlock(worker
->lock
);
4736 DLOG("%s acknowledged without worker property\n",
4742 //******************************************************************************
4743 // notifySystemShutdown
4745 // Notify all objects in PM tree that system will shutdown or restart
4746 //******************************************************************************
4749 notifySystemShutdown( IOService
* root
, unsigned long event
)
4751 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
4752 IORegistryIterator
* iter
;
4753 IORegistryEntry
* entry
;
4756 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
4757 AbsoluteTime deadline
;
4758 unsigned int totalNodes
= 0;
4760 unsigned int rootDepth
;
4761 unsigned int numWorkers
;
4767 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
4769 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
4771 // Iterate the entire PM tree starting from root
4773 rootDepth
= root
->getDepth( gIOPowerPlane
);
4774 if (!rootDepth
) goto done
;
4776 // debug - for repeated test runs
4777 while (PMHaltWorker::metaClass
->getInstanceCount())
4782 gPMHaltArray
= OSArray::withCapacity(40);
4783 if (!gPMHaltArray
) goto done
;
4786 gPMHaltArray
->flushCollection();
4790 gPMHaltLock
= IOLockAlloc();
4791 if (!gPMHaltLock
) goto done
;
4794 if (!gPMHaltClientAcknowledgeKey
)
4796 gPMHaltClientAcknowledgeKey
=
4797 OSSymbol::withCStringNoCopy("PMShutdown");
4798 if (!gPMHaltClientAcknowledgeKey
) goto done
;
4801 gPMHaltEvent
= event
;
4803 // Depth-first walk of PM plane
4805 iter
= IORegistryIterator::iterateOver(
4806 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
4810 while ((entry
= iter
->getNextObject()))
4812 node
= OSDynamicCast(IOService
, entry
);
4817 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
4820 depth
= node
->getDepth( gIOPowerPlane
);
4821 if (depth
<= rootDepth
)
4826 // adjust to zero based depth
4827 depth
-= (rootDepth
+ 1);
4829 // gPMHaltArray is an array of containers, each container
4830 // refers to nodes with the same depth.
4832 count
= gPMHaltArray
->getCount();
4833 while (depth
>= count
)
4835 // expand array and insert placeholders
4836 gPMHaltArray
->setObject(PLACEHOLDER
);
4839 count
= gPMHaltArray
->getCount();
4842 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
4843 if (inner
== PLACEHOLDER
)
4845 inner
= OSSet::withCapacity(40);
4848 gPMHaltArray
->replaceObject(depth
, inner
);
4853 // PM nodes that appear more than once in the tree will have
4854 // the same depth, OSSet will refuse to add the node twice.
4856 ok
= inner
->setObject(node
);
4859 DLOG("Skipped PM node %s\n", node
->getName());
4865 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
4868 if (inner
!= PLACEHOLDER
)
4869 count
= inner
->getCount();
4870 DLOG("Nodes at depth %u = %u\n", i
, count
);
4873 // strip placeholders (not all depths are populated)
4875 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
4877 if (inner
== PLACEHOLDER
)
4879 gPMHaltArray
->removeObject(i
);
4882 count
= inner
->getCount();
4883 if (count
> numWorkers
)
4885 totalNodes
+= count
;
4889 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
4892 gPMHaltBusyCount
= 0;
4893 gPMHaltIdleCount
= 0;
4894 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
4896 // Create multiple workers (and threads)
4898 if (numWorkers
> kPMHaltMaxWorkers
)
4899 numWorkers
= kPMHaltMaxWorkers
;
4901 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
4902 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
4904 for (unsigned int i
= 0; i
< numWorkers
; i
++)
4905 workers
[i
] = PMHaltWorker::worker();
4907 // Wait for workers to exhaust all available work
4909 IOLockLock(gPMHaltLock
);
4910 while (gPMHaltDepth
>= 0)
4912 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
4914 waitResult
= IOLockSleepDeadline(
4915 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
4916 if (THREAD_TIMED_OUT
== waitResult
)
4919 clock_get_uptime(&now
);
4921 IOLockUnlock(gPMHaltLock
);
4922 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
4925 PMHaltWorker::checkTimeout(workers
[i
], &now
);
4927 IOLockLock(gPMHaltLock
);
4930 IOLockUnlock(gPMHaltLock
);
4932 // Release all workers
4934 for (unsigned int i
= 0; i
< numWorkers
; i
++)
4937 workers
[i
]->release();
4938 // worker also retained by it's own thread
4942 DLOG("%s done\n", __FUNCTION__
);
4947 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4951 #define super OSObject
4952 OSDefineMetaClassAndFinalStructors(PMSettingObject
, OSObject
)
4954 void PMSettingObject::setPMSetting(const OSSymbol
*type
, OSObject
*obj
)
4956 (*func
)(target
, type
, obj
, refcon
);
4960 * Static constructor/initializer for PMSettingObject
4962 PMSettingObject
*PMSettingObject::pmSettingObject(
4963 IOPMrootDomain
*parent_arg
,
4964 IOPMSettingControllerCallback handler_arg
,
4965 OSObject
*target_arg
,
4966 uintptr_t refcon_arg
,
4967 uint32_t supportedPowerSources
,
4968 const OSSymbol
* settings
[])
4970 uint32_t objCount
= 0;
4971 PMSettingObject
*pmso
;
4973 if( !parent_arg
|| !handler_arg
|| !settings
) return NULL
;
4975 // count OSSymbol entries in NULL terminated settings array
4976 while( settings
[objCount
] ) {
4979 if(0 == objCount
) return NULL
;
4981 pmso
= new PMSettingObject
;
4982 if(!pmso
|| !pmso
->init()) return NULL
;
4984 pmso
->parent
= parent_arg
;
4985 pmso
->func
= handler_arg
;
4986 pmso
->target
= target_arg
;
4987 pmso
->refcon
= refcon_arg
;
4988 pmso
->releaseAtCount
= objCount
+ 1; // release when it has count+1 retains
4990 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount
);
4991 if(pmso
->publishedFeatureID
) {
4992 for(unsigned int i
=0; i
<objCount
; i
++) {
4993 // Since there is now at least one listener to this setting, publish
4994 // PM root domain support for it.
4995 parent_arg
->publishFeature( settings
[i
]->getCStringNoCopy(),
4996 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
5003 void PMSettingObject::free(void)
5005 OSCollectionIterator
*settings_iter
;
5010 int objCount
= releaseAtCount
- 1;
5012 if(publishedFeatureID
) {
5013 for(i
=0; i
<objCount
; i
++) {
5014 if(0 != publishedFeatureID
[i
]) {
5015 parent
->removePublishedFeature( publishedFeatureID
[i
] );
5019 IOFree(publishedFeatureID
, sizeof(uint32_t) * objCount
);
5022 IORecursiveLockLock(parent
->settingsCtrlLock
);
5024 // Search each PM settings array in the kernel.
5025 settings_iter
= OSCollectionIterator::withCollection(parent
->settingsCallbacks
);
5028 while(( sym
= OSDynamicCast(OSSymbol
, settings_iter
->getNextObject()) ))
5030 arr
= (OSArray
*)parent
->settingsCallbacks
->getObject(sym
);
5031 arr_idx
= arr
->getNextIndexOfObject(this, 0);
5033 // 'this' was found in the array; remove it
5034 arr
->removeObject(arr_idx
);
5038 settings_iter
->release();
5041 IORecursiveLockUnlock(parent
->settingsCtrlLock
);
5046 void PMSettingObject::taggedRelease(const void *tag
, const int when
) const
5048 // We have n+1 retains - 1 per array that this PMSettingObject is a member
5049 // of, and 1 retain to ourself. When we get a release with n+1 retains
5050 // remaining, we go ahead and free ourselves, cleaning up array pointers
5053 super::taggedRelease(tag
, releaseAtCount
);
5058 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5061 #define super IOService
5063 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
5065 // This array exactly parallels the state array for the root domain.
5066 // Power state changes initiated by a device can be vetoed by a client of the device, and
5067 // power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
5068 // so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
5069 // its parent to make the change. That is the reason for this complexity.
5071 static IOPMPowerState patriarchPowerStates
[NUM_POWER_STATES
] =
5073 {1,0,0,0,0,0,0,0,0,0,0,0}, // off (not used)
5074 {1,0,RESTART_POWER
,0,0,0,0,0,0,0,0,0}, // reset (not used)
5075 {1,0,SLEEP_POWER
,0,0,0,0,0,0,0,0,0}, // sleep
5076 {1,0,DOZE_POWER
,0,0,0,0,0,0,0,0,0}, // doze
5077 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0}, // running
5080 bool IORootParent::start( IOService
* nub
)
5082 mostRecentChange
= ON_STATE
;
5084 attachToParent( getRegistryRoot(), gIOPowerPlane
);
5086 registerPowerDriver(this, patriarchPowerStates
, NUM_POWER_STATES
);
5088 powerOverrideOnPriv();
5092 void IORootParent::shutDownSystem( void )
5096 void IORootParent::restartSystem( void )
5100 void IORootParent::sleepSystem( void )
5102 mostRecentChange
= SLEEP_STATE
;
5103 changePowerStateToPriv(SLEEP_STATE
);
5106 void IORootParent::dozeSystem( void )
5108 mostRecentChange
= DOZE_STATE
;
5109 changePowerStateToPriv(DOZE_STATE
);
5112 // Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
5113 // This brings the parent to doze, which allows the root to step up from sleep to doze.
5115 // In idle sleep, do nothing because the parent is still on and the root can freely change state.
5117 void IORootParent::sleepToDoze( void )
5119 if ( mostRecentChange
== SLEEP_STATE
) {
5120 changePowerStateToPriv(DOZE_STATE
);
5124 void IORootParent::wakeSystem( void )
5126 mostRecentChange
= ON_STATE
;
5127 changePowerStateToPriv(ON_STATE
);