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 <libkern/OSDebug.h>
31 #include <IOKit/IOWorkLoop.h>
32 #include <IOKit/IOCommandGate.h>
33 #include <IOKit/IOPlatformExpert.h>
34 #include <IOKit/IOKitDebug.h>
35 #include <IOKit/IOTimeStamp.h>
36 #include <IOKit/pwr_mgt/IOPMlog.h>
37 #include <IOKit/pwr_mgt/RootDomain.h>
38 #include <IOKit/pwr_mgt/IOPMPrivate.h>
39 #include <IOKit/IODeviceTreeSupport.h>
40 #include <IOKit/IOMessage.h>
41 #include <IOKit/IOReturn.h>
42 #include "RootDomainUserClient.h"
43 #include "IOKit/pwr_mgt/IOPowerConnection.h"
44 #include "IOPMPowerStateQueue.h"
45 #include <IOKit/IOCatalogue.h>
46 #include <IOKit/IOCommand.h> // IOServicePMPrivate
48 #include <IOKit/IOHibernatePrivate.h>
50 #include <sys/syslog.h>
51 #include <sys/sysctl.h>
53 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
54 #include "IOServicePMPrivate.h"
57 #include <mach/shared_region.h>
60 #if defined(__i386__) || defined(__x86_64__)
62 #include "IOPMrootDomainInternal.h"
66 #define kIOPMrootDomainClass "IOPMrootDomain"
68 #define LOG_PREFIX "PMRD: "
70 #define LOG(x...) do { \
71 kprintf(LOG_PREFIX x); IOLog(x); } while (false)
73 #define KLOG(x...) do { \
74 kprintf(LOG_PREFIX x); } while (false)
76 #define DLOG(x...) do { \
77 if (kIOLogPMRootDomain & gIOKitDebug) \
78 kprintf(LOG_PREFIX x); } while (false)
80 #define CHECK_THREAD_CONTEXT
81 #ifdef CHECK_THREAD_CONTEXT
82 static IOWorkLoop
* gIOPMWorkLoop
= 0;
83 #define ASSERT_GATED(x) \
85 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
86 panic("RootDomain: not inside PM gate"); \
90 #define ASSERT_GATED(x)
91 #endif /* CHECK_THREAD_CONTEXT */
93 // Event types for IOPMPowerStateQueue::submitPowerEvent()
95 kPowerEventFeatureChanged
= 1,
96 kPowerEventReceivedPowerNotification
,
97 kPowerEventSystemBootCompleted
,
98 kPowerEventSystemShutdown
,
99 kPowerEventUserDisabledSleep
,
100 kPowerEventConfigdRegisteredInterest
,
101 kPowerEventAggressivenessChanged
,
102 kPowerEventAssertionCreate
, // 8
103 kPowerEventAssertionRelease
, // 9
104 kPowerEventAssertionSetLevel
// 10
108 IOReturn
OSKextSystemSleepOrWake( UInt32
);
111 extern const IORegistryPlane
* gIOPowerPlane
;
113 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
114 static void wakeupClamshellTimerExpired( thread_call_param_t us
, thread_call_param_t
);
115 static void notifySystemShutdown( IOService
* root
, unsigned long event
);
116 static bool clientMessageFilter( OSObject
* object
, void * context
);
117 static void handleAggressivesFunction( thread_call_param_t param1
, thread_call_param_t param2
);
118 static void pmEventTimeStamp(uint64_t *recordTS
);
120 // "IOPMSetSleepSupported" callPlatformFunction name
121 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
122 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
124 #define kIOSleepSupportedKey "IOSleepSupported"
126 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
127 | kIOPMSupportedOnBatt \
128 | kIOPMSupportedOnUPS)
132 // not idle around autowake time, secs
133 kAutoWakePreWindow
= 45,
134 kAutoWakePostWindow
= 15
137 #define kLocalEvalClamshellCommand (1 << 15)
148 #define ON_POWER kIOPMPowerOn
149 #define RESTART_POWER kIOPMRestart
150 #define SLEEP_POWER kIOPMAuxPowerOn
151 #define DOZE_POWER kIOPMDoze
153 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
155 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
156 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
157 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
158 {1, kIOPMDoze
, kIOPMDoze
, DOZE_POWER
, 0,0,0,0,0,0,0,0},
159 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
162 // Clients eligible to receive system power messages.
164 kMessageClientNone
= 0,
166 kMessageClientConfigd
169 // Run states (R-state) defined within the ON power state.
177 // IOService in power plane can be tagged with following flags.
179 kServiceFlagGraphics
= 0x01,
180 kServiceFlagNoPowerUp
= 0x02,
181 kServiceFlagTopLevelPCI
= 0x04
184 // Flags describing R-state features and capabilities.
186 kRStateFlagNone
= 0x00000000,
187 kRStateFlagSuppressGraphics
= 0x00000001,
188 kRStateFlagSuppressMessages
= 0x00000002,
189 kRStateFlagSuppressPCICheck
= 0x00000004,
190 kRStateFlagDisableIdleSleep
= 0x00000008
193 #if ROOT_DOMAIN_RUN_STATES
195 // Table of flags for each R-state.
196 static uint32_t gRStateFlags
[ kRStateCount
] =
201 kRStateFlagSuppressGraphics
,
203 /* Maintenance wake */
204 kRStateFlagSuppressGraphics
|
205 kRStateFlagSuppressMessages
|
206 kRStateFlagSuppressPCICheck
|
207 kRStateFlagDisableIdleSleep
210 static IONotifier
* gConfigdNotifier
= 0;
212 #define kIOPMRootDomainRunStateKey "Run State"
213 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
214 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
215 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
217 #endif /* ROOT_DOMAIN_RUN_STATES */
219 // Special interest that entitles the interested client from receiving
220 // all system messages. Used by pmconfigd to support maintenance wake.
222 #define kIOPMPrivilegedPowerInterest "IOPMPrivilegedPowerInterest"
224 static IONotifier
* gSysPowerDownNotifier
= 0;
229 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
230 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
232 #define kAggressivesMinValue 1
234 static uint32_t gAggressivesState
= 0;
237 kAggressivesStateBusy
= 0x01,
238 kAggressivesStateQuickSpindown
= 0x02
241 struct AggressivesRecord
{
247 struct AggressivesRequest
{
253 AggressivesRecord record
;
258 kAggressivesRequestTypeService
= 1,
259 kAggressivesRequestTypeRecord
263 kAggressivesOptionSynchronous
= 0x00000001,
264 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
265 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
266 kAggressivesOptionQuickSpindownMask
= 0x00000300
270 kAggressivesRecordFlagModified
= 0x00000001,
271 kAggressivesRecordFlagMinValue
= 0x00000002
275 static IOPMrootDomain
* gRootDomain
;
276 static UInt32 gSleepOrShutdownPending
= 0;
277 static UInt32 gWillShutdown
= 0;
278 static uint32_t gMessageClientType
= kMessageClientNone
;
279 static UInt32 gSleepWakeUUIDIsSet
= false;
281 struct timeval gIOLastSleepTime
;
282 struct timeval gIOLastWakeTime
;
284 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
285 #define kCPUUnknownIndex 9999999
292 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
293 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
294 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
296 class PMSettingObject
: public OSObject
298 OSDeclareFinalStructors(PMSettingObject
)
300 IOPMrootDomain
*parent
;
301 IOPMSettingControllerCallback func
;
304 uint32_t *publishedFeatureID
;
307 static PMSettingObject
*pmSettingObject(
308 IOPMrootDomain
*parent_arg
,
309 IOPMSettingControllerCallback handler_arg
,
310 OSObject
*target_arg
,
311 uintptr_t refcon_arg
,
312 uint32_t supportedPowerSources
,
313 const OSSymbol
*settings
[]);
315 void setPMSetting(const OSSymbol
*type
, OSObject
*obj
);
317 void taggedRelease(const void *tag
, const int when
) const;
322 * PMAssertionsTracker
323 * Tracks kernel and user space PM assertions
325 class PMAssertionsTracker
: public OSObject
327 OSDeclareFinalStructors(PMAssertionsTracker
)
329 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
331 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
332 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
333 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
334 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
336 OSArray
*copyAssertionsArray(void);
337 IOPMDriverAssertionType
getActivatedAssertions(void);
338 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
340 IOReturn
handleCreateAssertion(OSData
*);
341 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
342 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
343 IOReturn
handleSetUserAssertionLevels(void * arg0
);
344 void publishProperties(void);
348 IOPMDriverAssertionID id
;
349 IOPMDriverAssertionType assertionBits
;
350 uint64_t createdTime
;
351 uint64_t modifiedTime
;
352 const OSSymbol
*ownerString
;
353 IOService
*ownerService
;
354 IOPMDriverAssertionLevel level
;
357 uint32_t tabulateProducerCount
;
358 uint32_t tabulateConsumerCount
;
360 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
363 IOPMrootDomain
*owner
;
364 OSArray
*assertionsArray
;
365 IOLock
*assertionsArrayLock
;
366 IOPMDriverAssertionID issuingUniqueID
;
367 IOPMDriverAssertionType assertionsKernel
;
368 IOPMDriverAssertionType assertionsUser
;
369 IOPMDriverAssertionType assertionsCombined
;
372 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
376 * Internal helper object for logging trace points to RTC
377 * IOPMrootDomain and only IOPMrootDomain should instantiate
378 * exactly one of these.
381 typedef void (*IOPMTracePointHandler
)(
382 void * target
, uint32_t code
, uint32_t data
);
384 class PMTraceWorker
: public OSObject
386 OSDeclareDefaultStructors(PMTraceWorker
)
388 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
390 static PMTraceWorker
*tracer( IOPMrootDomain
* );
391 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
392 void tracePoint(uint8_t phase
);
393 void traceLoginWindowPhase(uint8_t phase
);
394 int recordTopLevelPCIDevice(IOService
*);
395 void RTC_TRACE(void);
396 virtual bool serialize(OSSerialize
*s
) const;
398 IOPMTracePointHandler tracePointHandler
;
399 void * tracePointTarget
;
401 IOPMrootDomain
*owner
;
402 IOLock
*pciMappingLock
;
403 OSArray
*pciDeviceBitMappings
;
406 uint8_t loginWindowPhase
;
407 uint8_t addedToRegistry
;
409 uint32_t pciBusyBitMask
;
414 * Internal helper object for Shutdown/Restart notifications.
416 #define kPMHaltMaxWorkers 8
417 #define kPMHaltTimeoutMS 100
419 class PMHaltWorker
: public OSObject
421 OSDeclareFinalStructors( PMHaltWorker
)
424 IOService
* service
; // service being worked on
425 AbsoluteTime startTime
; // time when work started
426 int depth
; // work on nubs at this PM-tree depth
427 int visits
; // number of nodes visited (debug)
429 bool timeout
; // service took too long
431 static PMHaltWorker
* worker( void );
432 static void main( void * arg
, wait_result_t waitResult
);
433 static void work( PMHaltWorker
* me
);
434 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
435 virtual void free( void );
438 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
441 #define super IOService
442 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
446 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
448 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
451 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
453 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
456 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
458 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
461 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
463 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
466 IOReturn
rootDomainRestart ( void )
468 return gRootDomain
->restartSystem();
471 IOReturn
rootDomainShutdown ( void )
473 return gRootDomain
->shutdownSystem();
476 void IOSystemShutdownNotification ( void )
478 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
480 OSKext::willShutdown();
481 for (int i
= 0; i
< 100; i
++)
483 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
489 int sync_internal(void);
493 A device is always in the highest power state which satisfies its driver, its policy-maker, and any power domain
494 children it has, but within the constraint of the power state provided by its parent. The driver expresses its desire by
495 calling changePowerStateTo(), the policy-maker expresses its desire by calling changePowerStateToPriv(), and the children
496 express their desires by calling requestPowerDomainState().
498 The Root Power Domain owns the policy for idle and demand sleep and doze for the system. It is a power-managed IOService just
499 like the others in the system. It implements several power states which correspond to what we see as Sleep, Doze, etc.
501 The sleep/doze policy is as follows:
502 Sleep and Doze are prevented if the case is open so that nobody will think the machine is off and plug/unplug cards.
503 Sleep and Doze are prevented if the sleep timeout slider in the preferences panel is at zero.
504 The system cannot Sleep, but can Doze if some object in the tree is in a power state marked kIOPMPreventSystemSleep.
506 These three conditions are enforced using the "driver clamp" by calling changePowerStateTo(). For example, if the case is
507 opened, changePowerStateTo(ON_STATE) is called to hold the system on regardless of the desires of the children of the root or
508 the state of the other clamp.
510 Demand Sleep/Doze is initiated by pressing the front panel power button, closing the clamshell, or selecting the menu item.
511 In this case the root's parent actually initiates the power state change so that the root has no choice and does not give
512 applications the opportunity to veto the change.
514 Idle Sleep/Doze occurs if no objects in the tree are in a state marked kIOPMPreventIdleSleep. When this is true, the root's
515 children are not holding the root on, so it sets the "policy-maker clamp" by calling changePowerStateToPriv(ON_STATE)
516 to hold itself on until the sleep timer expires. This timer is set for the difference between the sleep timeout slider and
517 the larger of the display dim timeout slider and the disk spindown timeout slider in the Preferences panel. For example, if
518 the system is set to sleep after thirty idle minutes, and the display and disk are set to sleep after five idle minutes,
519 when there is no longer an object in the tree holding the system out of Idle Sleep (via kIOPMPreventIdleSleep), the root
520 sets its timer for 25 minutes (30 - 5). When the timer expires, it releases its clamp and now nothing is holding it awake,
523 Demand sleep is prevented when the system is booting. When preferences are transmitted by the loginwindow at the end of
524 boot, a flag is cleared, and this allows subsequent Demand Sleep.
526 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
527 a clamp, but sets a flag which is noticed before actually sleeping the kernel. If the flag is set, the root steps up
528 one power state from Sleep to Doze, and any objects in the tree for which this is relevent will act appropriately (USB and
529 ADB will turn on again so that they can wake the system out of Doze (keyboard/mouse activity will cause the Display Wrangler
533 //******************************************************************************
535 IOPMrootDomain
* IOPMrootDomain::construct( void )
537 IOPMrootDomain
*root
;
539 root
= new IOPMrootDomain
;
546 //******************************************************************************
548 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
550 IOService
*rootDomain
= (IOService
*) p0
;
551 unsigned long pmRef
= (unsigned long) p1
;
553 DLOG("disk_sync_callout start\n");
556 IOHibernateSystemSleep();
559 rootDomain
->allowPowerChange(pmRef
);
560 DLOG("disk_sync_callout finish\n");
563 //******************************************************************************
565 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
567 AbsoluteTime endTime
;
570 clock_get_uptime(&endTime
);
571 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
573 SUB_ABSOLUTETIME(&endTime
, startTime
);
574 absolutetime_to_nanoseconds(endTime
, &nano
);
577 return (UInt32
)(nano
/ 1000000ULL);
580 //******************************************************************************
583 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
585 struct timeval
*swt
= (struct timeval
*)arg1
;
586 struct proc
*p
= req
->p
;
589 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
590 } else if(proc_is64bit(p
)) {
591 struct user64_timeval t
;
592 t
.tv_sec
= swt
->tv_sec
;
593 t
.tv_usec
= swt
->tv_usec
;
594 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
596 struct user32_timeval t
;
597 t
.tv_sec
= swt
->tv_sec
;
598 t
.tv_usec
= swt
->tv_usec
;
599 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
603 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
604 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
605 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
607 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
608 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
609 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
614 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
616 int new_value
, changed
;
617 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
619 if (!gWillShutdown
&& (new_value
== 1)) {
620 IOSystemShutdownNotification();
627 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
628 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
629 0, 0, sysctl_willshutdown
, "I", "");
634 sysctl_progressmeterenable
635 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
638 int new_value
, changed
;
640 error
= sysctl_io_number(req
, vc_progress_meter_enable
, sizeof(int), &new_value
, &changed
);
643 vc_enable_progressmeter(new_value
);
650 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
653 int new_value
, changed
;
655 error
= sysctl_io_number(req
, vc_progress_meter_value
, sizeof(int), &new_value
, &changed
);
658 vc_set_progressmeter(new_value
);
663 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
664 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
665 0, 0, sysctl_progressmeterenable
, "I", "");
667 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
668 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
669 0, 0, sysctl_progressmeter
, "I", "");
673 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
674 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
676 //******************************************************************************
679 //******************************************************************************
681 #define kRootDomainSettingsCount 16
683 bool IOPMrootDomain::start( IOService
* nub
)
685 OSIterator
*psIterator
;
686 OSDictionary
*tmpDict
;
691 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
692 gIOPMSettingMaintenanceWakeCalendarKey
=
693 OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
695 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
696 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
697 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
699 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
700 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
702 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
704 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
705 gIOPMSettingAutoWakeSecondsKey
,
706 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
707 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
),
708 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
709 OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
),
710 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
711 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
712 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
713 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
714 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
715 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
716 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
717 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
718 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
719 OSSymbol::withCString(kIOPMStateConsoleShutdown
)
722 queue_init(&aggressivesQueue
);
723 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
724 aggressivesData
= OSData::withCapacity(
725 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
727 featuresDictLock
= IOLockAlloc();
728 settingsCtrlLock
= IORecursiveLockAlloc();
729 setPMRootDomain(this);
731 extraSleepTimer
= thread_call_allocate(
732 idleSleepTimerExpired
,
733 (thread_call_param_t
) this);
735 clamshellWakeupIgnore
= thread_call_allocate(
736 wakeupClamshellTimerExpired
,
737 (thread_call_param_t
) this);
739 diskSyncCalloutEntry
= thread_call_allocate(
741 (thread_call_param_t
) this);
744 setProperty(kIOSleepSupportedKey
, true);
746 bzero(&pmStats
, sizeof(pmStats
));
748 pmTracer
= PMTraceWorker::tracer(this);
750 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
752 updateRunState(kRStateNormal
);
753 userDisabledAllSleep
= false;
755 sleepIsSupported
= true;
756 systemBooting
= true;
758 idleSleepTimerPending
= false;
761 clamshellIsClosed
= false;
762 clamshellExists
= false;
763 ignoringClamshell
= true;
764 ignoringClamshellOnWake
= false;
765 acAdaptorConnected
= true;
767 queuedSleepWakeUUIDString
= NULL
;
768 pmStatsAppResponses
= OSArray::withCapacity(5);
769 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
770 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
771 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
772 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
773 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
775 idxPMCPUClamshell
= kCPUUnknownIndex
;
776 idxPMCPULimitedPower
= kCPUUnknownIndex
;
778 tmpDict
= OSDictionary::withCapacity(1);
779 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
782 settingsCallbacks
= OSDictionary::withCapacity(1);
784 // Create a list of the valid PM settings that we'll relay to
785 // interested clients in setProperties() => setPMSetting()
786 allowedPMSettings
= OSArray::withObjects(
787 (const OSObject
**)settingsArr
,
788 kRootDomainSettingsCount
,
791 fPMSettingsDict
= OSDictionary::withCapacity(5);
793 PMinit(); // creates gIOPMWorkLoop
795 // Create IOPMPowerStateQueue used to queue external power
796 // events, and to handle those events on the PM work loop.
797 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
798 this, OSMemberFunctionCast(IOEventSource::Action
, this,
799 &IOPMrootDomain::dispatchPowerEvent
));
800 getPMworkloop()->addEventSource(pmPowerStateQueue
);
801 #ifdef CHECK_THREAD_CONTEXT
802 gIOPMWorkLoop
= getPMworkloop();
805 // create our power parent
806 patriarch
= new IORootParent
;
808 patriarch
->attach(this);
809 patriarch
->start(this);
810 patriarch
->addPowerChild(this);
812 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
814 // set a clamp until we sleep
815 changePowerStateToPriv(ON_STATE
);
817 // install power change handler
818 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
821 // Register for a notification when IODisplayWrangler is published
822 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
824 _displayWranglerNotifier
= addMatchingNotification(
825 gIOPublishNotification
, tmpDict
,
826 (IOServiceMatchingNotificationHandler
) &displayWranglerPublished
,
832 // Battery location published - ApplePMU support only
833 if ((tmpDict
= serviceMatching("IOPMPowerSource")))
835 _batteryPublishNotifier
= addMatchingNotification(
836 gIOPublishNotification
, tmpDict
,
837 (IOServiceMatchingNotificationHandler
) &batteryPublished
,
842 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
843 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
844 ucClassName
->release();
846 // IOBacklightDisplay can take a long time to load at boot, or it may
847 // not load at all if you're booting with clamshell closed. We publish
848 // 'DisplayDims' here redundantly to get it published early and at all.
849 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
850 if( psIterator
&& psIterator
->getNextObject() )
852 // There's at least one battery on the system, so we publish
853 // 'DisplayDims' support for the LCD.
854 publishFeature("DisplayDims");
857 psIterator
->release();
860 sysctl_register_oid(&sysctl__kern_sleeptime
);
861 sysctl_register_oid(&sysctl__kern_waketime
);
862 sysctl_register_oid(&sysctl__kern_willshutdown
);
864 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
865 sysctl_register_oid(&sysctl__kern_progressmeter
);
866 #endif /* !CONFIG_EMBEDDED */
869 IOHibernateSystemInit(this);
872 registerService(); // let clients find us
878 //******************************************************************************
881 // Receive a setProperty call
882 // The "System Boot" property means the system is completely booted.
883 //******************************************************************************
885 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
887 IOReturn return_value
= kIOReturnSuccess
;
888 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
896 const OSSymbol
*boot_complete_string
=
897 OSSymbol::withCString("System Boot Complete");
898 const OSSymbol
*sys_shutdown_string
=
899 OSSymbol::withCString("System Shutdown");
900 const OSSymbol
*stall_halt_string
=
901 OSSymbol::withCString("StallSystemAtHalt");
902 const OSSymbol
*battery_warning_disabled_string
=
903 OSSymbol::withCString("BatteryWarningsDisabled");
904 const OSSymbol
*idle_seconds_string
=
905 OSSymbol::withCString("System Idle Seconds");
907 const OSSymbol
*hibernatemode_string
=
908 OSSymbol::withCString(kIOHibernateModeKey
);
909 const OSSymbol
*hibernatefile_string
=
910 OSSymbol::withCString(kIOHibernateFileKey
);
911 const OSSymbol
*hibernatefreeratio_string
=
912 OSSymbol::withCString(kIOHibernateFreeRatioKey
);
913 const OSSymbol
*hibernatefreetime_string
=
914 OSSymbol::withCString(kIOHibernateFreeTimeKey
);
916 const OSSymbol
*sleepdisabled_string
=
917 OSSymbol::withCString("SleepDisabled");
918 const OSSymbol
*ondeck_sleepwake_uuid_string
=
919 OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
920 const OSSymbol
*loginwindow_tracepoint_string
=
921 OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
925 return_value
= kIOReturnBadArgument
;
929 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(idle_seconds_string
))))
931 setProperty(idle_seconds_string
, n
);
932 idleSeconds
= n
->unsigned32BitValue();
935 if (boot_complete_string
&& dict
->getObject(boot_complete_string
))
937 pmPowerStateQueue
->submitPowerEvent( kPowerEventSystemBootCompleted
);
940 if( battery_warning_disabled_string
941 && dict
->getObject(battery_warning_disabled_string
))
943 setProperty( battery_warning_disabled_string
,
944 dict
->getObject(battery_warning_disabled_string
));
947 if( sys_shutdown_string
948 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sys_shutdown_string
))))
950 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
953 if( stall_halt_string
954 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(stall_halt_string
))) )
956 setProperty(stall_halt_string
, b
);
960 if ( hibernatemode_string
961 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatemode_string
))))
963 setProperty(hibernatemode_string
, n
);
965 if ( hibernatefreeratio_string
966 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreeratio_string
))))
968 setProperty(hibernatefreeratio_string
, n
);
970 if ( hibernatefreetime_string
971 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreetime_string
))))
973 setProperty(hibernatefreetime_string
, n
);
975 if ( hibernatefile_string
976 && (str
= OSDynamicCast(OSString
, dict
->getObject(hibernatefile_string
))))
978 setProperty(hibernatefile_string
, str
);
982 if( sleepdisabled_string
983 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sleepdisabled_string
))) )
985 setProperty(sleepdisabled_string
, b
);
986 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
989 if (ondeck_sleepwake_uuid_string
990 && (obj
= dict
->getObject(ondeck_sleepwake_uuid_string
)))
992 // Clear the currently published UUID
993 if (kOSBooleanFalse
== obj
)
995 publishSleepWakeUUID(NULL
);
998 // Cache UUID for an upcoming sleep/wake
999 if ((str
= OSDynamicCast(OSString
, obj
)))
1001 if (queuedSleepWakeUUIDString
) {
1002 queuedSleepWakeUUIDString
->release();
1003 queuedSleepWakeUUIDString
= NULL
;
1005 queuedSleepWakeUUIDString
= str
;
1006 queuedSleepWakeUUIDString
->retain();
1007 DLOG("SleepWake UUID queued: %s\n",
1008 queuedSleepWakeUUIDString
->getCStringNoCopy());
1012 if (loginwindow_tracepoint_string
1013 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(loginwindow_tracepoint_string
)))
1016 pmTracer
->traceLoginWindowPhase( n
->unsigned8BitValue() );
1019 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(kIOPMDeepSleepEnabledKey
))))
1021 setProperty(kIOPMDeepSleepEnabledKey
, b
);
1023 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(kIOPMDeepSleepDelayKey
))))
1025 setProperty(kIOPMDeepSleepDelayKey
, n
);
1028 // Relay our allowed PM settings onto our registered PM clients
1029 for(i
= 0; i
< allowedPMSettings
->getCount(); i
++) {
1031 type
= (OSSymbol
*)allowedPMSettings
->getObject(i
);
1034 obj
= dict
->getObject(type
);
1037 if ((gIOPMSettingAutoWakeSecondsKey
== type
) && ((n
= OSDynamicCast(OSNumber
, obj
))))
1039 UInt32 rsecs
= n
->unsigned32BitValue();
1041 autoWakeStart
= autoWakeEnd
= 0;
1044 AbsoluteTime deadline
;
1045 clock_interval_to_deadline(rsecs
+ kAutoWakePostWindow
, kSecondScale
, &deadline
);
1046 autoWakeEnd
= AbsoluteTime_to_scalar(&deadline
);
1047 if (rsecs
> kAutoWakePreWindow
)
1048 rsecs
-= kAutoWakePreWindow
;
1051 clock_interval_to_deadline(rsecs
, kSecondScale
, &deadline
);
1052 autoWakeStart
= AbsoluteTime_to_scalar(&deadline
);
1056 return_value
= setPMSetting(type
, obj
);
1058 if(kIOReturnSuccess
!= return_value
) goto exit
;
1062 if(boot_complete_string
) boot_complete_string
->release();
1063 if(sys_shutdown_string
) sys_shutdown_string
->release();
1064 if(stall_halt_string
) stall_halt_string
->release();
1065 if (battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1066 if(idle_seconds_string
) idle_seconds_string
->release();
1067 if(sleepdisabled_string
) sleepdisabled_string
->release();
1068 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1069 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1071 if(hibernatemode_string
) hibernatemode_string
->release();
1072 if(hibernatefile_string
) hibernatefile_string
->release();
1073 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1074 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1076 return return_value
;
1080 //******************************************************************************
1081 // aggressivenessChanged
1083 // We are behind the command gate to examine changes to aggressives.
1084 //******************************************************************************
1086 void IOPMrootDomain::aggressivenessChanged( void )
1088 unsigned long minutesToSleep
= 0;
1089 unsigned long minutesToDisplayDim
= 0;
1093 // Fetch latest display and system sleep slider values.
1094 getAggressiveness(kPMMinutesToSleep
, &minutesToSleep
);
1095 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
1096 DLOG("aggressiveness changed system %u, display %u\n",
1097 (uint32_t) minutesToSleep
, (uint32_t) minutesToDisplayDim
);
1099 DLOG("idle time -> %ld secs (ena %d)\n",
1100 idleSeconds
, (minutesToSleep
!= 0));
1102 if (0x7fffffff == minutesToSleep
)
1103 minutesToSleep
= idleSeconds
;
1105 // How long to wait before sleeping the system once the displays turns
1106 // off is indicated by 'extraSleepDelay'.
1108 if ( minutesToSleep
> minutesToDisplayDim
) {
1109 extraSleepDelay
= minutesToSleep
- minutesToDisplayDim
;
1112 extraSleepDelay
= 0;
1115 // system sleep timer was disabled, but not anymore.
1116 if ( (sleepSlider
== 0) && (minutesToSleep
!= 0) ) {
1120 changePowerStateToPriv(ON_STATE
);
1123 startIdleSleepTimer( idleSeconds
);
1128 // Start idle sleep timer if wrangler went to sleep
1129 // while system sleep was disabled.
1136 uint32_t minutesSinceDisplaySleep
= 0;
1137 uint32_t sleepDelay
;
1139 clock_get_uptime(&now
);
1140 if (CMP_ABSOLUTETIME(&now
, &wranglerSleepTime
) > 0)
1142 SUB_ABSOLUTETIME(&now
, &wranglerSleepTime
);
1143 absolutetime_to_nanoseconds(now
, &nanos
);
1144 minutesSinceDisplaySleep
= nanos
/ (60000000000ULL);
1147 if (extraSleepDelay
> minutesSinceDisplaySleep
)
1149 sleepDelay
= extraSleepDelay
- minutesSinceDisplaySleep
;
1153 // 1 min idle sleep.
1157 startIdleSleepTimer(sleepDelay
* 60);
1158 DLOG("display slept %u min, set idle timer to %u min\n",
1159 minutesSinceDisplaySleep
, sleepDelay
);
1164 sleepSlider
= minutesToSleep
;
1165 if ( sleepSlider
== 0 ) {
1166 cancelIdleSleepTimer();
1167 // idle sleep is now disabled
1169 // make sure we're powered
1170 patriarch
->wakeSystem();
1175 //******************************************************************************
1176 // setAggressiveness
1178 // Override IOService::setAggressiveness()
1179 //******************************************************************************
1181 IOReturn
IOPMrootDomain::setAggressiveness(
1183 unsigned long value
)
1185 return setAggressiveness( type
, value
, 0 );
1189 * Private setAggressiveness() with an internal options argument.
1191 IOReturn
IOPMrootDomain::setAggressiveness(
1193 unsigned long value
,
1194 IOOptionBits options
)
1196 AggressivesRequest
* entry
;
1197 AggressivesRequest
* request
;
1200 DLOG("setAggressiveness 0x%x = %u, options 0x%x\n",
1201 (uint32_t) type
, (uint32_t) value
, (uint32_t) options
);
1203 request
= IONew(AggressivesRequest
, 1);
1205 return kIOReturnNoMemory
;
1207 memset(request
, 0, sizeof(*request
));
1208 request
->options
= options
;
1209 request
->dataType
= kAggressivesRequestTypeRecord
;
1210 request
->data
.record
.type
= (uint32_t) type
;
1211 request
->data
.record
.value
= (uint32_t) value
;
1215 // Update disk quick spindown flag used by getAggressiveness().
1216 // Never merge requests with quick spindown flags set.
1218 if (options
& kAggressivesOptionQuickSpindownEnable
)
1219 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1220 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1221 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1224 // Coalesce requests with identical aggressives types.
1225 // Deal with callers that calls us too "aggressively".
1227 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1229 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1230 (entry
->data
.record
.type
== type
) &&
1231 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1233 entry
->data
.record
.value
= value
;
1242 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1245 AGGRESSIVES_UNLOCK();
1248 IODelete(request
, AggressivesRequest
, 1);
1250 if (options
& kAggressivesOptionSynchronous
)
1251 handleAggressivesRequests(); // not truly synchronous
1253 thread_call_enter(aggressivesThreadCall
);
1255 return kIOReturnSuccess
;
1259 //******************************************************************************
1260 // getAggressiveness
1262 // Override IOService::setAggressiveness()
1263 // Fetch the aggressiveness factor with the given type.
1264 //******************************************************************************
1266 IOReturn
IOPMrootDomain::getAggressiveness (
1268 unsigned long * outLevel
)
1274 return kIOReturnBadArgument
;
1278 // Disk quick spindown in effect, report value = 1
1280 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1281 (type
== kPMMinutesToSpinDown
))
1283 value
= kAggressivesMinValue
;
1287 // Consult the pending request queue.
1291 AggressivesRequest
* entry
;
1293 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1295 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1296 (entry
->data
.record
.type
== type
) &&
1297 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1299 value
= entry
->data
.record
.value
;
1306 // Consult the backend records.
1308 if (!source
&& aggressivesData
)
1310 AggressivesRecord
* record
;
1313 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1314 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1316 for (i
= 0; i
< count
; i
++, record
++)
1318 if (record
->type
== type
)
1320 value
= record
->value
;
1327 AGGRESSIVES_UNLOCK();
1331 DLOG("getAggressiveness 0x%x = %u, source %d\n",
1332 (uint32_t) type
, value
, source
);
1333 *outLevel
= (unsigned long) value
;
1334 return kIOReturnSuccess
;
1338 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1339 *outLevel
= 0; // default return = 0, driver may not check for error
1340 return kIOReturnInvalid
;
1345 //******************************************************************************
1346 // joinAggressiveness
1348 // Request from IOService to join future aggressiveness broadcasts.
1349 //******************************************************************************
1351 IOReturn
IOPMrootDomain::joinAggressiveness(
1352 IOService
* service
)
1354 AggressivesRequest
* request
;
1356 if (!service
|| (service
== this))
1357 return kIOReturnBadArgument
;
1359 DLOG("joinAggressiveness %s (%p)\n", service
->getName(), service
);
1361 request
= IONew(AggressivesRequest
, 1);
1363 return kIOReturnNoMemory
;
1365 service
->retain(); // released by synchronizeAggressives()
1367 memset(request
, 0, sizeof(*request
));
1368 request
->dataType
= kAggressivesRequestTypeService
;
1369 request
->data
.service
= service
;
1372 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1373 AGGRESSIVES_UNLOCK();
1375 thread_call_enter(aggressivesThreadCall
);
1377 return kIOReturnSuccess
;
1381 //******************************************************************************
1382 // handleAggressivesRequests
1384 // Backend thread processes all incoming aggressiveness requests in the queue.
1385 //******************************************************************************
1388 handleAggressivesFunction(
1389 thread_call_param_t param1
,
1390 thread_call_param_t param2
)
1394 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1398 void IOPMrootDomain::handleAggressivesRequests( void )
1400 AggressivesRecord
* start
;
1401 AggressivesRecord
* record
;
1402 AggressivesRequest
* request
;
1403 queue_head_t joinedQueue
;
1407 bool pingSelf
= false;
1411 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1412 queue_empty(&aggressivesQueue
))
1415 gAggressivesState
|= kAggressivesStateBusy
;
1416 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1417 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1422 queue_init(&joinedQueue
);
1426 // Remove request from the incoming queue in FIFO order.
1427 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1428 switch (request
->dataType
)
1430 case kAggressivesRequestTypeRecord
:
1431 // Update existing record if found.
1433 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1435 if (record
->type
== request
->data
.record
.type
)
1439 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1441 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1444 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1445 kAggressivesRecordFlagModified
);
1446 DLOG("quick spindown accelerated, was %u min\n",
1450 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1452 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1455 record
->flags
|= kAggressivesRecordFlagModified
;
1456 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1457 DLOG("disk spindown restored to %u min\n",
1461 else if (record
->value
!= request
->data
.record
.value
)
1463 record
->value
= request
->data
.record
.value
;
1464 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1467 record
->flags
|= kAggressivesRecordFlagModified
;
1474 // No matching record, append a new record.
1476 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1478 AggressivesRecord newRecord
;
1480 newRecord
.flags
= kAggressivesRecordFlagModified
;
1481 newRecord
.type
= request
->data
.record
.type
;
1482 newRecord
.value
= request
->data
.record
.value
;
1483 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1485 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1486 DLOG("disk spindown accelerated\n");
1489 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1491 // OSData may have switched to another (larger) buffer.
1492 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1493 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1497 // Finished processing the request, release it.
1498 IODelete(request
, AggressivesRequest
, 1);
1501 case kAggressivesRequestTypeService
:
1502 // synchronizeAggressives() will free request.
1503 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1507 panic("bad aggressives request type %x\n", request
->dataType
);
1510 } while (!queue_empty(&aggressivesQueue
));
1512 // Release the lock to perform work, with busy flag set.
1513 if (!queue_empty(&joinedQueue
) || broadcast
)
1515 AGGRESSIVES_UNLOCK();
1516 if (!queue_empty(&joinedQueue
))
1517 synchronizeAggressives(&joinedQueue
, start
, count
);
1519 broadcastAggressives(start
, count
);
1523 // Remove the modified flag from all records.
1524 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1526 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1527 ((record
->type
== kPMMinutesToDim
) ||
1528 (record
->type
== kPMMinutesToSleep
)))
1531 record
->flags
&= ~kAggressivesRecordFlagModified
;
1534 // Check the incoming queue again since new entries may have been
1535 // added while lock was released above.
1537 } while (!queue_empty(&aggressivesQueue
));
1539 gAggressivesState
&= ~kAggressivesStateBusy
;
1542 AGGRESSIVES_UNLOCK();
1544 // Root domain is interested in system and display sleep slider changes.
1545 // Submit a power event to handle those changes on the PM work loop.
1547 if (pingSelf
&& pmPowerStateQueue
) {
1548 pmPowerStateQueue
->submitPowerEvent( kPowerEventAggressivenessChanged
);
1553 //******************************************************************************
1554 // synchronizeAggressives
1556 // Push all known aggressiveness records to one or more IOService.
1557 //******************************************************************************
1559 void IOPMrootDomain::synchronizeAggressives(
1560 queue_head_t
* joinedQueue
,
1561 const AggressivesRecord
* array
,
1564 IOService
* service
;
1565 AggressivesRequest
* request
;
1566 const AggressivesRecord
* record
;
1570 while (!queue_empty(joinedQueue
))
1572 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1573 if (request
->dataType
== kAggressivesRequestTypeService
)
1574 service
= request
->data
.service
;
1578 IODelete(request
, AggressivesRequest
, 1);
1583 if (service
->assertPMThreadCall())
1585 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1587 value
= record
->value
;
1588 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1589 value
= kAggressivesMinValue
;
1591 DLOG("synchronizeAggressives 0x%x = %u to %s\n",
1592 record
->type
, value
, service
->getName());
1593 service
->setAggressiveness(record
->type
, value
);
1595 service
->deassertPMThreadCall();
1597 service
->release(); // retained by joinAggressiveness()
1603 //******************************************************************************
1604 // broadcastAggressives
1606 // Traverse PM tree and call setAggressiveness() for records that have changed.
1607 //******************************************************************************
1609 void IOPMrootDomain::broadcastAggressives(
1610 const AggressivesRecord
* array
,
1613 IORegistryIterator
* iter
;
1614 IORegistryEntry
* entry
;
1615 IOPowerConnection
* connect
;
1616 IOService
* service
;
1617 const AggressivesRecord
* record
;
1621 iter
= IORegistryIterator::iterateOver(
1622 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1628 while ((entry
= iter
->getNextObject()))
1630 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1631 if (!connect
|| !connect
->getReadyFlag())
1634 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1636 if (service
->assertPMThreadCall())
1638 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1640 if (record
->flags
& kAggressivesRecordFlagModified
)
1642 value
= record
->value
;
1643 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1644 value
= kAggressivesMinValue
;
1645 DLOG("broadcastAggressives %x = %u to %s\n",
1646 record
->type
, value
, service
->getName());
1647 service
->setAggressiveness(record
->type
, value
);
1650 service
->deassertPMThreadCall();
1656 while (!entry
&& !iter
->isValid());
1662 //******************************************************************************
1663 // startIdleSleepTimer
1665 //******************************************************************************
1667 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1669 AbsoluteTime deadline
;
1674 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1675 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1676 idleSleepTimerPending
= true;
1677 DLOG("idle timer set for %u seconds\n", inSeconds
);
1682 //******************************************************************************
1683 // cancelIdleSleepTimer
1685 //******************************************************************************
1687 void IOPMrootDomain::cancelIdleSleepTimer( void )
1690 if (idleSleepTimerPending
)
1692 DLOG("idle timer cancelled\n");
1693 thread_call_cancel(extraSleepTimer
);
1694 idleSleepTimerPending
= false;
1699 //******************************************************************************
1700 // idleSleepTimerExpired
1702 //******************************************************************************
1704 static void idleSleepTimerExpired(
1705 thread_call_param_t us
, thread_call_param_t
)
1707 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
1710 static void wakeupClamshellTimerExpired(
1711 thread_call_param_t us
, thread_call_param_t
)
1713 ((IOPMrootDomain
*)us
)->stopIgnoringClamshellEventsDuringWakeup();
1717 //******************************************************************************
1718 // handleSleepTimerExpiration
1720 // The time between the sleep idle timeout and the next longest one has elapsed.
1721 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1722 //******************************************************************************
1724 void IOPMrootDomain::handleSleepTimerExpiration( void )
1726 if (!getPMworkloop()->inGate())
1728 getPMworkloop()->runAction(
1729 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1730 &IOPMrootDomain::handleSleepTimerExpiration
),
1737 DLOG("sleep timer expired\n");
1740 idleSleepTimerPending
= false;
1742 clock_get_uptime(&time
);
1743 if ((AbsoluteTime_to_scalar(&time
) > autoWakeStart
) &&
1744 (AbsoluteTime_to_scalar(&time
) < autoWakeEnd
))
1746 thread_call_enter_delayed(extraSleepTimer
, *((AbsoluteTime
*) &autoWakeEnd
));
1750 // accelerate disk spin down if spin down timer is non-zero
1751 setQuickSpinDownTimeout();
1758 //******************************************************************************
1759 // stopIgnoringClamshellEventsDuringWakeup
1761 //******************************************************************************
1763 void IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup( void )
1765 if (!getPMworkloop()->inGate())
1767 getPMworkloop()->runAction(
1768 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1769 &IOPMrootDomain::stopIgnoringClamshellEventsDuringWakeup
),
1776 // Allow clamshell-induced sleep now
1777 ignoringClamshellOnWake
= false;
1779 // Re-send clamshell event, in case it causes a sleep
1780 if (clamshellIsClosed
)
1781 handlePowerNotification( kLocalEvalClamshellCommand
);
1785 //******************************************************************************
1788 //******************************************************************************
1791 IOReturn
IOPMrootDomain::sleepSystem( void )
1793 return sleepSystemOptions(NULL
);
1797 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
1799 /* sleepSystem is a public function, and may be called by any kernel driver.
1800 * And that's bad - drivers should sleep the system by calling
1801 * receivePowerNotification() instead. Drivers should not use sleepSystem.
1803 * Note that user space app calls to IOPMSleepSystem() will also travel
1804 * this code path and thus be correctly identified as software sleeps.
1807 if (options
&& options
->getObject("OSSwitch"))
1810 // Log specific sleep cause for OS Switch hibernation
1811 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernation
);
1815 return privateSleepSystem( kIOPMSleepReasonSoftware
);
1821 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
1823 static const char * IOPMSleepReasons
[kIOPMSleepReasonMax
] = {
1825 kIOPMClamshellSleepKey
,
1826 kIOPMPowerButtonSleepKey
,
1827 kIOPMSoftwareSleepKey
,
1828 kIOPMOSSwitchHibernationKey
,
1830 kIOPMLowPowerSleepKey
,
1831 kIOPMClamshellSleepKey
,
1832 kIOPMThermalEmergencySleepKey
1834 if ( userDisabledAllSleep
)
1836 LOG("Sleep prevented by user disable\n");
1838 /* Prevent sleep of all kinds if directed to by user space */
1839 return kIOReturnNotPermitted
;
1842 if ( systemBooting
|| systemShutdown
|| !allowSleep
)
1844 LOG("Sleep prevented by SB %d, SS %d, AS %d\n",
1845 systemBooting
, systemShutdown
, allowSleep
);
1847 // Unable to sleep because system is in the process of booting or
1848 // shutting down, or sleep has otherwise been disallowed.
1849 return kIOReturnError
;
1852 // Record sleep cause in IORegistry
1853 lastSleepReason
= sleepReason
;
1854 if (sleepReason
&& (sleepReason
< kIOPMSleepReasonMax
)) {
1855 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[sleepReason
]);
1858 patriarch
->sleepSystem();
1859 return kIOReturnSuccess
;
1863 //******************************************************************************
1866 //******************************************************************************
1868 IOReturn
IOPMrootDomain::shutdownSystem( void )
1870 //patriarch->shutDownSystem();
1871 return kIOReturnUnsupported
;
1875 //******************************************************************************
1878 //******************************************************************************
1880 IOReturn
IOPMrootDomain::restartSystem( void )
1882 //patriarch->restartSystem();
1883 return kIOReturnUnsupported
;
1887 //******************************************************************************
1890 // This overrides powerChangeDone in IOService.
1892 // Menu sleep and idle sleep move us from the ON state to the SLEEP_STATE.
1894 // If we finished going to the SLEEP_STATE, and the platform is capable of
1895 // true sleep, then sleep the kernel. Otherwise switch up to the DOZE_STATE
1896 // which will keep almost everything as off as it can get.
1897 //******************************************************************************
1899 void IOPMrootDomain::powerChangeDone( unsigned long previousState
)
1902 DLOG("PowerChangeDone: %u->%u\n",
1903 (uint32_t) previousState
, (uint32_t) getPowerState());
1905 switch ( getPowerState() ) {
1907 if ( previousState
!= ON_STATE
)
1912 // re-enable this timer for next sleep
1913 cancelIdleSleepTimer();
1914 wranglerTickled
= true;
1917 clock_usec_t microsecs
;
1918 clock_get_calendar_microtime(&secs
, µsecs
);
1920 gIOLastSleepTime
.tv_sec
= secs
;
1921 gIOLastSleepTime
.tv_usec
= microsecs
;
1922 gIOLastWakeTime
.tv_sec
= 0;
1923 gIOLastWakeTime
.tv_usec
= 0;
1926 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
1928 tracePoint(kIOPMTracePointSystemHibernatePhase
);
1930 IOHibernateSystemHasSlept();
1932 evaluateSystemSleepPolicyFinal();
1934 LOG("System Sleep\n");
1937 tracePoint(kIOPMTracePointSystemSleepPlatformPhase
);
1939 getPlatform()->sleepKernel();
1941 // The CPU(s) are off at this point. When they're awakened by CPU interrupt,
1942 // code will resume execution here.
1944 // Now we're waking...
1945 tracePoint(kIOPMTracePointSystemWakeDriversPhase
);
1948 IOHibernateSystemWake();
1951 // sleep transition complete
1952 gSleepOrShutdownPending
= 0;
1954 // trip the reset of the calendar clock
1955 clock_wakeup_calendar();
1957 // get us some power
1958 patriarch
->wakeSystem();
1960 // Set indicator if UUID was set - allow it to be cleared.
1961 if (getProperty(kIOPMSleepWakeUUIDKey
))
1962 gSleepWakeUUIDIsSet
= true;
1964 #if !ROOT_DOMAIN_RUN_STATES
1965 tellClients(kIOMessageSystemWillPowerOn
, clientMessageFilter
);
1969 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
1973 getPlatform()->PMLog(kIOPMrootDomainClass
, kPMLogSystemWake
, 0, 0);
1974 lowBatteryCondition
= false;
1977 // tell the tree we're waking
1982 #if defined(__i386__) || defined(__x86_64__)
1983 sleepTimerMaintenance
= false;
1984 #if ROOT_DOMAIN_RUN_STATES
1985 OSString
* wakeType
= OSDynamicCast(
1986 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
1987 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
1989 lowBatteryCondition
= true;
1990 updateRunState(kRStateMaintenance
);
1991 wranglerTickled
= false;
1993 else if (wakeType
&& !hibernateAborted
&& wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
1995 sleepTimerMaintenance
= true;
1996 updateRunState(kRStateMaintenance
);
1997 wranglerTickled
= false;
1999 else if (wakeType
&& !hibernateAborted
&& wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2001 updateRunState(kRStateMaintenance
);
2002 wranglerTickled
= false;
2005 #endif /* ROOT_DOMAIN_RUN_STATES */
2007 updateRunState(kRStateNormal
);
2010 #else /* !__i386__ && !__x86_64__ */
2011 // stay awake for at least 30 seconds
2012 startIdleSleepTimer(30);
2016 changePowerStateToPriv(ON_STATE
);
2018 updateRunState(kRStateNormal
);
2020 // allow us to step up a power state
2021 patriarch
->sleepToDoze();
2023 // ignore children's request for higher power during doze.
2024 changePowerStateWithOverrideTo(DOZE_STATE
);
2029 if ( previousState
!= DOZE_STATE
)
2031 LOG("System Doze\n");
2033 // re-enable this timer for next sleep
2034 cancelIdleSleepTimer();
2035 gSleepOrShutdownPending
= 0;
2037 // Invalidate prior activity tickles to allow wake from doze.
2038 if (wrangler
) wrangler
->changePowerStateTo(0);
2041 #if ROOT_DOMAIN_RUN_STATES
2043 // SLEEP -> ON (Maintenance)
2044 // Go back to sleep, unless cancelled by a HID event.
2046 if ((previousState
== SLEEP_STATE
) &&
2047 (runStateIndex
== kRStateMaintenance
) &&
2050 if (lowBatteryCondition
)
2052 lastSleepReason
= kIOPMSleepReasonLowPower
;
2053 setProperty(kRootDomainSleepReasonKey
, kIOPMLowPowerSleepKey
);
2057 lastSleepReason
= kIOPMSleepReasonMaintenance
;
2058 setProperty(kRootDomainSleepReasonKey
, kIOPMMaintenanceSleepKey
);
2060 changePowerStateWithOverrideTo(SLEEP_STATE
);
2063 // ON -> ON triggered by R-state changes.
2065 if ((previousState
== ON_STATE
) &&
2066 (runStateIndex
!= nextRunStateIndex
) &&
2067 (nextRunStateIndex
< kRStateCount
))
2069 LOG("R-state changed %u->%u\n",
2070 runStateIndex
, nextRunStateIndex
);
2071 updateRunState(nextRunStateIndex
);
2073 DLOG("kIOMessageSystemHasPoweredOn (%u)\n",
2074 gMessageClientType
);
2075 tellClients(kIOMessageSystemHasPoweredOn
, clientMessageFilter
);
2079 #endif /* ROOT_DOMAIN_RUN_STATES */
2084 //******************************************************************************
2087 // The Display Wrangler calls here when it switches to its highest state.
2088 // If the system is currently dozing, allow it to wake by making sure the
2089 // parent is providing power.
2090 //******************************************************************************
2092 void IOPMrootDomain::wakeFromDoze( void )
2094 if ( getPowerState() == DOZE_STATE
)
2096 tracePoint(kIOPMTracePointSystemWakeDriversPhase
);
2097 changePowerStateToPriv(ON_STATE
);
2098 patriarch
->wakeSystem();
2103 //******************************************************************************
2106 // Adds a new feature to the supported features dictionary
2107 //******************************************************************************
2109 void IOPMrootDomain::publishFeature( const char * feature
)
2111 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
2115 //******************************************************************************
2116 // publishFeature (with supported power source specified)
2118 // Adds a new feature to the supported features dictionary
2119 //******************************************************************************
2121 void IOPMrootDomain::publishFeature(
2122 const char *feature
,
2123 uint32_t supportedWhere
,
2124 uint32_t *uniqueFeatureID
)
2126 static uint16_t next_feature_id
= 500;
2128 OSNumber
*new_feature_data
= NULL
;
2129 OSNumber
*existing_feature
= NULL
;
2130 OSArray
*existing_feature_arr
= NULL
;
2131 OSObject
*osObj
= NULL
;
2132 uint32_t feature_value
= 0;
2134 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
2136 if(!supportedWhere
) {
2137 // Feature isn't supported anywhere!
2141 if(next_feature_id
> 5000) {
2142 // Far, far too many features!
2146 if(featuresDictLock
) IOLockLock(featuresDictLock
);
2148 OSDictionary
*features
=
2149 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
2151 // Create new features dict if necessary
2152 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
2153 features
= OSDictionary::withDictionary(features
);
2155 features
= OSDictionary::withCapacity(1);
2158 // Create OSNumber to track new feature
2160 next_feature_id
+= 1;
2161 if( uniqueFeatureID
) {
2162 // We don't really mind if the calling kext didn't give us a place
2163 // to stash their unique id. Many kexts don't plan to unload, and thus
2164 // have no need to remove themselves later.
2165 *uniqueFeatureID
= next_feature_id
;
2168 feature_value
= (uint32_t)next_feature_id
;
2169 feature_value
<<= 16;
2170 feature_value
+= supportedWhere
;
2172 new_feature_data
= OSNumber::withNumber(
2173 (unsigned long long)feature_value
, 32);
2175 // Does features object already exist?
2176 if( (osObj
= features
->getObject(feature
)) )
2178 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
2180 // We need to create an OSArray to hold the now 2 elements.
2181 existing_feature_arr
= OSArray::withObjects(
2182 (const OSObject
**)&existing_feature
, 1, 2);
2183 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
2185 // Add object to existing array
2186 existing_feature_arr
= OSArray::withArray(
2187 existing_feature_arr
,
2188 existing_feature_arr
->getCount() + 1);
2191 if (existing_feature_arr
)
2193 existing_feature_arr
->setObject(new_feature_data
);
2194 features
->setObject(feature
, existing_feature_arr
);
2195 existing_feature_arr
->release();
2196 existing_feature_arr
= 0;
2199 // The easy case: no previously existing features listed. We simply
2200 // set the OSNumber at key 'feature' and we're on our way.
2201 features
->setObject(feature
, new_feature_data
);
2204 new_feature_data
->release();
2206 setProperty(kRootDomainSupportedFeatures
, features
);
2208 features
->release();
2210 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
2212 // Notify EnergySaver and all those in user space so they might
2213 // re-populate their feature specific UI
2214 if(pmPowerStateQueue
) {
2215 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
2220 //******************************************************************************
2221 // removePublishedFeature
2223 // Removes previously published feature
2224 //******************************************************************************
2226 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
2228 IOReturn ret
= kIOReturnError
;
2229 uint32_t feature_value
= 0;
2230 uint16_t feature_id
= 0;
2231 bool madeAChange
= false;
2233 OSSymbol
*dictKey
= NULL
;
2234 OSCollectionIterator
*dictIterator
= NULL
;
2235 OSArray
*arrayMember
= NULL
;
2236 OSNumber
*numberMember
= NULL
;
2237 OSObject
*osObj
= NULL
;
2238 OSNumber
*osNum
= NULL
;
2239 OSArray
*arrayMemberCopy
;
2241 if(featuresDictLock
) IOLockLock(featuresDictLock
);
2243 OSDictionary
*features
=
2244 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
2246 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
2248 // Any modifications to the dictionary are made to the copy to prevent
2249 // races & crashes with userland clients. Dictionary updated
2250 // automically later.
2251 features
= OSDictionary::withDictionary(features
);
2254 ret
= kIOReturnNotFound
;
2258 // We iterate 'features' dictionary looking for an entry tagged
2259 // with 'removeFeatureID'. If found, we remove it from our tracking
2260 // structures and notify the OS via a general interest message.
2262 dictIterator
= OSCollectionIterator::withCollection(features
);
2267 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
2269 osObj
= features
->getObject(dictKey
);
2271 // Each Feature is either tracked by an OSNumber
2272 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
2274 feature_value
= numberMember
->unsigned32BitValue();
2275 feature_id
= (uint16_t)(feature_value
>> 16);
2277 if( feature_id
== (uint16_t)removeFeatureID
)
2280 features
->removeObject(dictKey
);
2285 // Or tracked by an OSArray of OSNumbers
2286 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
2288 unsigned int arrayCount
= arrayMember
->getCount();
2290 for(unsigned int i
=0; i
<arrayCount
; i
++)
2292 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
2297 feature_value
= osNum
->unsigned32BitValue();
2298 feature_id
= (uint16_t)(feature_value
>> 16);
2300 if( feature_id
== (uint16_t)removeFeatureID
)
2303 if( 1 == arrayCount
) {
2304 // If the array only contains one element, remove
2306 features
->removeObject(dictKey
);
2308 // Otherwise remove the element from a copy of the array.
2309 arrayMemberCopy
= OSArray::withArray(arrayMember
);
2310 if (arrayMemberCopy
)
2312 arrayMemberCopy
->removeObject(i
);
2313 features
->setObject(dictKey
, arrayMemberCopy
);
2314 arrayMemberCopy
->release();
2325 dictIterator
->release();
2329 ret
= kIOReturnSuccess
;
2331 setProperty(kRootDomainSupportedFeatures
, features
);
2333 // Notify EnergySaver and all those in user space so they might
2334 // re-populate their feature specific UI
2335 if(pmPowerStateQueue
) {
2336 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
2339 ret
= kIOReturnNotFound
;
2343 if(features
) features
->release();
2344 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
2349 //******************************************************************************
2350 // announcePowerSourceChange
2352 // Notifies "interested parties" that the battery state has changed
2353 //******************************************************************************
2355 void IOPMrootDomain::announcePowerSourceChange( void )
2358 IORegistryEntry
*_batteryRegEntry
= (IORegistryEntry
*) getProperty("BatteryEntry");
2360 // (if possible) re-publish power source state under IOPMrootDomain;
2361 // only do so if the battery controller publishes an IOResource
2362 // defining battery location. Called from ApplePMU battery driver.
2364 if(_batteryRegEntry
)
2367 batt_info
= (OSArray
*) _batteryRegEntry
->getProperty(kIOBatteryInfoKey
);
2369 setProperty(kIOBatteryInfoKey
, batt_info
);
2375 //******************************************************************************
2376 // setPMSetting (private)
2378 // Internal helper to relay PM settings changes from user space to individual
2379 // drivers. Should be called only by IOPMrootDomain::setProperties.
2380 //******************************************************************************
2382 IOReturn
IOPMrootDomain::setPMSetting(
2383 const OSSymbol
*type
,
2386 OSArray
*arr
= NULL
;
2387 PMSettingObject
*p_obj
= NULL
;
2391 if(NULL
== type
) return kIOReturnBadArgument
;
2393 IORecursiveLockLock(settingsCtrlLock
);
2395 fPMSettingsDict
->setObject(type
, obj
);
2397 arr
= (OSArray
*)settingsCallbacks
->getObject(type
);
2398 if(NULL
== arr
) goto exit
;
2399 count
= arr
->getCount();
2400 for(i
=0; i
<count
; i
++) {
2401 p_obj
= (PMSettingObject
*)OSDynamicCast(PMSettingObject
, arr
->getObject(i
));
2402 if(p_obj
) p_obj
->setPMSetting(type
, obj
);
2406 IORecursiveLockUnlock(settingsCtrlLock
);
2407 return kIOReturnSuccess
;
2411 //******************************************************************************
2412 // copyPMSetting (public)
2414 // Allows kexts to safely read setting values, without being subscribed to
2416 //******************************************************************************
2418 OSObject
* IOPMrootDomain::copyPMSetting(
2419 OSSymbol
*whichSetting
)
2421 OSObject
*obj
= NULL
;
2423 if(!whichSetting
) return NULL
;
2425 IORecursiveLockLock(settingsCtrlLock
);
2426 obj
= fPMSettingsDict
->getObject(whichSetting
);
2430 IORecursiveLockUnlock(settingsCtrlLock
);
2436 //******************************************************************************
2437 // registerPMSettingController (public)
2439 // direct wrapper to registerPMSettingController with uint32_t power source arg
2440 //******************************************************************************
2442 IOReturn
IOPMrootDomain::registerPMSettingController(
2443 const OSSymbol
* settings
[],
2444 IOPMSettingControllerCallback func
,
2449 return registerPMSettingController(
2451 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
2452 func
, target
, refcon
, handle
);
2456 //******************************************************************************
2457 // registerPMSettingController (public)
2459 // Kexts may register for notifications when a particular setting is changed.
2460 // A list of settings is available in IOPM.h.
2462 // * settings - An OSArray containing OSSymbols. Caller should populate this
2463 // array with a list of settings caller wants notifications from.
2464 // * func - A C function callback of the type IOPMSettingControllerCallback
2465 // * target - caller may provide an OSObject *, which PM will pass as an
2466 // target to calls to "func"
2467 // * refcon - caller may provide an void *, which PM will pass as an
2468 // argument to calls to "func"
2469 // * handle - This is a return argument. We will populate this pointer upon
2470 // call success. Hold onto this and pass this argument to
2471 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
2473 // kIOReturnSuccess on success
2474 //******************************************************************************
2476 IOReturn
IOPMrootDomain::registerPMSettingController(
2477 const OSSymbol
* settings
[],
2478 uint32_t supportedPowerSources
,
2479 IOPMSettingControllerCallback func
,
2484 PMSettingObject
*pmso
= NULL
;
2485 OSArray
*list
= NULL
;
2486 IOReturn ret
= kIOReturnSuccess
;
2489 if( NULL
== settings
||
2493 return kIOReturnBadArgument
;
2496 pmso
= PMSettingObject::pmSettingObject(
2497 (IOPMrootDomain
*)this, func
, target
,
2498 refcon
, supportedPowerSources
, settings
);
2501 ret
= kIOReturnInternalError
;
2502 goto bail_no_unlock
;
2505 IORecursiveLockLock(settingsCtrlLock
);
2506 for(i
=0; settings
[i
]; i
++)
2508 list
= (OSArray
*)settingsCallbacks
->getObject(settings
[i
]);
2510 // New array of callbacks for this setting
2511 list
= OSArray::withCapacity(1);
2512 settingsCallbacks
->setObject(settings
[i
], list
);
2516 // Add caller to the callback list
2517 list
->setObject(pmso
);
2520 IORecursiveLockUnlock(settingsCtrlLock
);
2522 ret
= kIOReturnSuccess
;
2524 // Track this instance by its OSData ptr from now on
2528 if(kIOReturnSuccess
!= ret
)
2530 // Error return case
2531 if(pmso
) pmso
->release();
2532 if(handle
) *handle
= NULL
;
2538 //******************************************************************************
2539 // sleepOnClamshellClosed
2541 // contains the logic to determine if the system should sleep when the clamshell
2543 //******************************************************************************
2545 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2547 DLOG("clamshell state %d, EX %d, IG %d, IW %d, DT %d, AC %d\n",
2548 clamshellIsClosed
, clamshellExists
, ignoringClamshell
,
2549 ignoringClamshellOnWake
, desktopMode
, acAdaptorConnected
);
2551 return ( !ignoringClamshell
2552 && !ignoringClamshellOnWake
2553 && !(desktopMode
&& acAdaptorConnected
) );
2556 void IOPMrootDomain::sendClientClamshellNotification( void )
2558 /* Only broadcast clamshell alert if clamshell exists. */
2559 if (!clamshellExists
)
2562 setProperty(kAppleClamshellStateKey
,
2563 clamshellIsClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
2565 setProperty(kAppleClamshellCausesSleepKey
,
2566 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
2568 /* Argument to message is a bitfiel of
2569 * ( kClamshellStateBit | kClamshellSleepBit )
2571 messageClients(kIOPMMessageClamshellStateChange
,
2572 (void *) ( (clamshellIsClosed
? kClamshellStateBit
: 0)
2573 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
2577 //******************************************************************************
2578 // informCPUStateChange
2580 // Call into PM CPU code so that CPU power savings may dynamically adjust for
2581 // running on battery, with the lid closed, etc.
2583 // informCPUStateChange is a no-op on non x86 systems
2584 // only x86 has explicit support in the IntelCPUPowerManagement kext
2585 //******************************************************************************
2587 void IOPMrootDomain::informCPUStateChange(
2591 #if defined(__i386__) || defined(__x86_64__)
2593 pmioctlVariableInfo_t varInfoStruct
;
2595 const char *varNameStr
= NULL
;
2596 int32_t *varIndex
= NULL
;
2598 if (kInformAC
== type
) {
2599 varNameStr
= kIOPMRootDomainBatPowerCString
;
2600 varIndex
= &idxPMCPULimitedPower
;
2601 } else if (kInformLid
== type
) {
2602 varNameStr
= kIOPMRootDomainLidCloseCString
;
2603 varIndex
= &idxPMCPUClamshell
;
2608 // Set the new value!
2609 // pmCPUControl will assign us a new ID if one doesn't exist yet
2610 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
2611 varInfoStruct
.varID
= *varIndex
;
2612 varInfoStruct
.varType
= vBool
;
2613 varInfoStruct
.varInitValue
= value
;
2614 varInfoStruct
.varCurValue
= value
;
2615 strncpy( (char *)varInfoStruct
.varName
,
2616 (const char *)varNameStr
,
2617 strlen(varNameStr
) + 1 );
2620 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
2622 // pmCPU only assigns numerical id's when a new varName is specified
2624 && (*varIndex
== kCPUUnknownIndex
))
2626 // pmCPUControl has assigned us a new variable ID.
2627 // Let's re-read the structure we just SET to learn that ID.
2628 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
2632 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
2633 *varIndex
= varInfoStruct
.varID
;
2639 #endif /* __i386__ || __x86_64__ */
2645 //******************************************************************************
2646 // evaluateSystemSleepPolicy
2647 //******************************************************************************
2649 struct IOPMSystemSleepPolicyEntry
2651 uint32_t factorMask
;
2652 uint32_t factorBits
;
2653 uint32_t sleepFlags
;
2654 uint32_t wakeEvents
;
2657 struct IOPMSystemSleepPolicyTable
2659 uint8_t signature
[4];
2661 uint16_t entryCount
;
2662 IOPMSystemSleepPolicyEntry entries
[];
2666 kIOPMSleepFactorSleepTimerWake
= 0x00000001,
2667 kIOPMSleepFactorLidOpen
= 0x00000002,
2668 kIOPMSleepFactorACPower
= 0x00000004,
2669 kIOPMSleepFactorLowBattery
= 0x00000008,
2670 kIOPMSleepFactorDeepSleepNoDelay
= 0x00000010,
2671 kIOPMSleepFactorDeepSleepDemand
= 0x00000020,
2672 kIOPMSleepFactorDeepSleepDisable
= 0x00000040,
2673 kIOPMSleepFactorUSBExternalDevice
= 0x00000080,
2674 kIOPMSleepFactorBluetoothHIDDevice
= 0x00000100,
2675 kIOPMSleepFactorExternalMediaMounted
= 0x00000200,
2676 kIOPMSleepFactorDriverAssertBit5
= 0x00000400,
2677 kIOPMSleepFactorDriverAssertBit6
= 0x00000800,
2678 kIOPMSleepFactorDriverAssertBit7
= 0x00001000
2681 bool IOPMrootDomain::evaluateSystemSleepPolicy( IOPMSystemSleepParameters
* p
)
2683 const IOPMSystemSleepPolicyTable
* pt
;
2684 OSObject
* prop
= 0;
2685 OSData
* policyData
;
2686 uint32_t currentFactors
;
2687 uint32_t deepSleepDelay
= 0;
2688 bool success
= false;
2690 if (getProperty(kIOPMDeepSleepEnabledKey
) != kOSBooleanTrue
)
2693 getSleepOption(kIOPMDeepSleepDelayKey
, &deepSleepDelay
);
2695 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
2699 policyData
= OSDynamicCast(OSData
, prop
);
2701 (policyData
->getLength() < sizeof(IOPMSystemSleepPolicyTable
)))
2706 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
2707 if ((pt
->signature
[0] != 'S') ||
2708 (pt
->signature
[1] != 'L') ||
2709 (pt
->signature
[2] != 'P') ||
2710 (pt
->signature
[3] != 'T') ||
2711 (pt
->version
!= 1) ||
2712 (pt
->entryCount
== 0))
2717 if ((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
2718 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
))
2724 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
2725 kIOPMDriverAssertionLevelOff
)
2726 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
2727 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
2728 kIOPMDriverAssertionLevelOff
)
2729 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
2730 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
2731 kIOPMDriverAssertionLevelOff
)
2732 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
2733 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
2734 kIOPMDriverAssertionLevelOff
)
2735 currentFactors
|= kIOPMSleepFactorDriverAssertBit5
;
2736 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit6
) !=
2737 kIOPMDriverAssertionLevelOff
)
2738 currentFactors
|= kIOPMSleepFactorDriverAssertBit6
;
2739 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit7
) !=
2740 kIOPMDriverAssertionLevelOff
)
2741 currentFactors
|= kIOPMSleepFactorDriverAssertBit7
;
2742 if (0 == deepSleepDelay
)
2743 currentFactors
|= kIOPMSleepFactorDeepSleepNoDelay
;
2744 if (!clamshellIsClosed
)
2745 currentFactors
|= kIOPMSleepFactorLidOpen
;
2746 if (acAdaptorConnected
)
2747 currentFactors
|= kIOPMSleepFactorACPower
;
2748 if (lowBatteryCondition
)
2749 currentFactors
|= kIOPMSleepFactorLowBattery
;
2750 if (sleepTimerMaintenance
)
2751 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
2754 if ((hibernateMode
& kIOHibernateModeOn
) == 0)
2755 currentFactors
|= kIOPMSleepFactorDeepSleepDisable
;
2756 else if ((hibernateMode
& kIOHibernateModeSleep
) == 0)
2757 currentFactors
|= kIOPMSleepFactorDeepSleepDemand
;
2759 DLOG("Sleep policy %u entries, current factors 0x%x\n",
2760 pt
->entryCount
, currentFactors
);
2762 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
2764 const IOPMSystemSleepPolicyEntry
* policyEntry
= &pt
->entries
[i
];
2766 DLOG("factor mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x\n",
2767 policyEntry
->factorMask
, policyEntry
->factorBits
,
2768 policyEntry
->sleepFlags
, policyEntry
->wakeEvents
);
2770 if ((currentFactors
^ policyEntry
->factorBits
) & policyEntry
->factorMask
)
2771 continue; // mismatch, try next
2776 p
->sleepFlags
= policyEntry
->sleepFlags
;
2778 p
->wakeEvents
= policyEntry
->wakeEvents
;
2779 if (p
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
2781 p
->sleepTimer
= deepSleepDelay
;
2785 DLOG("matched policy entry %u\n", i
);
2797 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
2799 IOPMSystemSleepParameters params
;
2801 // Evaluate sleep policy before driver sleep phase.
2803 DLOG("%s\n", __FUNCTION__
);
2804 removeProperty(kIOPMSystemSleepParametersKey
);
2806 hibernateDisabled
= false;
2808 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
2810 if (!hibernateNoDefeat
&&
2811 evaluateSystemSleepPolicy(¶ms
) &&
2812 ((params
.sleepFlags
& kIOPMSleepFlagHibernate
) == 0))
2814 hibernateDisabled
= true;
2818 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
2820 IOPMSystemSleepParameters params
;
2821 OSData
* paramsData
;
2823 // Evaluate sleep policy after drivers but before platform sleep.
2825 DLOG("%s\n", __FUNCTION__
);
2827 if (evaluateSystemSleepPolicy(¶ms
))
2829 if ((hibernateDisabled
|| hibernateAborted
) &&
2830 (params
.sleepFlags
& kIOPMSleepFlagHibernate
))
2832 // Should hibernate but unable to or aborted.
2833 // Arm timer for a short sleep and retry or wake fully.
2835 params
.sleepFlags
&= ~kIOPMSleepFlagHibernate
;
2836 params
.sleepFlags
|= kIOPMSleepFlagSleepTimerEnable
;
2837 params
.sleepTimer
= 1;
2838 hibernateNoDefeat
= true;
2839 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
2840 params
.sleepTimer
, hibernateDisabled
, hibernateAborted
);
2843 hibernateNoDefeat
= false;
2845 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
2848 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
2849 paramsData
->release();
2852 if (params
.sleepFlags
& kIOPMSleepFlagHibernate
)
2855 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
2860 bool IOPMrootDomain::getHibernateSettings(
2861 uint32_t * hibernateMode
,
2862 uint32_t * hibernateFreeRatio
,
2863 uint32_t * hibernateFreeTime
)
2865 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateMode
);
2866 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
2867 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
2868 if (hibernateDisabled
)
2870 DLOG("hibernateMode 0x%x\n", *hibernateMode
);
2874 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
2876 OSObject
* optionsProp
;
2877 OSDictionary
* optionsDict
;
2882 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
2883 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
2887 obj
= optionsDict
->getObject(key
);
2888 if (obj
) obj
->retain();
2892 obj
= copyProperty(key
);
2894 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)))
2896 *option
= num
->unsigned32BitValue();
2903 optionsProp
->release();
2907 #endif /* HIBERNATION */
2910 //******************************************************************************
2911 // dispatchPowerEvent
2913 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
2914 //******************************************************************************
2916 void IOPMrootDomain::dispatchPowerEvent(
2917 uint32_t event
, void * arg0
, uint64_t arg1
)
2919 DLOG("power event %u args %p 0x%llx\n", event
, arg0
, arg1
);
2924 case kPowerEventFeatureChanged
:
2925 messageClients(kIOPMMessageFeatureChange
, this);
2928 case kPowerEventReceivedPowerNotification
:
2929 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
2932 case kPowerEventSystemBootCompleted
:
2935 systemBooting
= false;
2938 // If lid is closed, re-send lid closed notification
2939 // now that booting is complete.
2940 if( clamshellIsClosed
)
2942 handlePowerNotification(kLocalEvalClamshellCommand
);
2947 case kPowerEventSystemShutdown
:
2948 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
2950 /* We set systemShutdown = true during shutdown
2951 to prevent sleep at unexpected times while loginwindow is trying
2952 to shutdown apps and while the OS is trying to transition to
2955 Set to true during shutdown, as soon as loginwindow shows
2956 the "shutdown countdown dialog", through individual app
2957 termination, and through black screen kernel shutdown.
2959 LOG("systemShutdown true\n");
2960 systemShutdown
= true;
2963 A shutdown was initiated, but then the shutdown
2964 was cancelled, clearing systemShutdown to false here.
2966 LOG("systemShutdown false\n");
2967 systemShutdown
= false;
2971 case kPowerEventUserDisabledSleep
:
2972 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
2975 #if ROOT_DOMAIN_RUN_STATES
2976 case kPowerEventConfigdRegisteredInterest
:
2977 if (gConfigdNotifier
)
2979 gConfigdNotifier
->release();
2980 gConfigdNotifier
= 0;
2984 gConfigdNotifier
= (IONotifier
*) arg0
;
2989 case kPowerEventAggressivenessChanged
:
2990 aggressivenessChanged();
2993 case kPowerEventAssertionCreate
:
2995 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
2999 case kPowerEventAssertionRelease
:
3001 pmAssertions
->handleReleaseAssertion(arg1
);
3005 case kPowerEventAssertionSetLevel
:
3007 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
3014 //******************************************************************************
3015 // systemPowerEventOccurred
3017 // The power controller is notifying us of a hardware-related power management
3018 // event that we must handle.
3020 // systemPowerEventOccurred covers the same functionality that
3021 // receivePowerNotification does; it simply provides a richer API for conveying
3022 // more information.
3023 //******************************************************************************
3025 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
3026 const OSSymbol
*event
,
3029 IOReturn attempt
= kIOReturnSuccess
;
3030 OSNumber
*newNumber
= NULL
;
3033 return kIOReturnBadArgument
;
3035 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
3037 return kIOReturnInternalError
;
3039 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
3041 newNumber
->release();
3046 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
3047 const OSSymbol
*event
,
3050 OSDictionary
*thermalsDict
= NULL
;
3051 bool shouldUpdate
= true;
3053 if (!event
|| !value
)
3054 return kIOReturnBadArgument
;
3057 // We reuse featuresDict Lock because it already exists and guards
3058 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
3059 // of stepping on that lock.
3060 if (featuresDictLock
) IOLockLock(featuresDictLock
);
3062 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
3064 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
3065 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
3067 thermalsDict
= OSDictionary::withCapacity(1);
3070 if (!thermalsDict
) {
3071 shouldUpdate
= false;
3075 thermalsDict
->setObject (event
, value
);
3077 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
3079 thermalsDict
->release();
3083 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
3086 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
3088 return kIOReturnSuccess
;
3092 //******************************************************************************
3093 // receivePowerNotification
3095 // The power controller is notifying us of a hardware-related power management
3096 // event that we must handle. This may be a result of an 'environment' interrupt
3097 // from the power mgt micro.
3098 //******************************************************************************
3100 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
3102 pmPowerStateQueue
->submitPowerEvent(
3103 kPowerEventReceivedPowerNotification
, (void *) msg
);
3104 return kIOReturnSuccess
;
3107 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
3109 bool eval_clamshell
= false;
3114 * Local (IOPMrootDomain only) eval clamshell command
3116 if (msg
& kLocalEvalClamshellCommand
)
3118 eval_clamshell
= true;
3124 if (msg
& kIOPMOverTemp
)
3126 LOG("PowerManagement emergency overtemp signal. Going to sleep!");
3127 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
3132 * PMU Processor Speed Change
3134 if (msg
& kIOPMProcessorSpeedChange
)
3136 IOService
*pmu
= waitForService(serviceMatching("ApplePMU"));
3137 pmu
->callPlatformFunction("prepareForSleep", false, 0, 0, 0, 0);
3138 getPlatform()->sleepKernel();
3139 pmu
->callPlatformFunction("recoverFromSleep", false, 0, 0, 0, 0);
3146 if (msg
& kIOPMSleepNow
)
3148 privateSleepSystem (kIOPMSleepReasonSoftware
);
3154 if (msg
& kIOPMPowerEmergency
)
3156 lowBatteryCondition
= true;
3157 privateSleepSystem (kIOPMSleepReasonLowPower
);
3163 if (msg
& kIOPMClamshellOpened
)
3165 // Received clamshel open message from clamshell controlling driver
3166 // Update our internal state and tell general interest clients
3167 clamshellIsClosed
= false;
3168 clamshellExists
= true;
3170 if (msg
& kIOPMSetValue
)
3176 informCPUStateChange(kInformLid
, 0);
3178 // Tell general interest clients
3179 sendClientClamshellNotification();
3181 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
3182 || (lastSleepReason
== kIOPMSleepReasonIdle
)
3183 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
3184 if (aborting
) userActivityCount
++;
3185 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
3190 * Send the clamshell interest notification since the lid is closing.
3192 if (msg
& kIOPMClamshellClosed
)
3194 // Received clamshel open message from clamshell controlling driver
3195 // Update our internal state and tell general interest clients
3196 clamshellIsClosed
= true;
3197 clamshellExists
= true;
3200 informCPUStateChange(kInformLid
, 1);
3202 // Tell general interest clients
3203 sendClientClamshellNotification();
3205 // And set eval_clamshell = so we can attempt
3206 eval_clamshell
= true;
3210 * Set Desktop mode (sent from graphics)
3212 * -> reevaluate lid state
3214 if (msg
& kIOPMSetDesktopMode
)
3216 desktopMode
= (0 != (msg
& kIOPMSetValue
));
3217 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
3219 sendClientClamshellNotification();
3221 // Re-evaluate the lid state
3222 if( clamshellIsClosed
)
3224 eval_clamshell
= true;
3229 * AC Adaptor connected
3231 * -> reevaluate lid state
3233 if (msg
& kIOPMSetACAdaptorConnected
)
3235 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
3236 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
3239 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
3241 // Tell BSD if AC is connected
3242 // 0 == external power source; 1 == on battery
3243 post_sys_powersource(acAdaptorConnected
? 0:1);
3245 sendClientClamshellNotification();
3247 // Re-evaluate the lid state
3248 if( clamshellIsClosed
)
3250 eval_clamshell
= true;
3255 * Enable Clamshell (external display disappear)
3257 * -> reevaluate lid state
3259 if (msg
& kIOPMEnableClamshell
)
3261 // Re-evaluate the lid state
3262 // System should sleep on external display disappearance
3263 // in lid closed operation.
3264 if( clamshellIsClosed
&& (true == ignoringClamshell
) )
3266 eval_clamshell
= true;
3269 ignoringClamshell
= false;
3271 sendClientClamshellNotification();
3275 * Disable Clamshell (external display appeared)
3276 * We don't bother re-evaluating clamshell state. If the system is awake,
3277 * the lid is probably open.
3279 if (msg
& kIOPMDisableClamshell
)
3281 ignoringClamshell
= true;
3283 sendClientClamshellNotification();
3287 * Evaluate clamshell and SLEEP if appropiate
3289 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
3294 privateSleepSystem (kIOPMSleepReasonClamshell
);
3300 if (msg
& kIOPMPowerButton
)
3302 // toggle state of sleep/wake
3304 if ( getPowerState() == DOZE_STATE
)
3307 // yes, tell the tree we're waking
3310 // wake the Display Wrangler
3314 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
3315 // Check that power button sleep is enabled
3317 if( kOSBooleanTrue
!= getProperty(pbs
))
3318 privateSleepSystem (kIOPMSleepReasonPowerButton
);
3327 if ( (msg
& kIOPMAllowSleep
) && !allowSleep
)
3337 if (msg
& kIOPMPreventSleep
) {
3340 if ( getPowerState() == DOZE_STATE
) {
3342 // yes, tell the tree we're waking
3346 // wake the Display Wrangler
3350 // make sure we have power to clamp
3351 patriarch
->wakeSystem();
3357 //******************************************************************************
3358 // getSleepSupported
3360 //******************************************************************************
3362 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3364 return( platformSleepSupport
);
3368 //******************************************************************************
3369 // setSleepSupported
3371 //******************************************************************************
3373 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3375 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3376 OSBitOrAtomic(flags
, &platformSleepSupport
);
3380 //******************************************************************************
3381 // requestPowerDomainState
3383 // The root domain intercepts this call to the superclass.
3384 // Called on the PM work loop thread.
3386 // If the clamp bit is not set in the desire, then the child doesn't need the power
3387 // state it's requesting; it just wants it. The root ignores desires but not needs.
3388 // If the clamp bit is not set, the root takes it that the child can tolerate no
3389 // power and interprets the request accordingly. If all children can thus tolerate
3390 // no power, we are on our way to idle sleep.
3391 //******************************************************************************
3393 IOReturn
IOPMrootDomain::requestPowerDomainState (
3394 IOPMPowerFlags desiredFlags
,
3395 IOPowerConnection
* whichChild
,
3396 unsigned long specification
)
3400 IOPowerConnection
*connection
;
3401 IOPMPowerFlags powerRequestFlag
= 0;
3402 IOPMPowerFlags editedDesire
;
3406 if (kIOLogPMRootDomain
& gIOKitDebug
)
3408 IOService
* powerChild
=
3409 (IOService
*) whichChild
->getChildEntry(gIOPowerPlane
);
3410 DLOG("child %p, flags %lx, spec %lx - %s\n",
3411 powerChild
, desiredFlags
, specification
,
3412 powerChild
? powerChild
->getName() : "?");
3415 // Force the child's input power requirements to 0 unless the prevent
3416 // idle-sleep flag is set. No input power flags map to our state 0.
3417 // Our power clamp (deviceDesire) keeps the minimum power state at 2.
3419 if (desiredFlags
& kIOPMPreventIdleSleep
)
3420 editedDesire
= kIOPMPreventIdleSleep
| kIOPMPowerOn
;
3424 // Recompute sleep supported flag (doze if not supported)
3425 sleepIsSupported
= true;
3427 iter
= getChildIterator(gIOPowerPlane
);
3430 while ( (next
= iter
->getNextObject()) )
3432 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
3434 // Ignore child that are in the process of joining.
3435 if (connection
->getReadyFlag() == false)
3438 // Is this connection attached to the child that called
3439 // requestPowerDomainState()?
3441 if (connection
== whichChild
)
3443 // OR in the child's input power requirements.
3444 powerRequestFlag
|= editedDesire
;
3446 if ( desiredFlags
& kIOPMPreventSystemSleep
)
3447 sleepIsSupported
= false;
3451 if (kIOLogPMRootDomain
& gIOKitDebug
)
3453 IOService
* powerChild
=
3454 (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
3455 DLOG("child %p, state %ld, noIdle %d, noSleep %d - %s\n",
3457 connection
->getDesiredDomainState(),
3458 connection
->getPreventIdleSleepFlag(),
3459 connection
->getPreventSystemSleepFlag(),
3460 powerChild
? powerChild
->getName() : "?");
3463 // OR in the child's desired power state (0 or ON_STATE).
3464 powerRequestFlag
|= connection
->getDesiredDomainState();
3466 if ( connection
->getPreventSystemSleepFlag() )
3467 sleepIsSupported
= false;
3474 DLOG("childPowerFlags 0x%lx, extraSleepDelay %ld\n",
3475 powerRequestFlag
, extraSleepDelay
);
3477 if ( !powerRequestFlag
&& !systemBooting
)
3482 changePowerStateToPriv(ON_STATE
);
3485 // stay awake for at least idleSeconds
3486 startIdleSleepTimer(idleSeconds
);
3489 else if (!extraSleepDelay
&& !idleSleepTimerPending
)
3495 // Drop our power clamp to SLEEP_STATE when all children became idle,
3496 // and the system sleep and display sleep values are equal.
3500 // If our power clamp has already dropped to SLEEP_STATE, and no child
3501 // is keeping us at ON_STATE, then this will trigger idle sleep.
3503 editedDesire
|= (desiredFlags
& kIOPMPreventSystemSleep
);
3505 return super::requestPowerDomainState(
3506 editedDesire
, whichChild
, specification
);
3510 //******************************************************************************
3511 // handlePlatformHaltRestart
3513 //******************************************************************************
3515 struct HaltRestartApplierContext
{
3516 IOPMrootDomain
* RootDomain
;
3517 unsigned long PowerState
;
3518 IOPMPowerFlags PowerFlags
;
3524 platformHaltRestartApplier( OSObject
* object
, void * context
)
3526 IOPowerStateChangeNotification notify
;
3527 HaltRestartApplierContext
* ctx
;
3528 AbsoluteTime startTime
;
3531 ctx
= (HaltRestartApplierContext
*) context
;
3533 memset(¬ify
, 0, sizeof(notify
));
3534 notify
.powerRef
= (void *)ctx
->Counter
;
3535 notify
.returnValue
= 0;
3536 notify
.stateNumber
= ctx
->PowerState
;
3537 notify
.stateFlags
= ctx
->PowerFlags
;
3539 clock_get_uptime(&startTime
);
3540 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
3541 deltaTime
= computeDeltaTimeMS(&startTime
);
3543 if ((deltaTime
> kPMHaltTimeoutMS
) || (gIOKitDebug
& kIOLogDebugPower
))
3545 _IOServiceInterestNotifier
* notifier
;
3546 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
3548 // IOService children of IOPMrootDomain are not instrumented.
3549 // Only IORootParent currently falls under that group.
3553 KLOG("%s handler %p took %u ms\n",
3554 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ?
3555 "PowerOff" : "Restart",
3556 notifier
->handler
, (uint32_t) deltaTime
);
3563 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
3565 HaltRestartApplierContext ctx
;
3566 AbsoluteTime startTime
;
3569 memset(&ctx
, 0, sizeof(ctx
));
3570 ctx
.RootDomain
= this;
3572 clock_get_uptime(&startTime
);
3576 case kPEUPSDelayHaltCPU
:
3577 ctx
.PowerState
= OFF_STATE
;
3578 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
3582 ctx
.PowerState
= RESTART_STATE
;
3583 ctx
.MessageType
= kIOMessageSystemWillRestart
;
3590 // Notify legacy clients
3591 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
3593 // For normal shutdown, turn off File Server Mode.
3594 if (kPEHaltCPU
== pe_type
)
3596 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
3597 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
3600 setPMSetting(setting
, num
);
3606 // Notify in power tree order
3607 notifySystemShutdown(this, ctx
.MessageType
);
3609 deltaTime
= computeDeltaTimeMS(&startTime
);
3610 KLOG("%s all drivers took %u ms\n",
3611 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ?
3612 "PowerOff" : "Restart",
3613 (uint32_t) deltaTime
);
3617 //******************************************************************************
3620 //******************************************************************************
3622 IONotifier
* IOPMrootDomain::registerInterest(
3623 const OSSymbol
* typeOfInterest
,
3624 IOServiceInterestHandler handler
,
3625 void * target
, void * ref
)
3627 IONotifier
* notifier
;
3630 isConfigd
= typeOfInterest
&&
3631 typeOfInterest
->isEqualTo(kIOPMPrivilegedPowerInterest
);
3634 typeOfInterest
= gIOAppPowerStateInterest
;
3636 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
3638 #if ROOT_DOMAIN_RUN_STATES
3639 if (isConfigd
&& notifier
&& pmPowerStateQueue
)
3642 if (pmPowerStateQueue
->submitPowerEvent(
3643 kPowerEventConfigdRegisteredInterest
, notifier
) == false)
3644 notifier
->release();
3651 static bool clientMessageFilter( OSObject
* object
, void * arg
)
3653 #if ROOT_DOMAIN_RUN_STATES
3654 #if LOG_INTEREST_CLIENTS
3655 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
3659 switch (gMessageClientType
)
3661 case kMessageClientNone
:
3665 case kMessageClientAll
:
3669 case kMessageClientConfigd
:
3670 allow
= ((object
== (OSObject
*) gConfigdNotifier
) ||
3671 (object
== (OSObject
*) gSysPowerDownNotifier
));
3675 #if LOG_INTEREST_CLIENTS
3677 DLOG("system message %x to %p\n",
3678 context
->msgType
, object
);
3688 //******************************************************************************
3691 // We override the superclass implementation so we can send a different message
3692 // type to the client or application being notified.
3693 //******************************************************************************
3695 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
3699 DLOG("tellChangeDown %u->%u, R-state %u\n",
3700 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3702 switch ( stateNum
) {
3706 if (!ignoreChangeDown
)
3708 userActivityAtSleep
= userActivityCount
;
3709 hibernateAborted
= false;
3710 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
3712 // Direct callout into OSKext so it can disable kext unloads
3713 // during sleep/wake to prevent deadlocks.
3714 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
3716 if ( (SLEEP_STATE
== stateNum
) && sleepSupportedPEFunction
)
3718 // Reset PCI prevent sleep flag before calling platform driver.
3719 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
3721 // Skip PCI check for maintenance sleep.
3722 if ((runStateFlags
& kRStateFlagSuppressPCICheck
) == 0)
3724 // Determine if the machine supports sleep, or must doze.
3725 getPlatform()->callPlatformFunction(
3726 sleepSupportedPEFunction
, false,
3727 NULL
, NULL
, NULL
, NULL
);
3730 // If the machine only supports doze, the callPlatformFunction call
3731 // boils down to IOPMrootDomain::setSleepSupported(kPCICantSleep),
3732 // otherwise nothing.
3735 // Notify platform that sleep has begun
3736 getPlatform()->callPlatformFunction(
3737 sleepMessagePEFunction
, false,
3738 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
3741 // Update canSleep and kIOSleepSupportedKey property so drivers
3742 // can tell if platform is going to sleep versus doze.
3749 if (!sleepIsSupported
)
3751 if (platformSleepSupport
& kPCICantSleep
)
3753 setProperty(kIOSleepSupportedKey
, canSleep
);
3754 DLOG("canSleep %d\n", canSleep
);
3756 // Publish the new sleep-wake UUID
3757 publishSleepWakeUUID(true);
3759 // Two change downs are sent by IOServicePM. Ignore the 2nd.
3760 ignoreChangeDown
= true;
3762 tracePoint( kIOPMTracePointSystemSleepAppsPhase
);
3765 DLOG("kIOMessageSystemWillSleep (%d)\n", gMessageClientType
);
3766 done
= super::tellClientsWithResponse(
3767 kIOMessageSystemWillSleep
, clientMessageFilter
);
3771 done
= super::tellChangeDown(stateNum
);
3778 //******************************************************************************
3781 // We override the superclass implementation so we can send a different message
3782 // type to the client or application being notified.
3784 // This must be idle sleep since we don't ask during any other power change.
3785 //******************************************************************************
3787 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
3789 DLOG("askChangeDown %u->%u, R-state %u\n",
3790 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3791 DLOG("kIOMessageCanSystemSleep (%d)\n", gMessageClientType
);
3793 return super::tellClientsWithResponse(
3794 kIOMessageCanSystemSleep
,
3795 clientMessageFilter
);
3799 //******************************************************************************
3802 // Notify registered applications and kernel clients that we are not dropping
3805 // We override the superclass implementation so we can send a different message
3806 // type to the client or application being notified.
3808 // This must be a vetoed idle sleep, since no other power change can be vetoed.
3809 //******************************************************************************
3811 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
3813 DLOG("tellNoChangeDown %u->%u, R-state %u\n",
3814 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3816 // Sleep canceled, clear the sleep trace point.
3817 tracePoint(kIOPMTracePointSystemUp
);
3819 if (idleSeconds
&& !wrangler
)
3821 // stay awake for at least idleSeconds
3823 startIdleSleepTimer(idleSeconds
);
3825 DLOG("kIOMessageSystemWillNotSleep (%d)\n", gMessageClientType
);
3826 return tellClients(kIOMessageSystemWillNotSleep
, clientMessageFilter
);
3830 //******************************************************************************
3833 // Notify registered applications and kernel clients that we are raising power.
3835 // We override the superclass implementation so we can send a different message
3836 // type to the client or application being notified.
3837 //******************************************************************************
3839 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
3841 OSData
*publishPMStats
= NULL
;
3843 DLOG("tellChangeUp %u->%u, R-state %u\n",
3844 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3846 ignoreChangeDown
= false;
3848 if ( stateNum
== ON_STATE
)
3850 // Direct callout into OSKext so it can disable kext unloads
3851 // during sleep/wake to prevent deadlocks.
3852 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
3854 // Notify platform that sleep was cancelled or resumed.
3855 getPlatform()->callPlatformFunction(
3856 sleepMessagePEFunction
, false,
3857 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
3860 if (getPowerState() == ON_STATE
)
3862 // this is a quick wake from aborted sleep
3863 if (idleSeconds
&& !wrangler
)
3865 // stay awake for at least idleSeconds
3867 startIdleSleepTimer(idleSeconds
);
3869 DLOG("kIOMessageSystemWillPowerOn (%d)\n", gMessageClientType
);
3870 tellClients(kIOMessageSystemWillPowerOn
, clientMessageFilter
);
3875 IOHibernateSystemPostWake();
3879 tracePoint(kIOPMTracePointSystemWakeAppsPhase
);
3880 publishPMStats
= OSData::withBytes(&pmStats
, sizeof(pmStats
));
3881 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
3882 publishPMStats
->release();
3883 bzero(&pmStats
, sizeof(pmStats
));
3885 if (pmStatsAppResponses
)
3887 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
3888 pmStatsAppResponses
->release();
3889 pmStatsAppResponses
= OSArray::withCapacity(5);
3892 DLOG("kIOMessageSystemHasPoweredOn (%d)\n", gMessageClientType
);
3893 tellClients(kIOMessageSystemHasPoweredOn
, clientMessageFilter
);
3895 tracePoint(kIOPMTracePointSystemUp
);
3900 //******************************************************************************
3903 //******************************************************************************
3905 void IOPMrootDomain::reportUserInput( void )
3912 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
3915 wrangler
= (IOService
*) iter
->getNextObject();
3921 wrangler
->activityTickle(0,0);
3926 //******************************************************************************
3927 // setQuickSpinDownTimeout
3929 //******************************************************************************
3931 void IOPMrootDomain::setQuickSpinDownTimeout( void )
3935 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
3939 //******************************************************************************
3940 // restoreUserSpinDownTimeout
3942 //******************************************************************************
3944 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
3948 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
3952 //******************************************************************************
3953 // changePowerStateTo & changePowerStateToPriv
3955 // Override of these methods for logging purposes.
3956 //******************************************************************************
3958 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3960 return kIOReturnUnsupported
; // ignored
3963 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3965 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3967 if ( (getPowerState() == DOZE_STATE
) && (ordinal
!= ON_STATE
) )
3969 return kIOReturnSuccess
;
3972 if ( (userDisabledAllSleep
|| systemBooting
|| systemShutdown
) &&
3973 (ordinal
== SLEEP_STATE
) )
3975 DLOG("SLEEP rejected, forced to ON state (UD %d, SB %d, SS %d)\n",
3976 userDisabledAllSleep
, systemBooting
, systemShutdown
);
3978 super::changePowerStateToPriv(ON_STATE
);
3981 return super::changePowerStateToPriv(ordinal
);
3984 //******************************************************************************
3987 //******************************************************************************
3989 bool IOPMrootDomain::activitySinceSleep(void)
3991 return (userActivityCount
!= userActivityAtSleep
);
3994 bool IOPMrootDomain::abortHibernation(void)
3996 bool ret
= activitySinceSleep();
3998 if (ret
&& !hibernateAborted
)
4000 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
4001 hibernateAborted
= true;
4007 hibernate_should_abort(void)
4010 return (gRootDomain
->abortHibernation());
4015 //******************************************************************************
4018 //******************************************************************************
4020 void IOPMrootDomain::updateRunState( uint32_t inRunState
)
4022 #if ROOT_DOMAIN_RUN_STATES
4023 if (inRunState
< kRStateCount
)
4025 runStateIndex
= nextRunStateIndex
= inRunState
;
4026 runStateFlags
= gRStateFlags
[inRunState
];
4029 kIOPMRootDomainRunStateKey
,
4030 (unsigned long long) inRunState
, 32);
4036 #if ROOT_DOMAIN_RUN_STATES
4037 //******************************************************************************
4038 // tagPowerPlaneService
4040 // Running on PM work loop thread.
4041 //******************************************************************************
4043 void IOPMrootDomain::tagPowerPlaneService(
4044 IOService
* service
,
4045 uint32_t * rdFlags
)
4049 if (service
->getProperty("IOPMStrictTreeOrder") ||
4050 service
->metaCast("IODisplayWrangler") ||
4051 OSDynamicCast(OSNumber
,
4052 service
->getProperty("IOPMUnattendedWakePowerState")))
4054 *rdFlags
|= kServiceFlagGraphics
;
4055 DLOG("tagged device %s %x\n", service
->getName(), *rdFlags
);
4058 // Locate the first PCI host bridge.
4059 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4061 IOService
* provider
= service
->getProvider();
4062 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4063 provider
->inPlane(gIODTPlane
))
4065 pciHostBridgeDevice
= provider
;
4066 DLOG("PMTrace found PCI host bridge %s->%s\n",
4067 provider
->getName(), service
->getName());
4071 // Tag top-level PCI devices. The order of PMinit() call does not
4072 // change across boots and is used as the PCI bit number.
4073 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4075 // Would prefer to check built-in property, but tagPowerPlaneService()
4076 // is called before pciDevice->registerService().
4077 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4078 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4080 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4083 // Save the assigned bit for fast lookup.
4085 *rdFlags
|= (kServiceFlagTopLevelPCI
| (bit
<< 8));
4092 //******************************************************************************
4093 // handleActivityTickleForService
4095 // Called by IOService::activityTickle() for a tickle that is requesting the
4096 // service to raise power state. Called from driver thread.
4097 //******************************************************************************
4099 void IOPMrootDomain::handleActivityTickleForService( IOService
* service
,
4101 unsigned long currentPowerState
,
4102 uint32_t activityTickleCount
)
4104 if ((service
== wrangler
)
4107 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
4108 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
4109 if (aborting
) userActivityCount
++;
4110 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
4113 // Tickle directed to IODisplayWrangler while graphics is disabled.
4114 // Bring graphics online.
4116 if ((!currentPowerState
) &&
4117 (service
== wrangler
) &&
4118 (runStateIndex
> kRStateNormal
) &&
4119 (false == wranglerTickled
) &&
4120 (false == lowBatteryCondition
))
4122 DLOG("display wrangler tickled\n");
4123 if (kIOLogPMRootDomain
& gIOKitDebug
)
4124 OSReportWithBacktrace("Display Tickle");
4125 wranglerTickled
= true;
4126 synchronizePowerTree();
4130 //******************************************************************************
4131 // handlePowerChangeStartForService
4133 // Running on PM work loop thread.
4134 //******************************************************************************
4136 void IOPMrootDomain::handlePowerChangeStartForService(
4137 IOService
* service
,
4139 uint32_t newPowerState
,
4140 uint32_t changeFlags
)
4142 if (service
== this)
4144 uint32_t currentPowerState
= (uint32_t) getPowerState();
4145 uint32_t nextRunStateFlags
;
4147 assert(nextRunStateIndex
< kRStateCount
);
4148 nextRunStateFlags
= gRStateFlags
[nextRunStateIndex
];
4150 gMessageClientType
= kMessageClientNone
;
4152 // Transition towards or away from ON power state.
4154 if ((currentPowerState
!= newPowerState
) &&
4155 ((ON_STATE
== newPowerState
) || (ON_STATE
== currentPowerState
)))
4157 if ((runStateFlags
& kRStateFlagSuppressMessages
) == 0)
4158 gMessageClientType
= kMessageClientAll
;
4160 gMessageClientType
= kMessageClientConfigd
;
4163 // Transition caused by deassertion of system notification suppression.
4165 if ((ON_STATE
== newPowerState
) &&
4166 (ON_STATE
== currentPowerState
) &&
4167 ((runStateFlags
^ nextRunStateFlags
) & kRStateFlagSuppressMessages
))
4169 gMessageClientType
= kMessageClientAll
;
4172 if (ON_STATE
== newPowerState
)
4174 DLOG("kIOMessageSystemWillPowerOn (%d)\n",
4175 gMessageClientType
);
4176 tellClients(kIOMessageSystemWillPowerOn
, clientMessageFilter
);
4179 if (SLEEP_STATE
== newPowerState
)
4181 tracePoint(kIOPMTracePointSleepStarted
);
4185 if (*rdFlags
& kServiceFlagTopLevelPCI
)
4187 pmTracer
->tracePCIPowerChange(
4188 PMTraceWorker::kPowerChangeStart
,
4189 service
, changeFlags
,
4190 (*rdFlags
>> 8) & 0xff);
4195 //******************************************************************************
4196 // handlePowerChangeDoneForService
4198 // Running on PM work loop thread.
4199 //******************************************************************************
4201 void IOPMrootDomain::handlePowerChangeDoneForService(
4202 IOService
* service
,
4204 uint32_t newPowerState
,
4205 uint32_t changeFlags
)
4207 if (*rdFlags
& kServiceFlagTopLevelPCI
)
4209 pmTracer
->tracePCIPowerChange(
4210 PMTraceWorker::kPowerChangeCompleted
,
4211 service
, changeFlags
,
4212 (*rdFlags
>> 8) & 0xff);
4217 //******************************************************************************
4218 // overridePowerStateForService
4220 // Runs on PM work loop thread.
4221 //******************************************************************************
4223 void IOPMrootDomain::overridePowerStateForService(
4224 IOService
* service
,
4226 unsigned long * powerState
,
4227 uint32_t changeFlags
)
4229 uint32_t inPowerState
= (uint32_t) *powerState
;
4231 if ((service
== this) && (inPowerState
== ON_STATE
) &&
4232 (changeFlags
& kIOPMSynchronize
))
4234 DLOG("sync root domain %u->%u\n",
4235 (uint32_t) getPowerState(), inPowerState
);
4237 // Root Domain is in a reduced R-state, and a HID tickle has
4238 // requested a PM tree sync. Begin R-state transition.
4240 if (runStateIndex
!= kRStateNormal
)
4242 sleepTimerMaintenance
= false;
4243 hibernateNoDefeat
= false;
4244 nextRunStateIndex
= kRStateNormal
;
4246 kIOPMRootDomainRunStateKey
,
4247 (unsigned long long) kRStateNormal
, 32);
4251 if (*rdFlags
& kServiceFlagGraphics
)
4253 DLOG("graphics device %s %u->%u (flags 0x%x)\n",
4254 service
->getName(), (uint32_t) service
->getPowerState(),
4255 inPowerState
, changeFlags
);
4257 if (inPowerState
== 0)
4259 // Graphics device is powering down, apply limit preventing
4260 // device from powering back up later unless we consent.
4262 if ((*rdFlags
& kServiceFlagNoPowerUp
) == 0)
4264 *rdFlags
|= kServiceFlagNoPowerUp
;
4265 DLOG("asserted power limit for %s\n",
4266 service
->getName());
4271 uint32_t nextRunStateFlags
;
4273 assert(nextRunStateIndex
< kRStateCount
);
4274 nextRunStateFlags
= gRStateFlags
[nextRunStateIndex
];
4276 // Graphics device is powering up. Release power limit at the
4277 // did-change machine state.
4279 if (changeFlags
& kIOPMSynchronize
)
4281 if ((runStateFlags
& kRStateFlagSuppressGraphics
) &&
4282 ((nextRunStateFlags
& kRStateFlagSuppressGraphics
) == 0) &&
4283 (changeFlags
& kIOPMDomainDidChange
))
4285 // Woke up without graphics power, but
4286 // HID event has tickled display wrangler.
4287 *rdFlags
&= ~kServiceFlagNoPowerUp
;
4288 DLOG("removed power limit for %s\n",
4289 service
->getName());
4292 else if ((runStateFlags
& kRStateFlagSuppressGraphics
) == 0)
4294 *rdFlags
&= ~kServiceFlagNoPowerUp
;
4297 if (*rdFlags
& kServiceFlagNoPowerUp
)
4299 DLOG("limited %s to power state 0\n",
4300 service
->getName());
4308 //******************************************************************************
4309 // setMaintenanceWakeCalendar
4311 //******************************************************************************
4313 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
4314 const IOPMCalendarStruct
* calendar
)
4320 return kIOReturnBadArgument
;
4322 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
4324 return kIOReturnNoMemory
;
4326 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
4331 #endif /* ROOT_DOMAIN_RUN_STATES */
4334 //******************************************************************************
4335 // sysPowerDownHandler
4337 // Receives a notification when the RootDomain changes state.
4339 // Allows us to take action on system sleep, power down, and restart after
4340 // applications have received their power change notifications and replied,
4341 // but before drivers have powered down. We perform a vfs sync on power down.
4342 //******************************************************************************
4344 IOReturn
IOPMrootDomain::sysPowerDownHandler( void * target
, void * refCon
,
4345 UInt32 messageType
, IOService
* service
,
4346 void * messageArgument
, vm_size_t argSize
)
4349 IOPowerStateChangeNotification
*params
= (IOPowerStateChangeNotification
*) messageArgument
;
4350 IOPMrootDomain
*rootDomain
= OSDynamicCast(IOPMrootDomain
, service
);
4352 DLOG("sysPowerDownHandler message %x\n", (uint32_t) messageType
);
4355 return kIOReturnUnsupported
;
4357 switch (messageType
) {
4358 case kIOMessageSystemWillSleep
:
4359 // Interested applications have been notified of an impending power
4360 // change and have acked (when applicable).
4361 // This is our chance to save whatever state we can before powering
4363 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
4366 rootDomain
->evaluateSystemSleepPolicyEarly();
4367 if (rootDomain
->hibernateMode
&& !rootDomain
->hibernateDisabled
)
4369 // We will ack within 240 seconds
4370 params
->returnValue
= 240 * 1000 * 1000;
4374 // We will ack within 20 seconds
4375 params
->returnValue
= 20 * 1000 * 1000;
4376 DLOG("sysPowerDownHandler timeout %d s\n", (int) (params
->returnValue
/ 1000 / 1000));
4377 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
4379 // Purposely delay the ack and hope that shutdown occurs quickly.
4380 // Another option is not to schedule the thread and wait for
4382 AbsoluteTime deadline
;
4383 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
4384 thread_call_enter1_delayed( rootDomain
->diskSyncCalloutEntry
,
4385 (thread_call_param_t
)params
->powerRef
,
4389 thread_call_enter1(rootDomain
->diskSyncCalloutEntry
, (thread_call_param_t
)params
->powerRef
);
4390 ret
= kIOReturnSuccess
;
4393 case kIOMessageSystemWillPowerOff
:
4394 case kIOMessageSystemWillRestart
:
4395 ret
= kIOReturnUnsupported
;
4399 ret
= kIOReturnUnsupported
;
4405 //******************************************************************************
4406 // publishSleepWakeUUID
4409 //******************************************************************************
4410 void IOPMrootDomain::publishSleepWakeUUID( bool shouldPublish
)
4414 if (queuedSleepWakeUUIDString
)
4416 if (OSCompareAndSwap(/*old*/ true, /*new*/ false, &gSleepWakeUUIDIsSet
))
4418 // Upon wake, it takes some time for userland to invalidate the
4419 // UUID. If another sleep is initiated during that period, force
4420 // a CLEAR message to balance the upcoming SET message.
4422 messageClients( kIOPMMessageSleepWakeUUIDChange
,
4423 kIOPMMessageSleepWakeUUIDCleared
);
4425 DLOG("SleepWake UUID forced clear\n");
4428 setProperty(kIOPMSleepWakeUUIDKey
, queuedSleepWakeUUIDString
);
4429 DLOG("SleepWake UUID published: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
4430 queuedSleepWakeUUIDString
->release();
4431 queuedSleepWakeUUIDString
= NULL
;
4432 messageClients(kIOPMMessageSleepWakeUUIDChange
,
4433 kIOPMMessageSleepWakeUUIDSet
);
4436 if (OSCompareAndSwap(/*old*/ true, /*new*/ false, &gSleepWakeUUIDIsSet
))
4438 DLOG("SleepWake UUID cleared\n");
4439 removeProperty(kIOPMSleepWakeUUIDKey
);
4440 messageClients(kIOPMMessageSleepWakeUUIDChange
,
4441 kIOPMMessageSleepWakeUUIDCleared
);
4447 //******************************************************************************
4448 // displayWranglerNotification
4450 // Receives a notification when the IODisplayWrangler changes state.
4452 // Allows us to take action on display dim/undim.
4454 // When the display sleeps we:
4455 // - Start the idle sleep timer
4456 // - set the quick spin down timeout
4458 // On wake from display sleep:
4459 // - Cancel the idle sleep timer
4460 // - restore the user's chosen spindown timer from the "quick" spin down value
4461 //******************************************************************************
4463 IOReturn
IOPMrootDomain::displayWranglerNotification(
4464 void * target
, void * refCon
,
4465 UInt32 messageType
, IOService
* service
,
4466 void * messageArgument
, vm_size_t argSize
)
4469 int displayPowerState
;
4470 IOPowerStateChangeNotification
* params
=
4471 (IOPowerStateChangeNotification
*) messageArgument
;
4473 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
4474 (messageType
!= kIOMessageDeviceHasPoweredOn
))
4475 return kIOReturnUnsupported
;
4479 return kIOReturnUnsupported
;
4481 displayPowerState
= params
->stateNumber
;
4482 DLOG("DisplayWrangler message 0x%x, new power state %d\n",
4483 (uint32_t) messageType
, displayPowerState
);
4485 switch (messageType
) {
4486 case kIOMessageDeviceWillPowerOff
:
4488 // The display wrangler has dropped power because of idle display sleep
4489 // or force system sleep.
4494 // 1 Not visible to user
4495 // 0 Not visible to user
4497 if (gRootDomain
->wranglerAsleep
|| (displayPowerState
> 2))
4500 // Record the time the display wrangler went to sleep.
4502 gRootDomain
->wranglerAsleep
= true;
4503 clock_get_uptime(&gRootDomain
->wranglerSleepTime
);
4505 // We start a timer here if the System Sleep timer is greater than the
4506 // Display Sleep timer. We kick off this timer when the display sleeps.
4508 // Note that, although Display Dim timings may change adaptively accordingly
4509 // to the user's activity patterns, Display Sleep _always_ occurs at the
4510 // specified interval since last user activity.
4512 if ( gRootDomain
->extraSleepDelay
)
4514 gRootDomain
->startIdleSleepTimer(gRootDomain
->extraSleepDelay
* 60);
4516 else if ( gRootDomain
->sleepSlider
)
4518 // Accelerate disk spindown if system sleep and display sleep
4519 // sliders are set to the same value (e.g. both set to 5 min),
4520 // and display is about to go dark. Check that spin down timer
4521 // is non-zero (zero = never spin down) and system sleep is
4522 // not set to never sleep.
4524 gRootDomain
->setQuickSpinDownTimeout();
4529 case kIOMessageDeviceHasPoweredOn
:
4531 // The display wrangler has powered on either because of user activity
4532 // or wake from sleep/doze.
4534 if ( 4 != displayPowerState
)
4537 gRootDomain
->wranglerAsleep
= false;
4538 gRootDomain
->adjustPowerState();
4539 gRootDomain
->cancelIdleSleepTimer();
4541 // Change the spindown value back to the user's selection from our
4542 // accelerated setting.
4543 gRootDomain
->restoreUserSpinDownTimeout();
4551 return kIOReturnUnsupported
;
4555 //******************************************************************************
4556 // displayWranglerPublished
4558 // Receives a notification when the IODisplayWrangler is published.
4559 // When it's published we install a power state change handler.
4560 //******************************************************************************
4562 bool IOPMrootDomain::displayWranglerPublished(
4565 IOService
* newService
)
4571 gRootDomain
->wrangler
= newService
;
4573 // we found the display wrangler, now install a handler
4574 if( !gRootDomain
->wrangler
->registerInterest( gIOGeneralInterest
,
4575 &displayWranglerNotification
, target
, 0) )
4584 //******************************************************************************
4587 // Notification on battery class IOPowerSource appearance
4588 //******************************************************************************
4590 bool IOPMrootDomain::batteryPublished(
4593 IOService
* resourceService
)
4595 // rdar://2936060&4435589
4596 // All laptops have dimmable LCD displays
4597 // All laptops have batteries
4598 // So if this machine has a battery, publish the fact that the backlight
4599 // supports dimming.
4600 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
4606 //******************************************************************************
4609 // Some condition that affects our wake/sleep/doze decision has changed.
4611 // If the sleep slider is in the off position, we cannot sleep or doze.
4612 // If the enclosure is open, we cannot sleep or doze.
4613 // If the system is still booting, we cannot sleep or doze.
4615 // In those circumstances, we prevent sleep and doze by holding power on with
4616 // changePowerStateToPriv(ON).
4618 // If the above conditions do not exist, and also the sleep timer has expired,
4619 // we allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
4620 // changePowerStateToPriv(DOZE) depending on whether or not we already know the
4621 // platform cannot sleep.
4623 // In this case, sleep or doze will either occur immediately or at the next time
4624 // that no children are holding the system out of idle sleep via the
4625 // kIOPMPreventIdleSleep flag in their power state arrays.
4626 //******************************************************************************
4628 void IOPMrootDomain::adjustPowerState( void )
4630 DLOG("adjustPowerState "
4631 "PS %u, ASAP %d, SL %ld, AS %d, SB %d, SS %d, UD %d\n",
4632 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
,
4633 allowSleep
, systemBooting
, systemShutdown
, userDisabledAllSleep
);
4637 if ( (sleepSlider
== 0)
4641 || userDisabledAllSleep
4642 || (runStateFlags
& kRStateFlagDisableIdleSleep
) )
4644 changePowerStateToPriv(ON_STATE
);
4648 /* Convenient place to run any code at idle sleep time
4649 * IOPMrootDomain initiates an idle sleep here
4651 * Set last sleep cause accordingly.
4653 lastSleepReason
= kIOPMSleepReasonIdle
;
4654 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
4657 changePowerStateToPriv(SLEEP_STATE
);
4662 void IOPMrootDomain::pmStatsRecordEvent(
4664 AbsoluteTime timestamp
)
4666 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
4667 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
4671 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
4673 absolutetime_to_nanoseconds(timestamp
, &nsec
);
4675 switch (eventIndex
) {
4676 case kIOPMStatsHibernateImageWrite
:
4678 pmStats
.hibWrite
.start
= nsec
;
4680 pmStats
.hibWrite
.stop
= nsec
;
4683 delta
= pmStats
.hibWrite
.stop
- pmStats
.hibWrite
.start
;
4684 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
4687 case kIOPMStatsHibernateImageRead
:
4689 pmStats
.hibRead
.start
= nsec
;
4691 pmStats
.hibRead
.stop
= nsec
;
4694 delta
= pmStats
.hibRead
.stop
- pmStats
.hibRead
.start
;
4695 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
4702 * Appends a record of the application response to
4703 * IOPMrootDomain::pmStatsAppResponses
4705 void IOPMrootDomain::pmStatsRecordApplicationResponse(
4706 const OSSymbol
*response
,
4712 OSDictionary
*responseDescription
= NULL
;
4713 OSNumber
*delayNum
= NULL
;
4714 OSNumber
*pidNum
= NULL
;
4715 OSNumber
*msgNum
= NULL
;
4716 const OSSymbol
*appname
;
4717 const OSSymbol
*entryName
;
4718 OSObject
*entryType
;
4721 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
4725 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
4727 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
4728 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
4729 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
))
4731 OSNumber
* entryValue
;
4732 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
4733 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
4734 entryValue
->setValue(delay_ms
);
4739 responseDescription
= OSDictionary::withCapacity(5);
4740 if (responseDescription
)
4743 responseDescription
->setObject(_statsResponseTypeKey
, response
);
4746 if (messageType
!= 0) {
4747 msgNum
= OSNumber::withNumber(messageType
, 32);
4749 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
4754 if (name
&& (strlen(name
) > 0))
4756 appname
= OSSymbol::withCString(name
);
4758 responseDescription
->setObject(_statsNameKey
, appname
);
4763 if (app_pid
!= -1) {
4764 pidNum
= OSNumber::withNumber(app_pid
, 32);
4766 responseDescription
->setObject(_statsPIDKey
, pidNum
);
4771 delayNum
= OSNumber::withNumber(delay_ms
, 32);
4773 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
4774 delayNum
->release();
4777 if (pmStatsAppResponses
) {
4778 pmStatsAppResponses
->setObject(responseDescription
);
4781 responseDescription
->release();
4787 //******************************************************************************
4788 // TracePoint support
4790 //******************************************************************************
4792 #define kIOPMRegisterNVRAMTracePointHandlerKey \
4793 "IOPMRegisterNVRAMTracePointHandler"
4795 IOReturn
IOPMrootDomain::callPlatformFunction(
4796 const OSSymbol
* functionName
,
4797 bool waitForFunction
,
4798 void * param1
, void * param2
,
4799 void * param3
, void * param4
)
4801 if (pmTracer
&& functionName
&&
4802 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
4803 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
4805 uint32_t tracePointPhases
, tracePointPCI
;
4806 uint64_t statusCode
;
4808 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
4809 pmTracer
->tracePointTarget
= (void *) param2
;
4810 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
4811 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
4812 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
4813 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
4815 LOG("Sleep failure code 0x%08x 0x%08x\n",
4816 tracePointPCI
, tracePointPhases
);
4818 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
4819 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
4821 return kIOReturnSuccess
;
4824 return super::callPlatformFunction(
4825 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
4828 void IOPMrootDomain::tracePoint( uint8_t point
)
4830 pmTracer
->tracePoint(point
);
4833 //******************************************************************************
4834 // PMTraceWorker Class
4836 //******************************************************************************
4839 #define super OSObject
4840 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
4842 #define kPMBestGuessPCIDevicesCount 25
4843 #define kPMMaxRTCBitfieldSize 32
4845 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
4849 me
= OSTypeAlloc( PMTraceWorker
);
4850 if (!me
|| !me
->init())
4855 DLOG("PMTraceWorker %p\n", me
);
4857 // Note that we cannot instantiate the PCI device -> bit mappings here, since
4858 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
4859 // this dictionary lazily.
4861 me
->pciDeviceBitMappings
= NULL
;
4862 me
->pciMappingLock
= IOLockAlloc();
4863 me
->tracePhase
= kIOPMTracePointSystemUp
;
4864 me
->loginWindowPhase
= 0;
4865 me
->pciBusyBitMask
= 0;
4869 void PMTraceWorker::RTC_TRACE(void)
4871 if (tracePointHandler
&& tracePointTarget
)
4875 wordA
= tracePhase
; // destined for bits 24-31
4877 wordA
|= loginWindowPhase
; // destined for bits 16-23
4880 tracePointHandler( tracePointTarget
, pciBusyBitMask
, wordA
);
4881 DLOG("RTC_TRACE wrote 0x%08x 0x%08x\n", pciBusyBitMask
, wordA
);
4885 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
4887 const OSSymbol
* deviceName
;
4890 IOLockLock(pciMappingLock
);
4892 if (!pciDeviceBitMappings
)
4894 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
4895 if (!pciDeviceBitMappings
)
4899 // Check for bitmask overflow.
4900 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
4903 if ((deviceName
= pciDevice
->copyName()) &&
4904 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
4905 pciDeviceBitMappings
->setObject(deviceName
))
4907 index
= pciDeviceBitMappings
->getCount() - 1;
4908 DLOG("PMTrace PCI array: set object %s => %d\n",
4909 deviceName
->getCStringNoCopy(), index
);
4912 deviceName
->release();
4913 if (!addedToRegistry
&& (index
>= 0))
4914 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
4917 IOLockUnlock(pciMappingLock
);
4921 bool PMTraceWorker::serialize(OSSerialize
*s
) const
4924 if (pciDeviceBitMappings
)
4926 IOLockLock(pciMappingLock
);
4927 ok
= pciDeviceBitMappings
->serialize(s
);
4928 IOLockUnlock(pciMappingLock
);
4933 void PMTraceWorker::tracePoint(uint8_t phase
)
4937 DLOG("IOPMrootDomain: trace point 0x%02x\n", tracePhase
);
4941 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
4943 loginWindowPhase
= phase
;
4945 DLOG("IOPMrootDomain: loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
4949 void PMTraceWorker::tracePCIPowerChange(
4950 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
4953 uint32_t expectedFlag
;
4955 // Ignore PCI changes outside of system sleep/wake.
4956 if ((kIOPMTracePointSystemSleepDriversPhase
!= tracePhase
) &&
4957 (kIOPMTracePointSystemWakeDriversPhase
!= tracePhase
))
4960 // Only record the WillChange transition when going to sleep,
4961 // and the DidChange on the way up.
4962 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
4963 expectedFlag
= (kIOPMTracePointSystemSleepDriversPhase
== tracePhase
) ?
4964 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
4965 if (changeFlags
!= expectedFlag
)
4968 // Mark this device off in our bitfield
4969 if (bitNum
< kPMMaxRTCBitfieldSize
)
4971 bitMask
= (1 << bitNum
);
4973 if (kPowerChangeStart
== type
)
4975 pciBusyBitMask
|= bitMask
;
4976 DLOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
4977 service
->getName(), bitNum
, bitMask
, pciBusyBitMask
);
4981 pciBusyBitMask
&= ~bitMask
;
4982 DLOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
4983 service
->getName(), bitNum
, bitMask
, pciBusyBitMask
);
4991 //******************************************************************************
4992 // PMHaltWorker Class
4994 //******************************************************************************
4996 static unsigned int gPMHaltBusyCount
;
4997 static unsigned int gPMHaltIdleCount
;
4998 static int gPMHaltDepth
;
4999 static unsigned long gPMHaltEvent
;
5000 static IOLock
* gPMHaltLock
= 0;
5001 static OSArray
* gPMHaltArray
= 0;
5002 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
5004 PMHaltWorker
* PMHaltWorker::worker( void )
5010 me
= OSTypeAlloc( PMHaltWorker
);
5011 if (!me
|| !me
->init())
5014 me
->lock
= IOLockAlloc();
5018 DLOG("PMHaltWorker %p\n", me
);
5019 me
->retain(); // thread holds extra retain
5020 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
5025 thread_deallocate(thread
);
5030 if (me
) me
->release();
5034 void PMHaltWorker::free( void )
5036 DLOG("PMHaltWorker free %p\n", this);
5042 return OSObject::free();
5045 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
5047 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
5049 IOLockLock( gPMHaltLock
);
5051 me
->depth
= gPMHaltDepth
;
5052 IOLockUnlock( gPMHaltLock
);
5054 while (me
->depth
>= 0)
5056 PMHaltWorker::work( me
);
5058 IOLockLock( gPMHaltLock
);
5059 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
5061 // This is the last thread to finish work on this level,
5062 // inform everyone to start working on next lower level.
5064 me
->depth
= gPMHaltDepth
;
5065 gPMHaltIdleCount
= 0;
5066 thread_wakeup((event_t
) &gPMHaltIdleCount
);
5070 // One or more threads are still working on this level,
5071 // this thread must wait.
5072 me
->depth
= gPMHaltDepth
- 1;
5074 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
5075 } while (me
->depth
!= gPMHaltDepth
);
5077 IOLockUnlock( gPMHaltLock
);
5080 // No more work to do, terminate thread
5081 DLOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
5082 thread_wakeup( &gPMHaltDepth
);
5086 void PMHaltWorker::work( PMHaltWorker
* me
)
5088 IOService
* service
;
5090 AbsoluteTime startTime
;
5099 // Claim an unit of work from the shared pool
5100 IOLockLock( gPMHaltLock
);
5101 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
5104 service
= (IOService
*)inner
->getAnyObject();
5108 inner
->removeObject(service
);
5111 IOLockUnlock( gPMHaltLock
);
5113 break; // no more work at this depth
5115 clock_get_uptime(&startTime
);
5117 if (!service
->isInactive() &&
5118 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
5120 IOLockLock(me
->lock
);
5121 me
->startTime
= startTime
;
5122 me
->service
= service
;
5123 me
->timeout
= false;
5124 IOLockUnlock(me
->lock
);
5126 service
->systemWillShutdown( gPMHaltEvent
);
5128 // Wait for driver acknowledgement
5129 IOLockLock(me
->lock
);
5130 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
5132 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
5135 timeout
= me
->timeout
;
5136 IOLockUnlock(me
->lock
);
5139 deltaTime
= computeDeltaTimeMS(&startTime
);
5140 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
5141 (gIOKitDebug
& (kIOLogDebugPower
| kIOLogPMRootDomain
)))
5143 KLOG("%s driver %s (%p) took %u ms\n",
5144 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
5145 "PowerOff" : "Restart",
5146 service
->getName(), service
,
5147 (uint32_t) deltaTime
);
5155 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
5158 AbsoluteTime startTime
;
5159 AbsoluteTime endTime
;
5163 IOLockLock(me
->lock
);
5164 if (me
->service
&& !me
->timeout
)
5166 startTime
= me
->startTime
;
5168 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
5170 SUB_ABSOLUTETIME(&endTime
, &startTime
);
5171 absolutetime_to_nanoseconds(endTime
, &nano
);
5173 if (nano
> 3000000000ULL)
5176 LOG("%s still waiting on %s\n",
5177 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
5178 "PowerOff" : "Restart",
5179 me
->service
->getName());
5182 IOLockUnlock(me
->lock
);
5186 //******************************************************************************
5187 // acknowledgeSystemWillShutdown
5189 // Acknowledgement from drivers that they have prepared for shutdown/restart.
5190 //******************************************************************************
5192 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
5194 PMHaltWorker
* worker
;
5200 //DLOG("%s acknowledged\n", from->getName());
5201 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
5204 worker
= (PMHaltWorker
*) prop
;
5205 IOLockLock(worker
->lock
);
5206 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
5207 thread_wakeup((event_t
) worker
);
5208 IOLockUnlock(worker
->lock
);
5213 DLOG("%s acknowledged without worker property\n",
5219 //******************************************************************************
5220 // notifySystemShutdown
5222 // Notify all objects in PM tree that system will shutdown or restart
5223 //******************************************************************************
5226 notifySystemShutdown( IOService
* root
, unsigned long event
)
5228 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
5229 IORegistryIterator
* iter
;
5230 IORegistryEntry
* entry
;
5233 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
5234 AbsoluteTime deadline
;
5235 unsigned int totalNodes
= 0;
5237 unsigned int rootDepth
;
5238 unsigned int numWorkers
;
5244 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
5246 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
5248 // Iterate the entire PM tree starting from root
5250 rootDepth
= root
->getDepth( gIOPowerPlane
);
5251 if (!rootDepth
) goto done
;
5253 // debug - for repeated test runs
5254 while (PMHaltWorker::metaClass
->getInstanceCount())
5259 gPMHaltArray
= OSArray::withCapacity(40);
5260 if (!gPMHaltArray
) goto done
;
5263 gPMHaltArray
->flushCollection();
5267 gPMHaltLock
= IOLockAlloc();
5268 if (!gPMHaltLock
) goto done
;
5271 if (!gPMHaltClientAcknowledgeKey
)
5273 gPMHaltClientAcknowledgeKey
=
5274 OSSymbol::withCStringNoCopy("PMShutdown");
5275 if (!gPMHaltClientAcknowledgeKey
) goto done
;
5278 gPMHaltEvent
= event
;
5280 // Depth-first walk of PM plane
5282 iter
= IORegistryIterator::iterateOver(
5283 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
5287 while ((entry
= iter
->getNextObject()))
5289 node
= OSDynamicCast(IOService
, entry
);
5294 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
5297 depth
= node
->getDepth( gIOPowerPlane
);
5298 if (depth
<= rootDepth
)
5303 // adjust to zero based depth
5304 depth
-= (rootDepth
+ 1);
5306 // gPMHaltArray is an array of containers, each container
5307 // refers to nodes with the same depth.
5309 count
= gPMHaltArray
->getCount();
5310 while (depth
>= count
)
5312 // expand array and insert placeholders
5313 gPMHaltArray
->setObject(PLACEHOLDER
);
5316 count
= gPMHaltArray
->getCount();
5319 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
5320 if (inner
== PLACEHOLDER
)
5322 inner
= OSSet::withCapacity(40);
5325 gPMHaltArray
->replaceObject(depth
, inner
);
5330 // PM nodes that appear more than once in the tree will have
5331 // the same depth, OSSet will refuse to add the node twice.
5333 ok
= inner
->setObject(node
);
5336 DLOG("Skipped PM node %s\n", node
->getName());
5342 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
5345 if (inner
!= PLACEHOLDER
)
5346 count
= inner
->getCount();
5347 DLOG("Nodes at depth %u = %u\n", i
, count
);
5350 // strip placeholders (not all depths are populated)
5352 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
5354 if (inner
== PLACEHOLDER
)
5356 gPMHaltArray
->removeObject(i
);
5359 count
= inner
->getCount();
5360 if (count
> numWorkers
)
5362 totalNodes
+= count
;
5366 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
5369 gPMHaltBusyCount
= 0;
5370 gPMHaltIdleCount
= 0;
5371 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
5373 // Create multiple workers (and threads)
5375 if (numWorkers
> kPMHaltMaxWorkers
)
5376 numWorkers
= kPMHaltMaxWorkers
;
5378 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
5379 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
5381 for (unsigned int i
= 0; i
< numWorkers
; i
++)
5382 workers
[i
] = PMHaltWorker::worker();
5384 // Wait for workers to exhaust all available work
5386 IOLockLock(gPMHaltLock
);
5387 while (gPMHaltDepth
>= 0)
5389 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
5391 waitResult
= IOLockSleepDeadline(
5392 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
5393 if (THREAD_TIMED_OUT
== waitResult
)
5396 clock_get_uptime(&now
);
5398 IOLockUnlock(gPMHaltLock
);
5399 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
5402 PMHaltWorker::checkTimeout(workers
[i
], &now
);
5404 IOLockLock(gPMHaltLock
);
5407 IOLockUnlock(gPMHaltLock
);
5409 // Release all workers
5411 for (unsigned int i
= 0; i
< numWorkers
; i
++)
5414 workers
[i
]->release();
5415 // worker also retained by it's own thread
5419 DLOG("%s done\n", __FUNCTION__
);
5423 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5425 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
5426 IOPMDriverAssertionType whichAssertionBits
,
5427 IOPMDriverAssertionLevel assertionLevel
,
5428 IOService
*ownerService
,
5429 const char *ownerDescription
)
5432 IOPMDriverAssertionID newAssertion
;
5437 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
5439 if (kIOReturnSuccess
== ret
)
5440 return newAssertion
;
5445 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
5448 return kIOReturnInternalError
;
5450 return pmAssertions
->releaseAssertion(releaseAssertion
);
5453 IOReturn
IOPMrootDomain::setPMAssertionLevel(
5454 IOPMDriverAssertionID assertionID
,
5455 IOPMDriverAssertionLevel assertionLevel
)
5457 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
5460 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
5462 IOPMDriverAssertionType sysLevels
;
5464 if (!pmAssertions
|| whichAssertion
== 0)
5465 return kIOPMDriverAssertionLevelOff
;
5467 sysLevels
= pmAssertions
->getActivatedAssertions();
5469 // Check that every bit set in argument 'whichAssertion' is asserted
5470 // in the aggregate bits.
5471 if ((sysLevels
& whichAssertion
) == whichAssertion
)
5472 return kIOPMDriverAssertionLevelOn
;
5474 return kIOPMDriverAssertionLevelOff
;
5477 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
5480 return kIOReturnNotFound
;
5482 return pmAssertions
->setUserAssertionLevels(inLevels
);
5485 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
5489 pmAssertions
->publishProperties();
5491 return( IOService::serializeProperties(s
) );
5494 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5498 #define super OSObject
5499 OSDefineMetaClassAndFinalStructors(PMSettingObject
, OSObject
)
5501 void PMSettingObject::setPMSetting(const OSSymbol
*type
, OSObject
*obj
)
5503 (*func
)(target
, type
, obj
, refcon
);
5507 * Static constructor/initializer for PMSettingObject
5509 PMSettingObject
*PMSettingObject::pmSettingObject(
5510 IOPMrootDomain
*parent_arg
,
5511 IOPMSettingControllerCallback handler_arg
,
5512 OSObject
*target_arg
,
5513 uintptr_t refcon_arg
,
5514 uint32_t supportedPowerSources
,
5515 const OSSymbol
* settings
[])
5517 uint32_t objCount
= 0;
5518 PMSettingObject
*pmso
;
5520 if( !parent_arg
|| !handler_arg
|| !settings
) return NULL
;
5522 // count OSSymbol entries in NULL terminated settings array
5523 while( settings
[objCount
] ) {
5526 if(0 == objCount
) return NULL
;
5528 pmso
= new PMSettingObject
;
5529 if(!pmso
|| !pmso
->init()) return NULL
;
5531 pmso
->parent
= parent_arg
;
5532 pmso
->func
= handler_arg
;
5533 pmso
->target
= target_arg
;
5534 pmso
->refcon
= refcon_arg
;
5535 pmso
->releaseAtCount
= objCount
+ 1; // release when it has count+1 retains
5537 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount
);
5538 if(pmso
->publishedFeatureID
) {
5539 for(unsigned int i
=0; i
<objCount
; i
++) {
5540 // Since there is now at least one listener to this setting, publish
5541 // PM root domain support for it.
5542 parent_arg
->publishFeature( settings
[i
]->getCStringNoCopy(),
5543 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
5550 void PMSettingObject::free(void)
5552 OSCollectionIterator
*settings_iter
;
5557 int objCount
= releaseAtCount
- 1;
5559 if(publishedFeatureID
) {
5560 for(i
=0; i
<objCount
; i
++) {
5561 if(0 != publishedFeatureID
[i
]) {
5562 parent
->removePublishedFeature( publishedFeatureID
[i
] );
5566 IOFree(publishedFeatureID
, sizeof(uint32_t) * objCount
);
5569 IORecursiveLockLock(parent
->settingsCtrlLock
);
5571 // Search each PM settings array in the kernel.
5572 settings_iter
= OSCollectionIterator::withCollection(parent
->settingsCallbacks
);
5575 while(( sym
= OSDynamicCast(OSSymbol
, settings_iter
->getNextObject()) ))
5577 arr
= (OSArray
*)parent
->settingsCallbacks
->getObject(sym
);
5578 arr_idx
= arr
->getNextIndexOfObject(this, 0);
5580 // 'this' was found in the array; remove it
5581 arr
->removeObject(arr_idx
);
5585 settings_iter
->release();
5588 IORecursiveLockUnlock(parent
->settingsCtrlLock
);
5593 void PMSettingObject::taggedRelease(const void *tag
, const int when
) const
5595 // We have n+1 retains - 1 per array that this PMSettingObject is a member
5596 // of, and 1 retain to ourself. When we get a release with n+1 retains
5597 // remaining, we go ahead and free ourselves, cleaning up array pointers
5600 super::taggedRelease(tag
, releaseAtCount
);
5604 // MARK: PMAssertionsTracker
5606 //*********************************************************************************
5607 //*********************************************************************************
5608 //*********************************************************************************
5609 // class PMAssertionsTracker Implementation
5611 #define kAssertUniqueIDStart 500
5613 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
5615 PMAssertionsTracker
*myself
;
5617 myself
= new PMAssertionsTracker
;
5621 myself
->owner
= rootDomain
;
5622 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
5623 myself
->assertionsArray
= OSArray::withCapacity(5);
5624 myself
->assertionsKernel
= 0;
5625 myself
->assertionsUser
= 0;
5626 myself
->assertionsCombined
= 0;
5627 myself
->assertionsArrayLock
= IOLockAlloc();
5628 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
5630 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
5638 * - Update assertionsKernel to reflect the state of all
5639 * assertions in the kernel.
5640 * - Update assertionsCombined to reflect both kernel & user space.
5642 void PMAssertionsTracker::tabulate(void)
5646 PMAssertStruct
*_a
= NULL
;
5649 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
5650 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
5654 assertionsKernel
= 0;
5655 assertionsCombined
= 0;
5657 if (!assertionsArray
)
5660 if ((count
= assertionsArray
->getCount()))
5662 for (i
=0; i
<count
; i
++)
5664 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
5667 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
5668 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
5669 assertionsKernel
|= _a
->assertionBits
;
5674 tabulateProducerCount
++;
5675 assertionsCombined
= assertionsKernel
| assertionsUser
;
5677 if ((assertionsKernel
!= oldKernel
) ||
5678 (assertionsCombined
!= oldCombined
))
5680 owner
->messageClients(kIOPMMessageDriverAssertionsChanged
);
5684 void PMAssertionsTracker::publishProperties( void )
5686 OSArray
*assertionsSummary
= NULL
;
5688 if (tabulateConsumerCount
!= tabulateProducerCount
)
5690 IOLockLock(assertionsArrayLock
);
5692 tabulateConsumerCount
= tabulateProducerCount
;
5694 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
5696 assertionsSummary
= copyAssertionsArray();
5697 if (assertionsSummary
)
5699 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
5700 assertionsSummary
->release();
5704 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
5707 /* Publish the IOPMrootDomain property "DriverPMAssertions"
5709 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
5711 IOLockUnlock(assertionsArrayLock
);
5715 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
5717 PMAssertStruct
*_a
= NULL
;
5724 && (count
= assertionsArray
->getCount()))
5726 for (i
=0; i
<count
; i
++)
5728 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
5731 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
5732 if (_a
&& (_id
== _a
->id
)) {
5749 /* PMAssertionsTracker::handleCreateAssertion
5750 * Perform assertion work on the PM workloop. Do not call directly.
5752 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
5758 IOLockLock(assertionsArrayLock
);
5759 assertionsArray
->setObject(newAssertion
);
5760 IOLockUnlock(assertionsArrayLock
);
5761 newAssertion
->release();
5765 return kIOReturnSuccess
;
5768 /* PMAssertionsTracker::createAssertion
5769 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
5772 IOReturn
PMAssertionsTracker::createAssertion(
5773 IOPMDriverAssertionType which
,
5774 IOPMDriverAssertionLevel level
,
5775 IOService
*serviceID
,
5776 const char *whoItIs
,
5777 IOPMDriverAssertionID
*outID
)
5779 OSData
*dataStore
= NULL
;
5780 PMAssertStruct track
;
5782 // Warning: trillions and trillions of created assertions may overflow the unique ID.
5784 track
.id
= issuingUniqueID
++; // FIXME: need OSIncrementAtomic64() for ppc
5786 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
5788 track
.level
= level
;
5789 track
.assertionBits
= which
;
5790 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
) : 0;
5791 track
.ownerService
= serviceID
;
5792 track
.modifiedTime
= 0;
5793 pmEventTimeStamp(&track
.createdTime
);
5795 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
5798 if (track
.ownerString
)
5799 track
.ownerString
->release();
5800 return kIOReturnNoMemory
;
5805 if (owner
&& owner
->pmPowerStateQueue
) {
5806 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
5809 return kIOReturnSuccess
;
5812 /* PMAssertionsTracker::handleReleaseAssertion
5813 * Runs in PM workloop. Do not call directly.
5815 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
5816 IOPMDriverAssertionID _id
)
5821 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
5824 return kIOReturnNotFound
;
5826 IOLockLock(assertionsArrayLock
);
5827 if (assertStruct
->ownerString
)
5828 assertStruct
->ownerString
->release();
5830 assertionsArray
->removeObject(index
);
5831 IOLockUnlock(assertionsArrayLock
);
5834 return kIOReturnSuccess
;
5837 /* PMAssertionsTracker::releaseAssertion
5838 * Releases an assertion and affects system behavior if appropiate.
5839 * Actual work happens on PM workloop.
5841 IOReturn
PMAssertionsTracker::releaseAssertion(
5842 IOPMDriverAssertionID _id
)
5844 if (owner
&& owner
->pmPowerStateQueue
) {
5845 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
5847 return kIOReturnSuccess
;
5850 /* PMAssertionsTracker::handleSetAssertionLevel
5851 * Runs in PM workloop. Do not call directly.
5853 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
5854 IOPMDriverAssertionID _id
,
5855 IOPMDriverAssertionLevel _level
)
5857 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
5861 if (!assertStruct
) {
5862 return kIOReturnNotFound
;
5865 IOLockLock(assertionsArrayLock
);
5866 pmEventTimeStamp(&assertStruct
->modifiedTime
);
5867 assertStruct
->level
= _level
;
5868 IOLockUnlock(assertionsArrayLock
);
5871 return kIOReturnSuccess
;
5874 /* PMAssertionsTracker::setAssertionLevel
5876 IOReturn
PMAssertionsTracker::setAssertionLevel(
5877 IOPMDriverAssertionID _id
,
5878 IOPMDriverAssertionLevel _level
)
5880 if (owner
&& owner
->pmPowerStateQueue
) {
5881 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
5882 (void *)_level
, _id
);
5885 return kIOReturnSuccess
;
5888 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
5890 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
5894 if (new_user_levels
!= assertionsUser
)
5896 assertionsUser
= new_user_levels
;
5897 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
5901 return kIOReturnSuccess
;
5904 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
5905 IOPMDriverAssertionType new_user_levels
)
5907 if (gIOPMWorkLoop
) {
5908 gIOPMWorkLoop
->runAction(
5909 OSMemberFunctionCast(
5912 &PMAssertionsTracker::handleSetUserAssertionLevels
),
5914 (void *) &new_user_levels
, 0, 0, 0);
5917 return kIOReturnSuccess
;
5921 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
5925 OSArray
*outArray
= NULL
;
5927 if (!assertionsArray
||
5928 (0 == (count
= assertionsArray
->getCount())) ||
5929 (NULL
== (outArray
= OSArray::withCapacity(count
))))
5934 for (i
=0; i
<count
; i
++)
5936 PMAssertStruct
*_a
= NULL
;
5938 OSDictionary
*details
= NULL
;
5940 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
5941 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
5943 OSNumber
*_n
= NULL
;
5945 details
= OSDictionary::withCapacity(7);
5949 outArray
->setObject(details
);
5952 _n
= OSNumber::withNumber(_a
->id
, 64);
5954 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
5957 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
5959 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
5962 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
5964 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
5967 _n
= OSNumber::withNumber((uintptr_t)_a
->ownerService
, 64);
5969 details
->setObject(kIOPMDriverAssertionOwnerServiceKey
, _n
);
5972 _n
= OSNumber::withNumber(_a
->level
, 64);
5974 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
5977 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
5979 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
5983 if (_a
->ownerString
) {
5984 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
5993 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
5995 return assertionsCombined
;
5998 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
5999 IOPMDriverAssertionType type
)
6001 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
6003 return kIOPMDriverAssertionLevelOn
;
6005 return kIOPMDriverAssertionLevelOff
;
6009 //*********************************************************************************
6010 //*********************************************************************************
6011 //*********************************************************************************
6013 static void pmEventTimeStamp(uint64_t *recordTS
)
6021 // We assume tsec fits into 32 bits; 32 bits holds enough
6022 // seconds for 136 years since the epoch in 1970.
6023 clock_get_calendar_microtime(&tsec
, &tusec
);
6026 // Pack the sec & microsec calendar time into a uint64_t, for fun.
6028 *recordTS
|= (uint32_t)tusec
;
6029 *recordTS
|= ((uint64_t)tsec
<< 32);
6034 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6037 #define super IOService
6039 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
6041 // This array exactly parallels the state array for the root domain.
6042 // Power state changes initiated by a device can be vetoed by a client of the device, and
6043 // power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
6044 // so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
6045 // its parent to make the change. That is the reason for this complexity.
6047 static IOPMPowerState patriarchPowerStates
[NUM_POWER_STATES
] =
6049 {1,0,0,0,0,0,0,0,0,0,0,0}, // off (not used)
6050 {1,0,RESTART_POWER
,0,0,0,0,0,0,0,0,0}, // reset (not used)
6051 {1,0,SLEEP_POWER
,0,0,0,0,0,0,0,0,0}, // sleep
6052 {1,0,DOZE_POWER
,0,0,0,0,0,0,0,0,0}, // doze
6053 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0}, // running
6056 bool IORootParent::start( IOService
* nub
)
6058 mostRecentChange
= ON_STATE
;
6060 attachToParent( getRegistryRoot(), gIOPowerPlane
);
6062 registerPowerDriver(this, patriarchPowerStates
, NUM_POWER_STATES
);
6064 powerOverrideOnPriv();
6068 void IORootParent::shutDownSystem( void )
6072 void IORootParent::restartSystem( void )
6076 void IORootParent::sleepSystem( void )
6078 mostRecentChange
= SLEEP_STATE
;
6079 changePowerStateToPriv(SLEEP_STATE
);
6082 void IORootParent::dozeSystem( void )
6084 mostRecentChange
= DOZE_STATE
;
6085 changePowerStateToPriv(DOZE_STATE
);
6088 // Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
6089 // This brings the parent to doze, which allows the root to step up from sleep to doze.
6091 // In idle sleep, do nothing because the parent is still on and the root can freely change state.
6093 void IORootParent::sleepToDoze( void )
6095 if ( mostRecentChange
== SLEEP_STATE
) {
6096 changePowerStateToPriv(DOZE_STATE
);
6100 void IORootParent::wakeSystem( void )
6102 mostRecentChange
= ON_STATE
;
6103 changePowerStateToPriv(ON_STATE
);