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;
3171 informCPUStateChange(kInformLid
, 0);
3173 // Tell general interest clients
3174 sendClientClamshellNotification();
3176 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
3177 || (lastSleepReason
== kIOPMSleepReasonIdle
)
3178 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
3179 if (aborting
) userActivityCount
++;
3180 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
3185 * Send the clamshell interest notification since the lid is closing.
3187 if (msg
& kIOPMClamshellClosed
)
3189 // Received clamshel open message from clamshell controlling driver
3190 // Update our internal state and tell general interest clients
3191 clamshellIsClosed
= true;
3192 clamshellExists
= true;
3195 informCPUStateChange(kInformLid
, 1);
3197 // Tell general interest clients
3198 sendClientClamshellNotification();
3200 // And set eval_clamshell = so we can attempt
3201 eval_clamshell
= true;
3205 * Set Desktop mode (sent from graphics)
3207 * -> reevaluate lid state
3209 if (msg
& kIOPMSetDesktopMode
)
3211 desktopMode
= (0 != (msg
& kIOPMSetValue
));
3212 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
3214 sendClientClamshellNotification();
3216 // Re-evaluate the lid state
3217 if( clamshellIsClosed
)
3219 eval_clamshell
= true;
3224 * AC Adaptor connected
3226 * -> reevaluate lid state
3228 if (msg
& kIOPMSetACAdaptorConnected
)
3230 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
3231 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
3234 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
3236 // Tell BSD if AC is connected
3237 // 0 == external power source; 1 == on battery
3238 post_sys_powersource(acAdaptorConnected
? 0:1);
3240 sendClientClamshellNotification();
3242 // Re-evaluate the lid state
3243 if( clamshellIsClosed
)
3245 eval_clamshell
= true;
3250 * Enable Clamshell (external display disappear)
3252 * -> reevaluate lid state
3254 if (msg
& kIOPMEnableClamshell
)
3256 // Re-evaluate the lid state
3257 // System should sleep on external display disappearance
3258 // in lid closed operation.
3259 if( clamshellIsClosed
&& (true == ignoringClamshell
) )
3261 eval_clamshell
= true;
3264 ignoringClamshell
= false;
3266 sendClientClamshellNotification();
3270 * Disable Clamshell (external display appeared)
3271 * We don't bother re-evaluating clamshell state. If the system is awake,
3272 * the lid is probably open.
3274 if (msg
& kIOPMDisableClamshell
)
3276 ignoringClamshell
= true;
3278 sendClientClamshellNotification();
3282 * Evaluate clamshell and SLEEP if appropiate
3284 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
3289 privateSleepSystem (kIOPMSleepReasonClamshell
);
3295 if (msg
& kIOPMPowerButton
)
3297 // toggle state of sleep/wake
3299 if ( getPowerState() == DOZE_STATE
)
3302 // yes, tell the tree we're waking
3305 // wake the Display Wrangler
3309 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
3310 // Check that power button sleep is enabled
3312 if( kOSBooleanTrue
!= getProperty(pbs
))
3313 privateSleepSystem (kIOPMSleepReasonPowerButton
);
3322 if ( (msg
& kIOPMAllowSleep
) && !allowSleep
)
3332 if (msg
& kIOPMPreventSleep
) {
3335 if ( getPowerState() == DOZE_STATE
) {
3337 // yes, tell the tree we're waking
3341 // wake the Display Wrangler
3345 // make sure we have power to clamp
3346 patriarch
->wakeSystem();
3352 //******************************************************************************
3353 // getSleepSupported
3355 //******************************************************************************
3357 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3359 return( platformSleepSupport
);
3363 //******************************************************************************
3364 // setSleepSupported
3366 //******************************************************************************
3368 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3370 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3371 OSBitOrAtomic(flags
, &platformSleepSupport
);
3375 //******************************************************************************
3376 // requestPowerDomainState
3378 // The root domain intercepts this call to the superclass.
3379 // Called on the PM work loop thread.
3381 // If the clamp bit is not set in the desire, then the child doesn't need the power
3382 // state it's requesting; it just wants it. The root ignores desires but not needs.
3383 // If the clamp bit is not set, the root takes it that the child can tolerate no
3384 // power and interprets the request accordingly. If all children can thus tolerate
3385 // no power, we are on our way to idle sleep.
3386 //******************************************************************************
3388 IOReturn
IOPMrootDomain::requestPowerDomainState (
3389 IOPMPowerFlags desiredFlags
,
3390 IOPowerConnection
* whichChild
,
3391 unsigned long specification
)
3395 IOPowerConnection
*connection
;
3396 IOPMPowerFlags powerRequestFlag
= 0;
3397 IOPMPowerFlags editedDesire
;
3401 if (kIOLogPMRootDomain
& gIOKitDebug
)
3403 IOService
* powerChild
=
3404 (IOService
*) whichChild
->getChildEntry(gIOPowerPlane
);
3405 DLOG("child %p, flags %lx, spec %lx - %s\n",
3406 powerChild
, desiredFlags
, specification
,
3407 powerChild
? powerChild
->getName() : "?");
3410 // Force the child's input power requirements to 0 unless the prevent
3411 // idle-sleep flag is set. No input power flags map to our state 0.
3412 // Our power clamp (deviceDesire) keeps the minimum power state at 2.
3414 if (desiredFlags
& kIOPMPreventIdleSleep
)
3415 editedDesire
= kIOPMPreventIdleSleep
| kIOPMPowerOn
;
3419 // Recompute sleep supported flag (doze if not supported)
3420 sleepIsSupported
= true;
3422 iter
= getChildIterator(gIOPowerPlane
);
3425 while ( (next
= iter
->getNextObject()) )
3427 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
3429 // Ignore child that are in the process of joining.
3430 if (connection
->getReadyFlag() == false)
3433 // Is this connection attached to the child that called
3434 // requestPowerDomainState()?
3436 if (connection
== whichChild
)
3438 // OR in the child's input power requirements.
3439 powerRequestFlag
|= editedDesire
;
3441 if ( desiredFlags
& kIOPMPreventSystemSleep
)
3442 sleepIsSupported
= false;
3446 if (kIOLogPMRootDomain
& gIOKitDebug
)
3448 IOService
* powerChild
=
3449 (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
3450 DLOG("child %p, state %ld, noIdle %d, noSleep %d - %s\n",
3452 connection
->getDesiredDomainState(),
3453 connection
->getPreventIdleSleepFlag(),
3454 connection
->getPreventSystemSleepFlag(),
3455 powerChild
? powerChild
->getName() : "?");
3458 // OR in the child's desired power state (0 or ON_STATE).
3459 powerRequestFlag
|= connection
->getDesiredDomainState();
3461 if ( connection
->getPreventSystemSleepFlag() )
3462 sleepIsSupported
= false;
3469 DLOG("childPowerFlags 0x%lx, extraSleepDelay %ld\n",
3470 powerRequestFlag
, extraSleepDelay
);
3472 if ( !powerRequestFlag
&& !systemBooting
)
3477 changePowerStateToPriv(ON_STATE
);
3480 // stay awake for at least idleSeconds
3481 startIdleSleepTimer(idleSeconds
);
3484 else if (!extraSleepDelay
&& !idleSleepTimerPending
)
3490 // Drop our power clamp to SLEEP_STATE when all children became idle,
3491 // and the system sleep and display sleep values are equal.
3495 // If our power clamp has already dropped to SLEEP_STATE, and no child
3496 // is keeping us at ON_STATE, then this will trigger idle sleep.
3498 editedDesire
|= (desiredFlags
& kIOPMPreventSystemSleep
);
3500 return super::requestPowerDomainState(
3501 editedDesire
, whichChild
, specification
);
3505 //******************************************************************************
3506 // handlePlatformHaltRestart
3508 //******************************************************************************
3510 struct HaltRestartApplierContext
{
3511 IOPMrootDomain
* RootDomain
;
3512 unsigned long PowerState
;
3513 IOPMPowerFlags PowerFlags
;
3519 platformHaltRestartApplier( OSObject
* object
, void * context
)
3521 IOPowerStateChangeNotification notify
;
3522 HaltRestartApplierContext
* ctx
;
3523 AbsoluteTime startTime
;
3526 ctx
= (HaltRestartApplierContext
*) context
;
3528 memset(¬ify
, 0, sizeof(notify
));
3529 notify
.powerRef
= (void *)ctx
->Counter
;
3530 notify
.returnValue
= 0;
3531 notify
.stateNumber
= ctx
->PowerState
;
3532 notify
.stateFlags
= ctx
->PowerFlags
;
3534 clock_get_uptime(&startTime
);
3535 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
3536 deltaTime
= computeDeltaTimeMS(&startTime
);
3538 if ((deltaTime
> kPMHaltTimeoutMS
) || (gIOKitDebug
& kIOLogDebugPower
))
3540 _IOServiceInterestNotifier
* notifier
;
3541 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
3543 // IOService children of IOPMrootDomain are not instrumented.
3544 // Only IORootParent currently falls under that group.
3548 KLOG("%s handler %p took %u ms\n",
3549 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ?
3550 "PowerOff" : "Restart",
3551 notifier
->handler
, (uint32_t) deltaTime
);
3558 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
3560 HaltRestartApplierContext ctx
;
3561 AbsoluteTime startTime
;
3564 memset(&ctx
, 0, sizeof(ctx
));
3565 ctx
.RootDomain
= this;
3567 clock_get_uptime(&startTime
);
3571 case kPEUPSDelayHaltCPU
:
3572 ctx
.PowerState
= OFF_STATE
;
3573 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
3577 ctx
.PowerState
= RESTART_STATE
;
3578 ctx
.MessageType
= kIOMessageSystemWillRestart
;
3585 // Notify legacy clients
3586 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
3588 // For UPS shutdown leave File Server Mode intact, otherwise turn it off.
3589 if (kPEUPSDelayHaltCPU
!= pe_type
)
3591 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
3592 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
3595 setPMSetting(setting
, num
);
3601 // Notify in power tree order
3602 notifySystemShutdown(this, ctx
.MessageType
);
3604 deltaTime
= computeDeltaTimeMS(&startTime
);
3605 KLOG("%s all drivers took %u ms\n",
3606 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ?
3607 "PowerOff" : "Restart",
3608 (uint32_t) deltaTime
);
3612 //******************************************************************************
3615 //******************************************************************************
3617 IONotifier
* IOPMrootDomain::registerInterest(
3618 const OSSymbol
* typeOfInterest
,
3619 IOServiceInterestHandler handler
,
3620 void * target
, void * ref
)
3622 IONotifier
* notifier
;
3625 isConfigd
= typeOfInterest
&&
3626 typeOfInterest
->isEqualTo(kIOPMPrivilegedPowerInterest
);
3629 typeOfInterest
= gIOAppPowerStateInterest
;
3631 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
3633 #if ROOT_DOMAIN_RUN_STATES
3634 if (isConfigd
&& notifier
&& pmPowerStateQueue
)
3637 if (pmPowerStateQueue
->submitPowerEvent(
3638 kPowerEventConfigdRegisteredInterest
, notifier
) == false)
3639 notifier
->release();
3646 static bool clientMessageFilter( OSObject
* object
, void * arg
)
3648 #if ROOT_DOMAIN_RUN_STATES
3649 #if LOG_INTEREST_CLIENTS
3650 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
3654 switch (gMessageClientType
)
3656 case kMessageClientNone
:
3660 case kMessageClientAll
:
3664 case kMessageClientConfigd
:
3665 allow
= ((object
== (OSObject
*) gConfigdNotifier
) ||
3666 (object
== (OSObject
*) gSysPowerDownNotifier
));
3670 #if LOG_INTEREST_CLIENTS
3672 DLOG("system message %x to %p\n",
3673 context
->msgType
, object
);
3683 //******************************************************************************
3686 // We override the superclass implementation so we can send a different message
3687 // type to the client or application being notified.
3688 //******************************************************************************
3690 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
3694 DLOG("tellChangeDown %u->%u, R-state %u\n",
3695 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3697 switch ( stateNum
) {
3701 if (!ignoreChangeDown
)
3703 userActivityAtSleep
= userActivityCount
;
3704 hibernateAborted
= false;
3705 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
3707 // Direct callout into OSKext so it can disable kext unloads
3708 // during sleep/wake to prevent deadlocks.
3709 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
3711 if ( (SLEEP_STATE
== stateNum
) && sleepSupportedPEFunction
)
3713 // Reset PCI prevent sleep flag before calling platform driver.
3714 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
3716 // Skip PCI check for maintenance sleep.
3717 if ((runStateFlags
& kRStateFlagSuppressPCICheck
) == 0)
3719 // Determine if the machine supports sleep, or must doze.
3720 getPlatform()->callPlatformFunction(
3721 sleepSupportedPEFunction
, false,
3722 NULL
, NULL
, NULL
, NULL
);
3725 // If the machine only supports doze, the callPlatformFunction call
3726 // boils down to IOPMrootDomain::setSleepSupported(kPCICantSleep),
3727 // otherwise nothing.
3730 // Notify platform that sleep has begun
3731 getPlatform()->callPlatformFunction(
3732 sleepMessagePEFunction
, false,
3733 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
3736 // Update canSleep and kIOSleepSupportedKey property so drivers
3737 // can tell if platform is going to sleep versus doze.
3744 if (!sleepIsSupported
)
3746 if (platformSleepSupport
& kPCICantSleep
)
3748 setProperty(kIOSleepSupportedKey
, canSleep
);
3749 DLOG("canSleep %d\n", canSleep
);
3751 // Publish the new sleep-wake UUID
3752 publishSleepWakeUUID(true);
3754 // Two change downs are sent by IOServicePM. Ignore the 2nd.
3755 ignoreChangeDown
= true;
3757 tracePoint( kIOPMTracePointSystemSleepAppsPhase
);
3760 DLOG("kIOMessageSystemWillSleep (%d)\n", gMessageClientType
);
3761 done
= super::tellClientsWithResponse(
3762 kIOMessageSystemWillSleep
, clientMessageFilter
);
3766 done
= super::tellChangeDown(stateNum
);
3773 //******************************************************************************
3776 // We override the superclass implementation so we can send a different message
3777 // type to the client or application being notified.
3779 // This must be idle sleep since we don't ask during any other power change.
3780 //******************************************************************************
3782 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
3784 DLOG("askChangeDown %u->%u, R-state %u\n",
3785 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3786 DLOG("kIOMessageCanSystemSleep (%d)\n", gMessageClientType
);
3788 return super::tellClientsWithResponse(
3789 kIOMessageCanSystemSleep
,
3790 clientMessageFilter
);
3794 //******************************************************************************
3797 // Notify registered applications and kernel clients that we are not dropping
3800 // We override the superclass implementation so we can send a different message
3801 // type to the client or application being notified.
3803 // This must be a vetoed idle sleep, since no other power change can be vetoed.
3804 //******************************************************************************
3806 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
3808 DLOG("tellNoChangeDown %u->%u, R-state %u\n",
3809 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3811 // Sleep canceled, clear the sleep trace point.
3812 tracePoint(kIOPMTracePointSystemUp
);
3814 if (idleSeconds
&& !wrangler
)
3816 // stay awake for at least idleSeconds
3818 startIdleSleepTimer(idleSeconds
);
3820 DLOG("kIOMessageSystemWillNotSleep (%d)\n", gMessageClientType
);
3821 return tellClients(kIOMessageSystemWillNotSleep
, clientMessageFilter
);
3825 //******************************************************************************
3828 // Notify registered applications and kernel clients that we are raising power.
3830 // We override the superclass implementation so we can send a different message
3831 // type to the client or application being notified.
3832 //******************************************************************************
3834 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
3836 OSData
*publishPMStats
= NULL
;
3838 DLOG("tellChangeUp %u->%u, R-state %u\n",
3839 (uint32_t) getPowerState(), (uint32_t) stateNum
, runStateIndex
);
3841 ignoreChangeDown
= false;
3843 if ( stateNum
== ON_STATE
)
3845 // Direct callout into OSKext so it can disable kext unloads
3846 // during sleep/wake to prevent deadlocks.
3847 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
3849 // Notify platform that sleep was cancelled or resumed.
3850 getPlatform()->callPlatformFunction(
3851 sleepMessagePEFunction
, false,
3852 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
3855 if (getPowerState() == ON_STATE
)
3857 // this is a quick wake from aborted sleep
3858 if (idleSeconds
&& !wrangler
)
3860 // stay awake for at least idleSeconds
3862 startIdleSleepTimer(idleSeconds
);
3864 DLOG("kIOMessageSystemWillPowerOn (%d)\n", gMessageClientType
);
3865 tellClients(kIOMessageSystemWillPowerOn
, clientMessageFilter
);
3870 IOHibernateSystemPostWake();
3874 tracePoint(kIOPMTracePointSystemWakeAppsPhase
);
3875 publishPMStats
= OSData::withBytes(&pmStats
, sizeof(pmStats
));
3876 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
3877 publishPMStats
->release();
3878 bzero(&pmStats
, sizeof(pmStats
));
3880 if (pmStatsAppResponses
)
3882 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
3883 pmStatsAppResponses
->release();
3884 pmStatsAppResponses
= OSArray::withCapacity(5);
3887 DLOG("kIOMessageSystemHasPoweredOn (%d)\n", gMessageClientType
);
3888 tellClients(kIOMessageSystemHasPoweredOn
, clientMessageFilter
);
3890 tracePoint(kIOPMTracePointSystemUp
);
3895 //******************************************************************************
3898 //******************************************************************************
3900 void IOPMrootDomain::reportUserInput( void )
3907 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
3910 wrangler
= (IOService
*) iter
->getNextObject();
3916 wrangler
->activityTickle(0,0);
3921 //******************************************************************************
3922 // setQuickSpinDownTimeout
3924 //******************************************************************************
3926 void IOPMrootDomain::setQuickSpinDownTimeout( void )
3930 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
3934 //******************************************************************************
3935 // restoreUserSpinDownTimeout
3937 //******************************************************************************
3939 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
3943 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
3947 //******************************************************************************
3948 // changePowerStateTo & changePowerStateToPriv
3950 // Override of these methods for logging purposes.
3951 //******************************************************************************
3953 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3955 return kIOReturnUnsupported
; // ignored
3958 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3960 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3962 if ( (getPowerState() == DOZE_STATE
) && (ordinal
!= ON_STATE
) )
3964 return kIOReturnSuccess
;
3967 if ( (userDisabledAllSleep
|| systemBooting
|| systemShutdown
) &&
3968 (ordinal
== SLEEP_STATE
) )
3970 DLOG("SLEEP rejected, forced to ON state (UD %d, SB %d, SS %d)\n",
3971 userDisabledAllSleep
, systemBooting
, systemShutdown
);
3973 super::changePowerStateToPriv(ON_STATE
);
3976 return super::changePowerStateToPriv(ordinal
);
3979 //******************************************************************************
3982 //******************************************************************************
3984 bool IOPMrootDomain::activitySinceSleep(void)
3986 return (userActivityCount
!= userActivityAtSleep
);
3989 bool IOPMrootDomain::abortHibernation(void)
3991 bool ret
= activitySinceSleep();
3993 if (ret
&& !hibernateAborted
)
3995 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3996 hibernateAborted
= true;
4002 hibernate_should_abort(void)
4005 return (gRootDomain
->abortHibernation());
4010 //******************************************************************************
4013 //******************************************************************************
4015 void IOPMrootDomain::updateRunState( uint32_t inRunState
)
4017 #if ROOT_DOMAIN_RUN_STATES
4018 if (inRunState
< kRStateCount
)
4020 runStateIndex
= nextRunStateIndex
= inRunState
;
4021 runStateFlags
= gRStateFlags
[inRunState
];
4024 kIOPMRootDomainRunStateKey
,
4025 (unsigned long long) inRunState
, 32);
4031 #if ROOT_DOMAIN_RUN_STATES
4032 //******************************************************************************
4033 // tagPowerPlaneService
4035 // Running on PM work loop thread.
4036 //******************************************************************************
4038 void IOPMrootDomain::tagPowerPlaneService(
4039 IOService
* service
,
4040 uint32_t * rdFlags
)
4044 if (service
->getProperty("IOPMStrictTreeOrder") ||
4045 service
->metaCast("IODisplayWrangler") ||
4046 OSDynamicCast(OSNumber
,
4047 service
->getProperty("IOPMUnattendedWakePowerState")))
4049 *rdFlags
|= kServiceFlagGraphics
;
4050 DLOG("tagged device %s %x\n", service
->getName(), *rdFlags
);
4053 // Locate the first PCI host bridge.
4054 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4056 IOService
* provider
= service
->getProvider();
4057 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4058 provider
->inPlane(gIODTPlane
))
4060 pciHostBridgeDevice
= provider
;
4061 DLOG("PMTrace found PCI host bridge %s->%s\n",
4062 provider
->getName(), service
->getName());
4066 // Tag top-level PCI devices. The order of PMinit() call does not
4067 // change across boots and is used as the PCI bit number.
4068 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4070 // Would prefer to check built-in property, but tagPowerPlaneService()
4071 // is called before pciDevice->registerService().
4072 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4073 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4075 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4078 // Save the assigned bit for fast lookup.
4080 *rdFlags
|= (kServiceFlagTopLevelPCI
| (bit
<< 8));
4087 //******************************************************************************
4088 // handleActivityTickleForService
4090 // Called by IOService::activityTickle() for a tickle that is requesting the
4091 // service to raise power state. Called from driver thread.
4092 //******************************************************************************
4094 void IOPMrootDomain::handleActivityTickleForService( IOService
* service
,
4096 unsigned long currentPowerState
,
4097 uint32_t activityTickleCount
)
4099 if ((service
== wrangler
)
4102 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
4103 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
4104 if (aborting
) userActivityCount
++;
4105 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
4108 // Tickle directed to IODisplayWrangler while graphics is disabled.
4109 // Bring graphics online.
4111 if ((!currentPowerState
) &&
4112 (service
== wrangler
) &&
4113 (runStateIndex
> kRStateNormal
) &&
4114 (false == wranglerTickled
) &&
4115 (false == lowBatteryCondition
))
4117 DLOG("display wrangler tickled\n");
4118 if (kIOLogPMRootDomain
& gIOKitDebug
)
4119 OSReportWithBacktrace("Display Tickle");
4120 wranglerTickled
= true;
4121 synchronizePowerTree();
4125 //******************************************************************************
4126 // handlePowerChangeStartForService
4128 // Running on PM work loop thread.
4129 //******************************************************************************
4131 void IOPMrootDomain::handlePowerChangeStartForService(
4132 IOService
* service
,
4134 uint32_t newPowerState
,
4135 uint32_t changeFlags
)
4137 if (service
== this)
4139 uint32_t currentPowerState
= (uint32_t) getPowerState();
4140 uint32_t nextRunStateFlags
;
4142 assert(nextRunStateIndex
< kRStateCount
);
4143 nextRunStateFlags
= gRStateFlags
[nextRunStateIndex
];
4145 gMessageClientType
= kMessageClientNone
;
4147 // Transition towards or away from ON power state.
4149 if ((currentPowerState
!= newPowerState
) &&
4150 ((ON_STATE
== newPowerState
) || (ON_STATE
== currentPowerState
)))
4152 if ((runStateFlags
& kRStateFlagSuppressMessages
) == 0)
4153 gMessageClientType
= kMessageClientAll
;
4155 gMessageClientType
= kMessageClientConfigd
;
4158 // Transition caused by deassertion of system notification suppression.
4160 if ((ON_STATE
== newPowerState
) &&
4161 (ON_STATE
== currentPowerState
) &&
4162 ((runStateFlags
^ nextRunStateFlags
) & kRStateFlagSuppressMessages
))
4164 gMessageClientType
= kMessageClientAll
;
4167 if (ON_STATE
== newPowerState
)
4169 DLOG("kIOMessageSystemWillPowerOn (%d)\n",
4170 gMessageClientType
);
4171 tellClients(kIOMessageSystemWillPowerOn
, clientMessageFilter
);
4174 if (SLEEP_STATE
== newPowerState
)
4176 tracePoint(kIOPMTracePointSleepStarted
);
4180 if (*rdFlags
& kServiceFlagTopLevelPCI
)
4182 pmTracer
->tracePCIPowerChange(
4183 PMTraceWorker::kPowerChangeStart
,
4184 service
, changeFlags
,
4185 (*rdFlags
>> 8) & 0xff);
4190 //******************************************************************************
4191 // handlePowerChangeDoneForService
4193 // Running on PM work loop thread.
4194 //******************************************************************************
4196 void IOPMrootDomain::handlePowerChangeDoneForService(
4197 IOService
* service
,
4199 uint32_t newPowerState
,
4200 uint32_t changeFlags
)
4202 if (*rdFlags
& kServiceFlagTopLevelPCI
)
4204 pmTracer
->tracePCIPowerChange(
4205 PMTraceWorker::kPowerChangeCompleted
,
4206 service
, changeFlags
,
4207 (*rdFlags
>> 8) & 0xff);
4212 //******************************************************************************
4213 // overridePowerStateForService
4215 // Runs on PM work loop thread.
4216 //******************************************************************************
4218 void IOPMrootDomain::overridePowerStateForService(
4219 IOService
* service
,
4221 unsigned long * powerState
,
4222 uint32_t changeFlags
)
4224 uint32_t inPowerState
= (uint32_t) *powerState
;
4226 if ((service
== this) && (inPowerState
== ON_STATE
) &&
4227 (changeFlags
& kIOPMSynchronize
))
4229 DLOG("sync root domain %u->%u\n",
4230 (uint32_t) getPowerState(), inPowerState
);
4232 // Root Domain is in a reduced R-state, and a HID tickle has
4233 // requested a PM tree sync. Begin R-state transition.
4235 if (runStateIndex
!= kRStateNormal
)
4237 sleepTimerMaintenance
= false;
4238 hibernateNoDefeat
= false;
4239 nextRunStateIndex
= kRStateNormal
;
4241 kIOPMRootDomainRunStateKey
,
4242 (unsigned long long) kRStateNormal
, 32);
4246 if (*rdFlags
& kServiceFlagGraphics
)
4248 DLOG("graphics device %s %u->%u (flags 0x%x)\n",
4249 service
->getName(), (uint32_t) service
->getPowerState(),
4250 inPowerState
, changeFlags
);
4252 if (inPowerState
== 0)
4254 // Graphics device is powering down, apply limit preventing
4255 // device from powering back up later unless we consent.
4257 if ((*rdFlags
& kServiceFlagNoPowerUp
) == 0)
4259 *rdFlags
|= kServiceFlagNoPowerUp
;
4260 DLOG("asserted power limit for %s\n",
4261 service
->getName());
4266 uint32_t nextRunStateFlags
;
4268 assert(nextRunStateIndex
< kRStateCount
);
4269 nextRunStateFlags
= gRStateFlags
[nextRunStateIndex
];
4271 // Graphics device is powering up. Release power limit at the
4272 // did-change machine state.
4274 if (changeFlags
& kIOPMSynchronize
)
4276 if ((runStateFlags
& kRStateFlagSuppressGraphics
) &&
4277 ((nextRunStateFlags
& kRStateFlagSuppressGraphics
) == 0) &&
4278 (changeFlags
& kIOPMDomainDidChange
))
4280 // Woke up without graphics power, but
4281 // HID event has tickled display wrangler.
4282 *rdFlags
&= ~kServiceFlagNoPowerUp
;
4283 DLOG("removed power limit for %s\n",
4284 service
->getName());
4287 else if ((runStateFlags
& kRStateFlagSuppressGraphics
) == 0)
4289 *rdFlags
&= ~kServiceFlagNoPowerUp
;
4292 if (*rdFlags
& kServiceFlagNoPowerUp
)
4294 DLOG("limited %s to power state 0\n",
4295 service
->getName());
4303 //******************************************************************************
4304 // setMaintenanceWakeCalendar
4306 //******************************************************************************
4308 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
4309 const IOPMCalendarStruct
* calendar
)
4315 return kIOReturnBadArgument
;
4317 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
4319 return kIOReturnNoMemory
;
4321 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
4326 #endif /* ROOT_DOMAIN_RUN_STATES */
4329 //******************************************************************************
4330 // sysPowerDownHandler
4332 // Receives a notification when the RootDomain changes state.
4334 // Allows us to take action on system sleep, power down, and restart after
4335 // applications have received their power change notifications and replied,
4336 // but before drivers have powered down. We perform a vfs sync on power down.
4337 //******************************************************************************
4339 IOReturn
IOPMrootDomain::sysPowerDownHandler( void * target
, void * refCon
,
4340 UInt32 messageType
, IOService
* service
,
4341 void * messageArgument
, vm_size_t argSize
)
4344 IOPowerStateChangeNotification
*params
= (IOPowerStateChangeNotification
*) messageArgument
;
4345 IOPMrootDomain
*rootDomain
= OSDynamicCast(IOPMrootDomain
, service
);
4347 DLOG("sysPowerDownHandler message %x\n", (uint32_t) messageType
);
4350 return kIOReturnUnsupported
;
4352 switch (messageType
) {
4353 case kIOMessageSystemWillSleep
:
4354 // Interested applications have been notified of an impending power
4355 // change and have acked (when applicable).
4356 // This is our chance to save whatever state we can before powering
4358 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
4361 rootDomain
->evaluateSystemSleepPolicyEarly();
4362 if (rootDomain
->hibernateMode
&& !rootDomain
->hibernateDisabled
)
4364 // We will ack within 240 seconds
4365 params
->returnValue
= 240 * 1000 * 1000;
4369 // We will ack within 20 seconds
4370 params
->returnValue
= 20 * 1000 * 1000;
4371 DLOG("sysPowerDownHandler timeout %d s\n", (int) (params
->returnValue
/ 1000 / 1000));
4372 if ( ! OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
4374 // Purposely delay the ack and hope that shutdown occurs quickly.
4375 // Another option is not to schedule the thread and wait for
4377 AbsoluteTime deadline
;
4378 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
4379 thread_call_enter1_delayed( rootDomain
->diskSyncCalloutEntry
,
4380 (thread_call_param_t
)params
->powerRef
,
4384 thread_call_enter1(rootDomain
->diskSyncCalloutEntry
, (thread_call_param_t
)params
->powerRef
);
4385 ret
= kIOReturnSuccess
;
4388 case kIOMessageSystemWillPowerOff
:
4389 case kIOMessageSystemWillRestart
:
4390 ret
= kIOReturnUnsupported
;
4394 ret
= kIOReturnUnsupported
;
4400 //******************************************************************************
4401 // publishSleepWakeUUID
4404 //******************************************************************************
4405 void IOPMrootDomain::publishSleepWakeUUID( bool shouldPublish
)
4409 if (queuedSleepWakeUUIDString
)
4411 if (OSCompareAndSwap(/*old*/ true, /*new*/ false, &gSleepWakeUUIDIsSet
))
4413 // Upon wake, it takes some time for userland to invalidate the
4414 // UUID. If another sleep is initiated during that period, force
4415 // a CLEAR message to balance the upcoming SET message.
4417 messageClients( kIOPMMessageSleepWakeUUIDChange
,
4418 kIOPMMessageSleepWakeUUIDCleared
);
4420 DLOG("SleepWake UUID forced clear\n");
4423 setProperty(kIOPMSleepWakeUUIDKey
, queuedSleepWakeUUIDString
);
4424 DLOG("SleepWake UUID published: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
4425 queuedSleepWakeUUIDString
->release();
4426 queuedSleepWakeUUIDString
= NULL
;
4427 messageClients(kIOPMMessageSleepWakeUUIDChange
,
4428 kIOPMMessageSleepWakeUUIDSet
);
4431 if (OSCompareAndSwap(/*old*/ true, /*new*/ false, &gSleepWakeUUIDIsSet
))
4433 DLOG("SleepWake UUID cleared\n");
4434 removeProperty(kIOPMSleepWakeUUIDKey
);
4435 messageClients(kIOPMMessageSleepWakeUUIDChange
,
4436 kIOPMMessageSleepWakeUUIDCleared
);
4442 //******************************************************************************
4443 // displayWranglerNotification
4445 // Receives a notification when the IODisplayWrangler changes state.
4447 // Allows us to take action on display dim/undim.
4449 // When the display sleeps we:
4450 // - Start the idle sleep timer
4451 // - set the quick spin down timeout
4453 // On wake from display sleep:
4454 // - Cancel the idle sleep timer
4455 // - restore the user's chosen spindown timer from the "quick" spin down value
4456 //******************************************************************************
4458 IOReturn
IOPMrootDomain::displayWranglerNotification(
4459 void * target
, void * refCon
,
4460 UInt32 messageType
, IOService
* service
,
4461 void * messageArgument
, vm_size_t argSize
)
4464 int displayPowerState
;
4465 IOPowerStateChangeNotification
* params
=
4466 (IOPowerStateChangeNotification
*) messageArgument
;
4468 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
4469 (messageType
!= kIOMessageDeviceHasPoweredOn
))
4470 return kIOReturnUnsupported
;
4474 return kIOReturnUnsupported
;
4476 displayPowerState
= params
->stateNumber
;
4477 DLOG("DisplayWrangler message 0x%x, new power state %d\n",
4478 (uint32_t) messageType
, displayPowerState
);
4480 switch (messageType
) {
4481 case kIOMessageDeviceWillPowerOff
:
4483 // The display wrangler has dropped power because of idle display sleep
4484 // or force system sleep.
4489 // 1 Not visible to user
4490 // 0 Not visible to user
4492 if (gRootDomain
->wranglerAsleep
|| (displayPowerState
> 2))
4495 // Record the time the display wrangler went to sleep.
4497 gRootDomain
->wranglerAsleep
= true;
4498 clock_get_uptime(&gRootDomain
->wranglerSleepTime
);
4500 // We start a timer here if the System Sleep timer is greater than the
4501 // Display Sleep timer. We kick off this timer when the display sleeps.
4503 // Note that, although Display Dim timings may change adaptively accordingly
4504 // to the user's activity patterns, Display Sleep _always_ occurs at the
4505 // specified interval since last user activity.
4507 if ( gRootDomain
->extraSleepDelay
)
4509 gRootDomain
->startIdleSleepTimer(gRootDomain
->extraSleepDelay
* 60);
4511 else if ( gRootDomain
->sleepSlider
)
4513 // Accelerate disk spindown if system sleep and display sleep
4514 // sliders are set to the same value (e.g. both set to 5 min),
4515 // and display is about to go dark. Check that spin down timer
4516 // is non-zero (zero = never spin down) and system sleep is
4517 // not set to never sleep.
4519 gRootDomain
->setQuickSpinDownTimeout();
4524 case kIOMessageDeviceHasPoweredOn
:
4526 // The display wrangler has powered on either because of user activity
4527 // or wake from sleep/doze.
4529 if ( 4 != displayPowerState
)
4532 gRootDomain
->wranglerAsleep
= false;
4533 gRootDomain
->adjustPowerState();
4534 gRootDomain
->cancelIdleSleepTimer();
4536 // Change the spindown value back to the user's selection from our
4537 // accelerated setting.
4538 gRootDomain
->restoreUserSpinDownTimeout();
4546 return kIOReturnUnsupported
;
4550 //******************************************************************************
4551 // displayWranglerPublished
4553 // Receives a notification when the IODisplayWrangler is published.
4554 // When it's published we install a power state change handler.
4555 //******************************************************************************
4557 bool IOPMrootDomain::displayWranglerPublished(
4560 IOService
* newService
)
4566 gRootDomain
->wrangler
= newService
;
4568 // we found the display wrangler, now install a handler
4569 if( !gRootDomain
->wrangler
->registerInterest( gIOGeneralInterest
,
4570 &displayWranglerNotification
, target
, 0) )
4579 //******************************************************************************
4582 // Notification on battery class IOPowerSource appearance
4583 //******************************************************************************
4585 bool IOPMrootDomain::batteryPublished(
4588 IOService
* resourceService
)
4590 // rdar://2936060&4435589
4591 // All laptops have dimmable LCD displays
4592 // All laptops have batteries
4593 // So if this machine has a battery, publish the fact that the backlight
4594 // supports dimming.
4595 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
4601 //******************************************************************************
4604 // Some condition that affects our wake/sleep/doze decision has changed.
4606 // If the sleep slider is in the off position, we cannot sleep or doze.
4607 // If the enclosure is open, we cannot sleep or doze.
4608 // If the system is still booting, we cannot sleep or doze.
4610 // In those circumstances, we prevent sleep and doze by holding power on with
4611 // changePowerStateToPriv(ON).
4613 // If the above conditions do not exist, and also the sleep timer has expired,
4614 // we allow sleep or doze to occur with either changePowerStateToPriv(SLEEP) or
4615 // changePowerStateToPriv(DOZE) depending on whether or not we already know the
4616 // platform cannot sleep.
4618 // In this case, sleep or doze will either occur immediately or at the next time
4619 // that no children are holding the system out of idle sleep via the
4620 // kIOPMPreventIdleSleep flag in their power state arrays.
4621 //******************************************************************************
4623 void IOPMrootDomain::adjustPowerState( void )
4625 DLOG("adjustPowerState "
4626 "PS %u, ASAP %d, SL %ld, AS %d, SB %d, SS %d, UD %d\n",
4627 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
,
4628 allowSleep
, systemBooting
, systemShutdown
, userDisabledAllSleep
);
4632 if ( (sleepSlider
== 0)
4636 || userDisabledAllSleep
4637 || (runStateFlags
& kRStateFlagDisableIdleSleep
) )
4639 changePowerStateToPriv(ON_STATE
);
4643 /* Convenient place to run any code at idle sleep time
4644 * IOPMrootDomain initiates an idle sleep here
4646 * Set last sleep cause accordingly.
4648 lastSleepReason
= kIOPMSleepReasonIdle
;
4649 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
4652 changePowerStateToPriv(SLEEP_STATE
);
4657 void IOPMrootDomain::pmStatsRecordEvent(
4659 AbsoluteTime timestamp
)
4661 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
4662 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
4666 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
4668 absolutetime_to_nanoseconds(timestamp
, &nsec
);
4670 switch (eventIndex
) {
4671 case kIOPMStatsHibernateImageWrite
:
4673 pmStats
.hibWrite
.start
= nsec
;
4675 pmStats
.hibWrite
.stop
= nsec
;
4678 delta
= pmStats
.hibWrite
.stop
- pmStats
.hibWrite
.start
;
4679 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
4682 case kIOPMStatsHibernateImageRead
:
4684 pmStats
.hibRead
.start
= nsec
;
4686 pmStats
.hibRead
.stop
= nsec
;
4689 delta
= pmStats
.hibRead
.stop
- pmStats
.hibRead
.start
;
4690 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
4697 * Appends a record of the application response to
4698 * IOPMrootDomain::pmStatsAppResponses
4700 void IOPMrootDomain::pmStatsRecordApplicationResponse(
4701 const OSSymbol
*response
,
4707 OSDictionary
*responseDescription
= NULL
;
4708 OSNumber
*delayNum
= NULL
;
4709 OSNumber
*pidNum
= NULL
;
4710 OSNumber
*msgNum
= NULL
;
4711 const OSSymbol
*appname
;
4712 const OSSymbol
*entryName
;
4713 OSObject
*entryType
;
4716 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
4720 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
4722 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
4723 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
4724 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
))
4726 OSNumber
* entryValue
;
4727 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
4728 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
4729 entryValue
->setValue(delay_ms
);
4734 responseDescription
= OSDictionary::withCapacity(5);
4735 if (responseDescription
)
4738 responseDescription
->setObject(_statsResponseTypeKey
, response
);
4741 if (messageType
!= 0) {
4742 msgNum
= OSNumber::withNumber(messageType
, 32);
4744 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
4749 if (name
&& (strlen(name
) > 0))
4751 appname
= OSSymbol::withCString(name
);
4753 responseDescription
->setObject(_statsNameKey
, appname
);
4758 if (app_pid
!= -1) {
4759 pidNum
= OSNumber::withNumber(app_pid
, 32);
4761 responseDescription
->setObject(_statsPIDKey
, pidNum
);
4766 delayNum
= OSNumber::withNumber(delay_ms
, 32);
4768 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
4769 delayNum
->release();
4772 if (pmStatsAppResponses
) {
4773 pmStatsAppResponses
->setObject(responseDescription
);
4776 responseDescription
->release();
4782 //******************************************************************************
4783 // TracePoint support
4785 //******************************************************************************
4787 #define kIOPMRegisterNVRAMTracePointHandlerKey \
4788 "IOPMRegisterNVRAMTracePointHandler"
4790 IOReturn
IOPMrootDomain::callPlatformFunction(
4791 const OSSymbol
* functionName
,
4792 bool waitForFunction
,
4793 void * param1
, void * param2
,
4794 void * param3
, void * param4
)
4796 if (pmTracer
&& functionName
&&
4797 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
4798 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
4800 uint32_t tracePointPhases
, tracePointPCI
;
4801 uint64_t statusCode
;
4803 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
4804 pmTracer
->tracePointTarget
= (void *) param2
;
4805 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
4806 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
4807 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
4808 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
4810 LOG("Sleep failure code 0x%08x 0x%08x\n",
4811 tracePointPCI
, tracePointPhases
);
4813 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
4814 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
4816 return kIOReturnSuccess
;
4819 return super::callPlatformFunction(
4820 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
4823 void IOPMrootDomain::tracePoint( uint8_t point
)
4825 pmTracer
->tracePoint(point
);
4828 //******************************************************************************
4829 // PMTraceWorker Class
4831 //******************************************************************************
4834 #define super OSObject
4835 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
4837 #define kPMBestGuessPCIDevicesCount 25
4838 #define kPMMaxRTCBitfieldSize 32
4840 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
4844 me
= OSTypeAlloc( PMTraceWorker
);
4845 if (!me
|| !me
->init())
4850 DLOG("PMTraceWorker %p\n", me
);
4852 // Note that we cannot instantiate the PCI device -> bit mappings here, since
4853 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
4854 // this dictionary lazily.
4856 me
->pciDeviceBitMappings
= NULL
;
4857 me
->pciMappingLock
= IOLockAlloc();
4858 me
->tracePhase
= kIOPMTracePointSystemUp
;
4859 me
->loginWindowPhase
= 0;
4860 me
->pciBusyBitMask
= 0;
4864 void PMTraceWorker::RTC_TRACE(void)
4866 if (tracePointHandler
&& tracePointTarget
)
4870 wordA
= tracePhase
; // destined for bits 24-31
4872 wordA
|= loginWindowPhase
; // destined for bits 16-23
4875 tracePointHandler( tracePointTarget
, pciBusyBitMask
, wordA
);
4876 DLOG("RTC_TRACE wrote 0x%08x 0x%08x\n", pciBusyBitMask
, wordA
);
4880 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
4882 const OSSymbol
* deviceName
;
4885 IOLockLock(pciMappingLock
);
4887 if (!pciDeviceBitMappings
)
4889 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
4890 if (!pciDeviceBitMappings
)
4894 // Check for bitmask overflow.
4895 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
4898 if ((deviceName
= pciDevice
->copyName()) &&
4899 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
4900 pciDeviceBitMappings
->setObject(deviceName
))
4902 index
= pciDeviceBitMappings
->getCount() - 1;
4903 DLOG("PMTrace PCI array: set object %s => %d\n",
4904 deviceName
->getCStringNoCopy(), index
);
4907 deviceName
->release();
4908 if (!addedToRegistry
&& (index
>= 0))
4909 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
4912 IOLockUnlock(pciMappingLock
);
4916 bool PMTraceWorker::serialize(OSSerialize
*s
) const
4919 if (pciDeviceBitMappings
)
4921 IOLockLock(pciMappingLock
);
4922 ok
= pciDeviceBitMappings
->serialize(s
);
4923 IOLockUnlock(pciMappingLock
);
4928 void PMTraceWorker::tracePoint(uint8_t phase
)
4932 DLOG("IOPMrootDomain: trace point 0x%02x\n", tracePhase
);
4936 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
4938 loginWindowPhase
= phase
;
4940 DLOG("IOPMrootDomain: loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
4944 void PMTraceWorker::tracePCIPowerChange(
4945 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
4948 uint32_t expectedFlag
;
4950 // Ignore PCI changes outside of system sleep/wake.
4951 if ((kIOPMTracePointSystemSleepDriversPhase
!= tracePhase
) &&
4952 (kIOPMTracePointSystemWakeDriversPhase
!= tracePhase
))
4955 // Only record the WillChange transition when going to sleep,
4956 // and the DidChange on the way up.
4957 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
4958 expectedFlag
= (kIOPMTracePointSystemSleepDriversPhase
== tracePhase
) ?
4959 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
4960 if (changeFlags
!= expectedFlag
)
4963 // Mark this device off in our bitfield
4964 if (bitNum
< kPMMaxRTCBitfieldSize
)
4966 bitMask
= (1 << bitNum
);
4968 if (kPowerChangeStart
== type
)
4970 pciBusyBitMask
|= bitMask
;
4971 DLOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
4972 service
->getName(), bitNum
, bitMask
, pciBusyBitMask
);
4976 pciBusyBitMask
&= ~bitMask
;
4977 DLOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
4978 service
->getName(), bitNum
, bitMask
, pciBusyBitMask
);
4986 //******************************************************************************
4987 // PMHaltWorker Class
4989 //******************************************************************************
4991 static unsigned int gPMHaltBusyCount
;
4992 static unsigned int gPMHaltIdleCount
;
4993 static int gPMHaltDepth
;
4994 static unsigned long gPMHaltEvent
;
4995 static IOLock
* gPMHaltLock
= 0;
4996 static OSArray
* gPMHaltArray
= 0;
4997 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
4999 PMHaltWorker
* PMHaltWorker::worker( void )
5005 me
= OSTypeAlloc( PMHaltWorker
);
5006 if (!me
|| !me
->init())
5009 me
->lock
= IOLockAlloc();
5013 DLOG("PMHaltWorker %p\n", me
);
5014 me
->retain(); // thread holds extra retain
5015 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
5020 thread_deallocate(thread
);
5025 if (me
) me
->release();
5029 void PMHaltWorker::free( void )
5031 DLOG("PMHaltWorker free %p\n", this);
5037 return OSObject::free();
5040 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
5042 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
5044 IOLockLock( gPMHaltLock
);
5046 me
->depth
= gPMHaltDepth
;
5047 IOLockUnlock( gPMHaltLock
);
5049 while (me
->depth
>= 0)
5051 PMHaltWorker::work( me
);
5053 IOLockLock( gPMHaltLock
);
5054 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
5056 // This is the last thread to finish work on this level,
5057 // inform everyone to start working on next lower level.
5059 me
->depth
= gPMHaltDepth
;
5060 gPMHaltIdleCount
= 0;
5061 thread_wakeup((event_t
) &gPMHaltIdleCount
);
5065 // One or more threads are still working on this level,
5066 // this thread must wait.
5067 me
->depth
= gPMHaltDepth
- 1;
5069 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
5070 } while (me
->depth
!= gPMHaltDepth
);
5072 IOLockUnlock( gPMHaltLock
);
5075 // No more work to do, terminate thread
5076 DLOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
5077 thread_wakeup( &gPMHaltDepth
);
5081 void PMHaltWorker::work( PMHaltWorker
* me
)
5083 IOService
* service
;
5085 AbsoluteTime startTime
;
5094 // Claim an unit of work from the shared pool
5095 IOLockLock( gPMHaltLock
);
5096 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
5099 service
= (IOService
*)inner
->getAnyObject();
5103 inner
->removeObject(service
);
5106 IOLockUnlock( gPMHaltLock
);
5108 break; // no more work at this depth
5110 clock_get_uptime(&startTime
);
5112 if (!service
->isInactive() &&
5113 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
5115 IOLockLock(me
->lock
);
5116 me
->startTime
= startTime
;
5117 me
->service
= service
;
5118 me
->timeout
= false;
5119 IOLockUnlock(me
->lock
);
5121 service
->systemWillShutdown( gPMHaltEvent
);
5123 // Wait for driver acknowledgement
5124 IOLockLock(me
->lock
);
5125 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
5127 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
5130 timeout
= me
->timeout
;
5131 IOLockUnlock(me
->lock
);
5134 deltaTime
= computeDeltaTimeMS(&startTime
);
5135 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
5136 (gIOKitDebug
& (kIOLogDebugPower
| kIOLogPMRootDomain
)))
5138 KLOG("%s driver %s (%p) took %u ms\n",
5139 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
5140 "PowerOff" : "Restart",
5141 service
->getName(), service
,
5142 (uint32_t) deltaTime
);
5150 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
5153 AbsoluteTime startTime
;
5154 AbsoluteTime endTime
;
5158 IOLockLock(me
->lock
);
5159 if (me
->service
&& !me
->timeout
)
5161 startTime
= me
->startTime
;
5163 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
5165 SUB_ABSOLUTETIME(&endTime
, &startTime
);
5166 absolutetime_to_nanoseconds(endTime
, &nano
);
5168 if (nano
> 3000000000ULL)
5171 LOG("%s still waiting on %s\n",
5172 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
5173 "PowerOff" : "Restart",
5174 me
->service
->getName());
5177 IOLockUnlock(me
->lock
);
5181 //******************************************************************************
5182 // acknowledgeSystemWillShutdown
5184 // Acknowledgement from drivers that they have prepared for shutdown/restart.
5185 //******************************************************************************
5187 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
5189 PMHaltWorker
* worker
;
5195 //DLOG("%s acknowledged\n", from->getName());
5196 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
5199 worker
= (PMHaltWorker
*) prop
;
5200 IOLockLock(worker
->lock
);
5201 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
5202 thread_wakeup((event_t
) worker
);
5203 IOLockUnlock(worker
->lock
);
5208 DLOG("%s acknowledged without worker property\n",
5214 //******************************************************************************
5215 // notifySystemShutdown
5217 // Notify all objects in PM tree that system will shutdown or restart
5218 //******************************************************************************
5221 notifySystemShutdown( IOService
* root
, unsigned long event
)
5223 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
5224 IORegistryIterator
* iter
;
5225 IORegistryEntry
* entry
;
5228 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
5229 AbsoluteTime deadline
;
5230 unsigned int totalNodes
= 0;
5232 unsigned int rootDepth
;
5233 unsigned int numWorkers
;
5239 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
5241 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
5243 // Iterate the entire PM tree starting from root
5245 rootDepth
= root
->getDepth( gIOPowerPlane
);
5246 if (!rootDepth
) goto done
;
5248 // debug - for repeated test runs
5249 while (PMHaltWorker::metaClass
->getInstanceCount())
5254 gPMHaltArray
= OSArray::withCapacity(40);
5255 if (!gPMHaltArray
) goto done
;
5258 gPMHaltArray
->flushCollection();
5262 gPMHaltLock
= IOLockAlloc();
5263 if (!gPMHaltLock
) goto done
;
5266 if (!gPMHaltClientAcknowledgeKey
)
5268 gPMHaltClientAcknowledgeKey
=
5269 OSSymbol::withCStringNoCopy("PMShutdown");
5270 if (!gPMHaltClientAcknowledgeKey
) goto done
;
5273 gPMHaltEvent
= event
;
5275 // Depth-first walk of PM plane
5277 iter
= IORegistryIterator::iterateOver(
5278 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
5282 while ((entry
= iter
->getNextObject()))
5284 node
= OSDynamicCast(IOService
, entry
);
5289 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
5292 depth
= node
->getDepth( gIOPowerPlane
);
5293 if (depth
<= rootDepth
)
5298 // adjust to zero based depth
5299 depth
-= (rootDepth
+ 1);
5301 // gPMHaltArray is an array of containers, each container
5302 // refers to nodes with the same depth.
5304 count
= gPMHaltArray
->getCount();
5305 while (depth
>= count
)
5307 // expand array and insert placeholders
5308 gPMHaltArray
->setObject(PLACEHOLDER
);
5311 count
= gPMHaltArray
->getCount();
5314 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
5315 if (inner
== PLACEHOLDER
)
5317 inner
= OSSet::withCapacity(40);
5320 gPMHaltArray
->replaceObject(depth
, inner
);
5325 // PM nodes that appear more than once in the tree will have
5326 // the same depth, OSSet will refuse to add the node twice.
5328 ok
= inner
->setObject(node
);
5331 DLOG("Skipped PM node %s\n", node
->getName());
5337 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
5340 if (inner
!= PLACEHOLDER
)
5341 count
= inner
->getCount();
5342 DLOG("Nodes at depth %u = %u\n", i
, count
);
5345 // strip placeholders (not all depths are populated)
5347 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
5349 if (inner
== PLACEHOLDER
)
5351 gPMHaltArray
->removeObject(i
);
5354 count
= inner
->getCount();
5355 if (count
> numWorkers
)
5357 totalNodes
+= count
;
5361 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
5364 gPMHaltBusyCount
= 0;
5365 gPMHaltIdleCount
= 0;
5366 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
5368 // Create multiple workers (and threads)
5370 if (numWorkers
> kPMHaltMaxWorkers
)
5371 numWorkers
= kPMHaltMaxWorkers
;
5373 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
5374 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
5376 for (unsigned int i
= 0; i
< numWorkers
; i
++)
5377 workers
[i
] = PMHaltWorker::worker();
5379 // Wait for workers to exhaust all available work
5381 IOLockLock(gPMHaltLock
);
5382 while (gPMHaltDepth
>= 0)
5384 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
5386 waitResult
= IOLockSleepDeadline(
5387 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
5388 if (THREAD_TIMED_OUT
== waitResult
)
5391 clock_get_uptime(&now
);
5393 IOLockUnlock(gPMHaltLock
);
5394 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
5397 PMHaltWorker::checkTimeout(workers
[i
], &now
);
5399 IOLockLock(gPMHaltLock
);
5402 IOLockUnlock(gPMHaltLock
);
5404 // Release all workers
5406 for (unsigned int i
= 0; i
< numWorkers
; i
++)
5409 workers
[i
]->release();
5410 // worker also retained by it's own thread
5414 DLOG("%s done\n", __FUNCTION__
);
5418 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5420 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
5421 IOPMDriverAssertionType whichAssertionBits
,
5422 IOPMDriverAssertionLevel assertionLevel
,
5423 IOService
*ownerService
,
5424 const char *ownerDescription
)
5427 IOPMDriverAssertionID newAssertion
;
5432 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
5434 if (kIOReturnSuccess
== ret
)
5435 return newAssertion
;
5440 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
5443 return kIOReturnInternalError
;
5445 return pmAssertions
->releaseAssertion(releaseAssertion
);
5448 IOReturn
IOPMrootDomain::setPMAssertionLevel(
5449 IOPMDriverAssertionID assertionID
,
5450 IOPMDriverAssertionLevel assertionLevel
)
5452 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
5455 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
5457 IOPMDriverAssertionType sysLevels
;
5459 if (!pmAssertions
|| whichAssertion
== 0)
5460 return kIOPMDriverAssertionLevelOff
;
5462 sysLevels
= pmAssertions
->getActivatedAssertions();
5464 // Check that every bit set in argument 'whichAssertion' is asserted
5465 // in the aggregate bits.
5466 if ((sysLevels
& whichAssertion
) == whichAssertion
)
5467 return kIOPMDriverAssertionLevelOn
;
5469 return kIOPMDriverAssertionLevelOff
;
5472 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
5475 return kIOReturnNotFound
;
5477 return pmAssertions
->setUserAssertionLevels(inLevels
);
5480 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
5484 pmAssertions
->publishProperties();
5486 return( IOService::serializeProperties(s
) );
5489 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5493 #define super OSObject
5494 OSDefineMetaClassAndFinalStructors(PMSettingObject
, OSObject
)
5496 void PMSettingObject::setPMSetting(const OSSymbol
*type
, OSObject
*obj
)
5498 (*func
)(target
, type
, obj
, refcon
);
5502 * Static constructor/initializer for PMSettingObject
5504 PMSettingObject
*PMSettingObject::pmSettingObject(
5505 IOPMrootDomain
*parent_arg
,
5506 IOPMSettingControllerCallback handler_arg
,
5507 OSObject
*target_arg
,
5508 uintptr_t refcon_arg
,
5509 uint32_t supportedPowerSources
,
5510 const OSSymbol
* settings
[])
5512 uint32_t objCount
= 0;
5513 PMSettingObject
*pmso
;
5515 if( !parent_arg
|| !handler_arg
|| !settings
) return NULL
;
5517 // count OSSymbol entries in NULL terminated settings array
5518 while( settings
[objCount
] ) {
5521 if(0 == objCount
) return NULL
;
5523 pmso
= new PMSettingObject
;
5524 if(!pmso
|| !pmso
->init()) return NULL
;
5526 pmso
->parent
= parent_arg
;
5527 pmso
->func
= handler_arg
;
5528 pmso
->target
= target_arg
;
5529 pmso
->refcon
= refcon_arg
;
5530 pmso
->releaseAtCount
= objCount
+ 1; // release when it has count+1 retains
5532 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*objCount
);
5533 if(pmso
->publishedFeatureID
) {
5534 for(unsigned int i
=0; i
<objCount
; i
++) {
5535 // Since there is now at least one listener to this setting, publish
5536 // PM root domain support for it.
5537 parent_arg
->publishFeature( settings
[i
]->getCStringNoCopy(),
5538 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
5545 void PMSettingObject::free(void)
5547 OSCollectionIterator
*settings_iter
;
5552 int objCount
= releaseAtCount
- 1;
5554 if(publishedFeatureID
) {
5555 for(i
=0; i
<objCount
; i
++) {
5556 if(0 != publishedFeatureID
[i
]) {
5557 parent
->removePublishedFeature( publishedFeatureID
[i
] );
5561 IOFree(publishedFeatureID
, sizeof(uint32_t) * objCount
);
5564 IORecursiveLockLock(parent
->settingsCtrlLock
);
5566 // Search each PM settings array in the kernel.
5567 settings_iter
= OSCollectionIterator::withCollection(parent
->settingsCallbacks
);
5570 while(( sym
= OSDynamicCast(OSSymbol
, settings_iter
->getNextObject()) ))
5572 arr
= (OSArray
*)parent
->settingsCallbacks
->getObject(sym
);
5573 arr_idx
= arr
->getNextIndexOfObject(this, 0);
5575 // 'this' was found in the array; remove it
5576 arr
->removeObject(arr_idx
);
5580 settings_iter
->release();
5583 IORecursiveLockUnlock(parent
->settingsCtrlLock
);
5588 void PMSettingObject::taggedRelease(const void *tag
, const int when
) const
5590 // We have n+1 retains - 1 per array that this PMSettingObject is a member
5591 // of, and 1 retain to ourself. When we get a release with n+1 retains
5592 // remaining, we go ahead and free ourselves, cleaning up array pointers
5595 super::taggedRelease(tag
, releaseAtCount
);
5599 // MARK: PMAssertionsTracker
5601 //*********************************************************************************
5602 //*********************************************************************************
5603 //*********************************************************************************
5604 // class PMAssertionsTracker Implementation
5606 #define kAssertUniqueIDStart 500
5608 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
5610 PMAssertionsTracker
*myself
;
5612 myself
= new PMAssertionsTracker
;
5616 myself
->owner
= rootDomain
;
5617 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
5618 myself
->assertionsArray
= OSArray::withCapacity(5);
5619 myself
->assertionsKernel
= 0;
5620 myself
->assertionsUser
= 0;
5621 myself
->assertionsCombined
= 0;
5622 myself
->assertionsArrayLock
= IOLockAlloc();
5623 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
5625 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
5633 * - Update assertionsKernel to reflect the state of all
5634 * assertions in the kernel.
5635 * - Update assertionsCombined to reflect both kernel & user space.
5637 void PMAssertionsTracker::tabulate(void)
5641 PMAssertStruct
*_a
= NULL
;
5644 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
5645 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
5649 assertionsKernel
= 0;
5650 assertionsCombined
= 0;
5652 if (!assertionsArray
)
5655 if ((count
= assertionsArray
->getCount()))
5657 for (i
=0; i
<count
; i
++)
5659 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
5662 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
5663 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
5664 assertionsKernel
|= _a
->assertionBits
;
5669 tabulateProducerCount
++;
5670 assertionsCombined
= assertionsKernel
| assertionsUser
;
5672 if ((assertionsKernel
!= oldKernel
) ||
5673 (assertionsCombined
!= oldCombined
))
5675 owner
->messageClients(kIOPMMessageDriverAssertionsChanged
);
5679 void PMAssertionsTracker::publishProperties( void )
5681 OSArray
*assertionsSummary
= NULL
;
5683 if (tabulateConsumerCount
!= tabulateProducerCount
)
5685 IOLockLock(assertionsArrayLock
);
5687 tabulateConsumerCount
= tabulateProducerCount
;
5689 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
5691 assertionsSummary
= copyAssertionsArray();
5692 if (assertionsSummary
)
5694 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
5695 assertionsSummary
->release();
5699 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
5702 /* Publish the IOPMrootDomain property "DriverPMAssertions"
5704 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
5706 IOLockUnlock(assertionsArrayLock
);
5710 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
5712 PMAssertStruct
*_a
= NULL
;
5719 && (count
= assertionsArray
->getCount()))
5721 for (i
=0; i
<count
; i
++)
5723 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
5726 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
5727 if (_a
&& (_id
== _a
->id
)) {
5744 /* PMAssertionsTracker::handleCreateAssertion
5745 * Perform assertion work on the PM workloop. Do not call directly.
5747 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
5753 IOLockLock(assertionsArrayLock
);
5754 assertionsArray
->setObject(newAssertion
);
5755 IOLockUnlock(assertionsArrayLock
);
5756 newAssertion
->release();
5760 return kIOReturnSuccess
;
5763 /* PMAssertionsTracker::createAssertion
5764 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
5767 IOReturn
PMAssertionsTracker::createAssertion(
5768 IOPMDriverAssertionType which
,
5769 IOPMDriverAssertionLevel level
,
5770 IOService
*serviceID
,
5771 const char *whoItIs
,
5772 IOPMDriverAssertionID
*outID
)
5774 OSData
*dataStore
= NULL
;
5775 PMAssertStruct track
;
5777 // Warning: trillions and trillions of created assertions may overflow the unique ID.
5779 track
.id
= issuingUniqueID
++; // FIXME: need OSIncrementAtomic64() for ppc
5781 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
5783 track
.level
= level
;
5784 track
.assertionBits
= which
;
5785 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
) : 0;
5786 track
.ownerService
= serviceID
;
5787 track
.modifiedTime
= 0;
5788 pmEventTimeStamp(&track
.createdTime
);
5790 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
5793 if (track
.ownerString
)
5794 track
.ownerString
->release();
5795 return kIOReturnNoMemory
;
5800 if (owner
&& owner
->pmPowerStateQueue
) {
5801 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
5804 return kIOReturnSuccess
;
5807 /* PMAssertionsTracker::handleReleaseAssertion
5808 * Runs in PM workloop. Do not call directly.
5810 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
5811 IOPMDriverAssertionID _id
)
5816 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
5819 return kIOReturnNotFound
;
5821 IOLockLock(assertionsArrayLock
);
5822 if (assertStruct
->ownerString
)
5823 assertStruct
->ownerString
->release();
5825 assertionsArray
->removeObject(index
);
5826 IOLockUnlock(assertionsArrayLock
);
5829 return kIOReturnSuccess
;
5832 /* PMAssertionsTracker::releaseAssertion
5833 * Releases an assertion and affects system behavior if appropiate.
5834 * Actual work happens on PM workloop.
5836 IOReturn
PMAssertionsTracker::releaseAssertion(
5837 IOPMDriverAssertionID _id
)
5839 if (owner
&& owner
->pmPowerStateQueue
) {
5840 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
5842 return kIOReturnSuccess
;
5845 /* PMAssertionsTracker::handleSetAssertionLevel
5846 * Runs in PM workloop. Do not call directly.
5848 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
5849 IOPMDriverAssertionID _id
,
5850 IOPMDriverAssertionLevel _level
)
5852 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
5856 if (!assertStruct
) {
5857 return kIOReturnNotFound
;
5860 IOLockLock(assertionsArrayLock
);
5861 pmEventTimeStamp(&assertStruct
->modifiedTime
);
5862 assertStruct
->level
= _level
;
5863 IOLockUnlock(assertionsArrayLock
);
5866 return kIOReturnSuccess
;
5869 /* PMAssertionsTracker::setAssertionLevel
5871 IOReturn
PMAssertionsTracker::setAssertionLevel(
5872 IOPMDriverAssertionID _id
,
5873 IOPMDriverAssertionLevel _level
)
5875 if (owner
&& owner
->pmPowerStateQueue
) {
5876 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
5877 (void *)_level
, _id
);
5880 return kIOReturnSuccess
;
5883 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
5885 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
5889 if (new_user_levels
!= assertionsUser
)
5891 assertionsUser
= new_user_levels
;
5892 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
5896 return kIOReturnSuccess
;
5899 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
5900 IOPMDriverAssertionType new_user_levels
)
5902 if (gIOPMWorkLoop
) {
5903 gIOPMWorkLoop
->runAction(
5904 OSMemberFunctionCast(
5907 &PMAssertionsTracker::handleSetUserAssertionLevels
),
5909 (void *) &new_user_levels
, 0, 0, 0);
5912 return kIOReturnSuccess
;
5916 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
5920 OSArray
*outArray
= NULL
;
5922 if (!assertionsArray
||
5923 (0 == (count
= assertionsArray
->getCount())) ||
5924 (NULL
== (outArray
= OSArray::withCapacity(count
))))
5929 for (i
=0; i
<count
; i
++)
5931 PMAssertStruct
*_a
= NULL
;
5933 OSDictionary
*details
= NULL
;
5935 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
5936 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
5938 OSNumber
*_n
= NULL
;
5940 details
= OSDictionary::withCapacity(7);
5944 outArray
->setObject(details
);
5947 _n
= OSNumber::withNumber(_a
->id
, 64);
5949 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
5952 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
5954 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
5957 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
5959 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
5962 _n
= OSNumber::withNumber((uintptr_t)_a
->ownerService
, 64);
5964 details
->setObject(kIOPMDriverAssertionOwnerServiceKey
, _n
);
5967 _n
= OSNumber::withNumber(_a
->level
, 64);
5969 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
5972 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
5974 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
5978 if (_a
->ownerString
) {
5979 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
5988 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
5990 return assertionsCombined
;
5993 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
5994 IOPMDriverAssertionType type
)
5996 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
5998 return kIOPMDriverAssertionLevelOn
;
6000 return kIOPMDriverAssertionLevelOff
;
6004 //*********************************************************************************
6005 //*********************************************************************************
6006 //*********************************************************************************
6008 static void pmEventTimeStamp(uint64_t *recordTS
)
6016 // We assume tsec fits into 32 bits; 32 bits holds enough
6017 // seconds for 136 years since the epoch in 1970.
6018 clock_get_calendar_microtime(&tsec
, &tusec
);
6021 // Pack the sec & microsec calendar time into a uint64_t, for fun.
6023 *recordTS
|= (uint32_t)tusec
;
6024 *recordTS
|= ((uint64_t)tsec
<< 32);
6029 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6032 #define super IOService
6034 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
6036 // This array exactly parallels the state array for the root domain.
6037 // Power state changes initiated by a device can be vetoed by a client of the device, and
6038 // power state changes initiated by the parent of a device cannot be vetoed by a client of the device,
6039 // so when the root domain wants a power state change that cannot be vetoed (e.g. demand sleep), it asks
6040 // its parent to make the change. That is the reason for this complexity.
6042 static IOPMPowerState patriarchPowerStates
[NUM_POWER_STATES
] =
6044 {1,0,0,0,0,0,0,0,0,0,0,0}, // off (not used)
6045 {1,0,RESTART_POWER
,0,0,0,0,0,0,0,0,0}, // reset (not used)
6046 {1,0,SLEEP_POWER
,0,0,0,0,0,0,0,0,0}, // sleep
6047 {1,0,DOZE_POWER
,0,0,0,0,0,0,0,0,0}, // doze
6048 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0}, // running
6051 bool IORootParent::start( IOService
* nub
)
6053 mostRecentChange
= ON_STATE
;
6055 attachToParent( getRegistryRoot(), gIOPowerPlane
);
6057 registerPowerDriver(this, patriarchPowerStates
, NUM_POWER_STATES
);
6059 powerOverrideOnPriv();
6063 void IORootParent::shutDownSystem( void )
6067 void IORootParent::restartSystem( void )
6071 void IORootParent::sleepSystem( void )
6073 mostRecentChange
= SLEEP_STATE
;
6074 changePowerStateToPriv(SLEEP_STATE
);
6077 void IORootParent::dozeSystem( void )
6079 mostRecentChange
= DOZE_STATE
;
6080 changePowerStateToPriv(DOZE_STATE
);
6083 // Called in demand sleep when sleep discovered to be impossible after actually attaining that state.
6084 // This brings the parent to doze, which allows the root to step up from sleep to doze.
6086 // In idle sleep, do nothing because the parent is still on and the root can freely change state.
6088 void IORootParent::sleepToDoze( void )
6090 if ( mostRecentChange
== SLEEP_STATE
) {
6091 changePowerStateToPriv(DOZE_STATE
);
6095 void IORootParent::wakeSystem( void )
6097 mostRecentChange
= ON_STATE
;
6098 changePowerStateToPriv(ON_STATE
);