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/OSAtomic.h>
31 #include <libkern/OSDebug.h>
32 #include <IOKit/IOWorkLoop.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOPlatformExpert.h>
35 #include <IOKit/IOKitDebug.h>
36 #include <IOKit/IOTimeStamp.h>
37 #include <IOKit/pwr_mgt/IOPMlog.h>
38 #include <IOKit/pwr_mgt/RootDomain.h>
39 #include <IOKit/pwr_mgt/IOPMPrivate.h>
40 #include <IOKit/IODeviceTreeSupport.h>
41 #include <IOKit/IOMessage.h>
42 #include <IOKit/IOReturn.h>
43 #include "RootDomainUserClient.h"
44 #include "IOKit/pwr_mgt/IOPowerConnection.h"
45 #include "IOPMPowerStateQueue.h"
46 #include <IOKit/IOCatalogue.h>
48 #include <IOKit/IOHibernatePrivate.h>
50 #include <console/video_console.h>
51 #include <sys/syslog.h>
52 #include <sys/sysctl.h>
54 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
55 #include "IOServicePMPrivate.h"
58 #include <mach/shared_region.h>
61 #if defined(__i386__) || defined(__x86_64__)
63 #include "IOPMrootDomainInternal.h"
67 #define kIOPMrootDomainClass "IOPMrootDomain"
68 #define LOG_PREFIX "PMRD: "
71 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
74 do { kprintf(LOG_PREFIX x); } while (false)
76 #define DLOG(x...) do { \
77 if (kIOLogPMRootDomain & gIOKitDebug) \
78 kprintf(LOG_PREFIX x); } while (false)
82 #define DARK_WAKE_DEBUG 1
83 #define SUSPEND_PM_NOTIFICATIONS_DEBUG 1
85 #define CHECK_THREAD_CONTEXT
86 #ifdef CHECK_THREAD_CONTEXT
87 static IOWorkLoop
* gIOPMWorkLoop
= 0;
88 #define ASSERT_GATED() \
90 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
91 panic("RootDomain: not inside PM gate"); \
95 #define ASSERT_GATED()
96 #endif /* CHECK_THREAD_CONTEXT */
99 (((_pendingCapability & (c)) == 0) && \
100 ((_currentCapability & (c)) != 0))
102 #define CAP_GAIN(c) \
103 (((_currentCapability & (c)) == 0) && \
104 ((_pendingCapability & (c)) != 0))
106 #define CAP_CHANGE(c) \
107 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
109 #define CAP_CURRENT(c) \
110 ((_currentCapability & (c)) != 0)
112 #define CAP_HIGHEST(c) \
113 ((_highestCapability & (c)) != 0)
115 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 0
117 // Event types for IOPMPowerStateQueue::submitPowerEvent()
119 kPowerEventFeatureChanged
= 1, // 1
120 kPowerEventReceivedPowerNotification
, // 2
121 kPowerEventSystemBootCompleted
, // 3
122 kPowerEventSystemShutdown
, // 4
123 kPowerEventUserDisabledSleep
, // 5
124 kPowerEventRegisterSystemCapabilityClient
, // 6
125 kPowerEventRegisterKernelCapabilityClient
, // 7
126 kPowerEventPolicyStimulus
, // 8
127 kPowerEventAssertionCreate
, // 9
128 kPowerEventAssertionRelease
, // 10
129 kPowerEventAssertionSetLevel
, // 11
130 kPowerEventQueueSleepWakeUUID
, // 12
131 kPowerEventPublishSleepWakeUUID
, // 13
132 kPowerEventSuspendClient
// 14
135 // For evaluatePolicy()
136 // List of stimuli that affects the root domain policy.
138 kStimulusDisplayWranglerSleep
, // 0
139 kStimulusDisplayWranglerWake
, // 1
140 kStimulusAggressivenessChanged
, // 2
141 kStimulusDemandSystemSleep
, // 3
142 kStimulusAllowSystemSleepChanged
, // 4
143 kStimulusDarkWakeActivityTickle
, // 5
144 kStimulusDarkWakeEntry
, // 6
145 kStimulusDarkWakeReentry
, // 7
146 kStimulusDarkWakeEvaluate
, // 8
147 kStimulusNoIdleSleepPreventers
// 9
151 IOReturn
OSKextSystemSleepOrWake( UInt32
);
154 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
155 static void notifySystemShutdown( IOService
* root
, unsigned long event
);
156 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
157 static void pmEventTimeStamp(uint64_t *recordTS
);
159 // "IOPMSetSleepSupported" callPlatformFunction name
160 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
161 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
163 #define kIOSleepSupportedKey "IOSleepSupported"
164 #define kIOPMSystemCapabilitiesKey "System Capabilities"
166 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
167 | kIOPMSupportedOnBatt \
168 | kIOPMSupportedOnUPS)
172 // not idle around autowake time, secs
173 kAutoWakePreWindow
= 45,
174 kAutoWakePostWindow
= 15
177 #define kLocalEvalClamshellCommand (1 << 15)
178 #define kIdleSleepRetryInterval (3 * 60)
188 #define ON_POWER kIOPMPowerOn
189 #define RESTART_POWER kIOPMRestart
190 #define SLEEP_POWER kIOPMAuxPowerOn
192 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
194 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
195 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
196 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
197 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
200 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
201 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
202 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
203 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
204 #define kIOPMRootDomainWakeTypeUser "User"
205 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
206 #define kIOPMRootDomainWakeTypeNetwork "Network"
207 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
209 // Special interest that entitles the interested client from receiving
210 // all system messages. Only used by powerd.
212 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
214 #define kPMSuspendedNotificationClients "PMSuspendedNotificationClients"
219 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
220 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
222 #define kAggressivesMinValue 1
225 kAggressivesStateBusy
= 0x01,
226 kAggressivesStateQuickSpindown
= 0x02
229 struct AggressivesRecord
{
235 struct AggressivesRequest
{
241 AggressivesRecord record
;
246 kAggressivesRequestTypeService
= 1,
247 kAggressivesRequestTypeRecord
251 kAggressivesOptionSynchronous
= 0x00000001,
252 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
253 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
254 kAggressivesOptionQuickSpindownMask
= 0x00000300
258 kAggressivesRecordFlagModified
= 0x00000001,
259 kAggressivesRecordFlagMinValue
= 0x00000002
264 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
265 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
266 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
267 kDarkWakeFlagHIDTickleMask
= 0x03,
268 kDarkWakeFlagIgnoreDiskIOInDark
= 0x04, // ignore disk idle in DW
269 kDarkWakeFlagIgnoreDiskIOAlways
= 0x08, // always ignore disk idle
270 kDarkWakeFlagIgnoreDiskIOMask
= 0x0C,
271 kDarkWakeFlagAlarmIsDark
= 0x0100
274 static IOPMrootDomain
* gRootDomain
;
275 static IONotifier
* gSysPowerDownNotifier
= 0;
276 static UInt32 gSleepOrShutdownPending
= 0;
277 static UInt32 gWillShutdown
= 0;
278 static UInt32 gPagingOff
= 0;
279 static UInt32 gSleepWakeUUIDIsSet
= false;
280 static uint32_t gAggressivesState
= 0;
281 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
| kDarkWakeFlagIgnoreDiskIOAlways
;
282 static PMStatsStruct gPMStats
;
285 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= 0;
286 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= 0;
287 static void * gSleepPolicyTarget
;
290 struct timeval gIOLastSleepTime
;
291 struct timeval gIOLastWakeTime
;
293 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
294 #define kCPUUnknownIndex 9999999
301 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
302 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
303 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
305 #define kBadPMFeatureID 0
309 * Opaque handle passed to clients of registerPMSettingController()
311 class PMSettingHandle
: public OSObject
313 OSDeclareFinalStructors( PMSettingHandle
)
314 friend class PMSettingObject
;
317 PMSettingObject
*pmso
;
323 * Internal object to track each PM setting controller
325 class PMSettingObject
: public OSObject
327 OSDeclareFinalStructors( PMSettingObject
)
328 friend class IOPMrootDomain
;
331 queue_head_t calloutQueue
;
333 IOPMrootDomain
*parent
;
334 PMSettingHandle
*pmsh
;
335 IOPMSettingControllerCallback func
;
338 uint32_t *publishedFeatureID
;
339 uint32_t settingCount
;
345 static PMSettingObject
*pmSettingObject(
346 IOPMrootDomain
*parent_arg
,
347 IOPMSettingControllerCallback handler_arg
,
348 OSObject
*target_arg
,
349 uintptr_t refcon_arg
,
350 uint32_t supportedPowerSources
,
351 const OSSymbol
*settings
[],
352 OSObject
**handle_obj
);
354 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
355 void clientHandleFreed(void);
358 struct PMSettingCallEntry
{
363 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
364 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
365 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
366 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
368 //*********************************************************************************
369 //*********************************************************************************
370 //*********************************************************************************
372 /* @class IOPMTimeline
373 * @astract Tracks & records PM activity.
374 * @discussion Intended for use only as a helper-class to IOPMrootDomain.
375 * Do not subclass or directly invoke iOPMTimeline
377 class IOPMTimeline
: public OSObject
379 OSDeclareDefaultStructors( IOPMTimeline
);
382 static IOPMTimeline
* timeline(IOPMrootDomain
*root_domain
);
384 bool setProperties(OSDictionary
*d
);
385 OSDictionary
*copyInfoDictionary(void);
387 IOReturn
recordSystemPowerEvent( PMEventDetails
*details
);
389 IOReturn
recordDetailedPowerEvent( PMEventDetails
*details
);
391 IOMemoryDescriptor
*getPMTraceMemoryDescriptor();
393 uint32_t getNumEventsLoggedThisPeriod();
394 void setNumEventsLoggedThisPeriod(uint32_t newCount
);
395 bool isSleepCycleInProgress();
396 void setSleepCycleInProgressFlag(bool flag
);
401 void setEventsTrackedCount(uint32_t newTracked
);
402 void setEventsRecordingLevel(uint32_t eventsTrackedBits
);
403 static uint32_t _atomicIndexIncrement(uint32_t *index
, uint32_t limit
);
406 kPMTimelineRecordTardyDrivers
= 1 << 0,
407 kPMTmielineRecordSystemEvents
= 1 << 1,
408 kPMTimelineRecordAllDrivers
= 1 << 2,
409 kPMTimelineRecordOff
= 0,
410 kPMTimelineRecordDefault
= 3,
411 kPMTimelineRecordDebug
= 7
414 // eventsRecordingLevel is a bitfield defining which PM driver events will get logged
415 // into the PM buffer.
416 uint32_t eventsRecordingLevel
;
418 // pmTraceMemoryDescriptor represents the memory block that IOPMTimeLine records PM trace points into.
419 IOBufferMemoryDescriptor
*pmTraceMemoryDescriptor
;
421 // Pointer to starting address in pmTraceMemoryDescriptor
422 IOPMSystemEventRecord
*traceBuffer
;
423 IOPMTraceBufferHeader
*hdr
;
425 uint16_t systemState
;
428 IOPMrootDomain
*owner
;
430 uint32_t numEventsLoggedThisPeriod
;
431 bool sleepCycleInProgress
;
434 OSDefineMetaClassAndStructors( IOPMTimeline
, OSObject
)
438 * Internal helper object for logging trace points to RTC
439 * IOPMrootDomain and only IOPMrootDomain should instantiate
440 * exactly one of these.
443 typedef void (*IOPMTracePointHandler
)(
444 void * target
, uint32_t code
, uint32_t data
);
446 class PMTraceWorker
: public OSObject
448 OSDeclareDefaultStructors(PMTraceWorker
)
450 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
452 static PMTraceWorker
*tracer( IOPMrootDomain
* );
453 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
454 void tracePoint(uint8_t phase
);
455 void tracePoint(uint8_t phase
, uint8_t data8
);
456 void traceDetail(uint32_t detail
);
457 void traceLoginWindowPhase(uint8_t phase
);
458 int recordTopLevelPCIDevice(IOService
*);
459 void RTC_TRACE(void);
460 virtual bool serialize(OSSerialize
*s
) const;
462 IOPMTracePointHandler tracePointHandler
;
463 void * tracePointTarget
;
465 IOPMrootDomain
*owner
;
466 IOLock
*pciMappingLock
;
467 OSArray
*pciDeviceBitMappings
;
469 uint8_t addedToRegistry
;
471 uint8_t loginWindowPhase
;
473 uint32_t traceData32
;
477 * PMAssertionsTracker
478 * Tracks kernel and user space PM assertions
480 class PMAssertionsTracker
: public OSObject
482 OSDeclareFinalStructors(PMAssertionsTracker
)
484 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
486 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
487 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
488 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
489 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
491 OSArray
*copyAssertionsArray(void);
492 IOPMDriverAssertionType
getActivatedAssertions(void);
493 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
495 IOReturn
handleCreateAssertion(OSData
*);
496 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
497 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
498 IOReturn
handleSetUserAssertionLevels(void * arg0
);
499 void publishProperties(void);
503 IOPMDriverAssertionID id
;
504 IOPMDriverAssertionType assertionBits
;
505 uint64_t createdTime
;
506 uint64_t modifiedTime
;
507 const OSSymbol
*ownerString
;
508 IOService
*ownerService
;
509 IOPMDriverAssertionLevel level
;
512 uint32_t tabulateProducerCount
;
513 uint32_t tabulateConsumerCount
;
515 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
518 IOPMrootDomain
*owner
;
519 OSArray
*assertionsArray
;
520 IOLock
*assertionsArrayLock
;
521 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
522 IOPMDriverAssertionType assertionsKernel
;
523 IOPMDriverAssertionType assertionsUser
;
524 IOPMDriverAssertionType assertionsCombined
;
527 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
531 * Internal helper object for Shutdown/Restart notifications.
533 #define kPMHaltMaxWorkers 8
534 #define kPMHaltTimeoutMS 100
536 class PMHaltWorker
: public OSObject
538 OSDeclareFinalStructors( PMHaltWorker
)
541 IOService
* service
; // service being worked on
542 AbsoluteTime startTime
; // time when work started
543 int depth
; // work on nubs at this PM-tree depth
544 int visits
; // number of nodes visited (debug)
546 bool timeout
; // service took too long
548 static PMHaltWorker
* worker( void );
549 static void main( void * arg
, wait_result_t waitResult
);
550 static void work( PMHaltWorker
* me
);
551 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
552 virtual void free( void );
555 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
558 #define super IOService
559 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
561 static void IOPMRootDomainWillShutdown(void)
563 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
565 OSKext::willShutdown();
566 for (int i
= 0; i
< 100; i
++)
568 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
576 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
578 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
581 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
583 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
586 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
588 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
591 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
593 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
596 IOReturn
rootDomainRestart ( void )
598 return gRootDomain
->restartSystem();
601 IOReturn
rootDomainShutdown ( void )
603 return gRootDomain
->shutdownSystem();
606 void IOSystemShutdownNotification(void)
608 IOPMRootDomainWillShutdown();
609 if (OSCompareAndSwap(0, 1, &gPagingOff
))
612 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
617 int sync_internal(void);
621 A device is always in the highest power state which satisfies its driver,
622 its policy-maker, and any power children it has, but within the constraint
623 of the power state provided by its parent. The driver expresses its desire by
624 calling changePowerStateTo(), the policy-maker expresses its desire by calling
625 changePowerStateToPriv(), and the children express their desires by calling
626 requestPowerDomainState().
628 The Root Power Domain owns the policy for idle and demand sleep for the system.
629 It is a power-managed IOService just like the others in the system.
630 It implements several power states which map to what we see as Sleep and On.
632 The sleep policy is as follows:
633 1. Sleep is prevented if the case is open so that nobody will think the machine
634 is off and plug/unplug cards.
635 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
636 3. System cannot Sleep if some object in the tree is in a power state marked
637 kIOPMPreventSystemSleep.
639 These three conditions are enforced using the "driver clamp" by calling
640 changePowerStateTo(). For example, if the case is opened,
641 changePowerStateTo(ON_STATE) is called to hold the system on regardless
642 of the desires of the children of the root or the state of the other clamp.
644 Demand Sleep is initiated by pressing the front panel power button, closing
645 the clamshell, or selecting the menu item. In this case the root's parent
646 actually initiates the power state change so that the root domain has no
647 choice and does not give applications the opportunity to veto the change.
649 Idle Sleep occurs if no objects in the tree are in a state marked
650 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
651 the root on, so it sets the "policy-maker clamp" by calling
652 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
653 This timer is set for the difference between the sleep timeout slider and the
654 display dim timeout slider. When the timer expires, it releases its clamp and
655 now nothing is holding it awake, so it falls asleep.
657 Demand sleep is prevented when the system is booting. When preferences are
658 transmitted by the loginwindow at the end of boot, a flag is cleared,
659 and this allows subsequent Demand Sleep.
662 //******************************************************************************
664 IOPMrootDomain
* IOPMrootDomain::construct( void )
666 IOPMrootDomain
*root
;
668 root
= new IOPMrootDomain
;
675 //******************************************************************************
677 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
679 IOService
* rootDomain
= (IOService
*) p0
;
680 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
681 uint32_t powerState
= rootDomain
->getPowerState();
683 DLOG("disk_sync_callout ps=%u\n", powerState
);
685 if (ON_STATE
== powerState
)
688 IOHibernateSystemSleep();
695 IOHibernateSystemPostWake();
699 rootDomain
->allowPowerChange(notifyRef
);
700 DLOG("disk_sync_callout finish\n");
703 //******************************************************************************
705 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
707 AbsoluteTime endTime
;
710 clock_get_uptime(&endTime
);
711 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
713 SUB_ABSOLUTETIME(&endTime
, startTime
);
714 absolutetime_to_nanoseconds(endTime
, &nano
);
717 return (UInt32
)(nano
/ 1000000ULL);
720 //******************************************************************************
723 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
725 struct timeval
*swt
= (struct timeval
*)arg1
;
726 struct proc
*p
= req
->p
;
729 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
730 } else if(proc_is64bit(p
)) {
731 struct user64_timeval t
;
732 t
.tv_sec
= swt
->tv_sec
;
733 t
.tv_usec
= swt
->tv_usec
;
734 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
736 struct user32_timeval t
;
737 t
.tv_sec
= swt
->tv_sec
;
738 t
.tv_usec
= swt
->tv_usec
;
739 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
743 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
744 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
745 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
747 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
748 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
749 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
754 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
756 int new_value
, changed
;
757 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
759 if (!gWillShutdown
&& (new_value
== 1)) {
760 IOPMRootDomainWillShutdown();
767 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
768 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
769 0, 0, sysctl_willshutdown
, "I", "");
774 sysctl_progressmeterenable
775 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
778 int new_value
, changed
;
780 error
= sysctl_io_number(req
, vc_progress_meter_enable
, sizeof(int), &new_value
, &changed
);
783 vc_enable_progressmeter(new_value
);
790 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
793 int new_value
, changed
;
795 error
= sysctl_io_number(req
, vc_progress_meter_value
, sizeof(int), &new_value
, &changed
);
798 vc_set_progressmeter(new_value
);
803 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
804 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
805 0, 0, sysctl_progressmeterenable
, "I", "");
807 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
808 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
809 0, 0, sysctl_progressmeter
, "I", "");
813 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
815 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
816 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
817 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
818 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
819 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
820 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
822 //******************************************************************************
825 //******************************************************************************
827 #define kRootDomainSettingsCount 17
829 bool IOPMrootDomain::start( IOService
* nub
)
831 OSIterator
*psIterator
;
832 OSDictionary
*tmpDict
;
833 IORootParent
* patriarch
;
838 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
839 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
840 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
841 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
842 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
843 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
845 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
846 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
847 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
849 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
850 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
852 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
854 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
855 gIOPMSettingAutoWakeSecondsKey
,
856 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
857 gIOPMSettingAutoWakeCalendarKey
,
858 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
859 gIOPMSettingDebugWakeRelativeKey
,
860 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
861 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
862 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
863 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
864 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
865 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
866 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
867 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
868 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
869 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
870 gIOPMSettingSilentRunningKey
873 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
875 queue_init(&aggressivesQueue
);
876 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
877 aggressivesData
= OSData::withCapacity(
878 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
880 featuresDictLock
= IOLockAlloc();
881 settingsCtrlLock
= IOLockAlloc();
882 setPMRootDomain(this);
884 extraSleepTimer
= thread_call_allocate(
885 idleSleepTimerExpired
,
886 (thread_call_param_t
) this);
888 diskSyncCalloutEntry
= thread_call_allocate(
890 (thread_call_param_t
) this);
892 setProperty(kIOSleepSupportedKey
, true);
894 bzero(&gPMStats
, sizeof(gPMStats
));
896 pmTracer
= PMTraceWorker::tracer(this);
898 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
900 userDisabledAllSleep
= false;
901 systemBooting
= true;
903 idleSleepTimerPending
= false;
905 clamshellClosed
= false;
906 clamshellExists
= false;
907 clamshellDisabled
= true;
908 acAdaptorConnected
= true;
910 // Set the default system capabilities at boot.
911 _currentCapability
= kIOPMSystemCapabilityCPU
|
912 kIOPMSystemCapabilityGraphics
|
913 kIOPMSystemCapabilityAudio
|
914 kIOPMSystemCapabilityNetwork
;
916 _pendingCapability
= _currentCapability
;
917 _desiredCapability
= _currentCapability
;
918 _highestCapability
= _currentCapability
;
919 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
921 queuedSleepWakeUUIDString
= NULL
;
922 pmStatsAppResponses
= OSArray::withCapacity(5);
923 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
924 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
925 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
926 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
927 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
929 idxPMCPUClamshell
= kCPUUnknownIndex
;
930 idxPMCPULimitedPower
= kCPUUnknownIndex
;
932 tmpDict
= OSDictionary::withCapacity(1);
933 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
936 settingsCallbacks
= OSDictionary::withCapacity(1);
938 // Create a list of the valid PM settings that we'll relay to
939 // interested clients in setProperties() => setPMSetting()
940 allowedPMSettings
= OSArray::withObjects(
941 (const OSObject
**)settingsArr
,
942 kRootDomainSettingsCount
,
945 // List of PM settings that should not automatically publish itself
946 // as a feature when registered by a listener.
947 noPublishPMSettings
= OSArray::withObjects(
948 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
950 fPMSettingsDict
= OSDictionary::withCapacity(5);
951 preventIdleSleepList
= OSSet::withCapacity(8);
952 preventSystemSleepList
= OSSet::withCapacity(2);
954 PMinit(); // creates gIOPMWorkLoop
956 // Create IOPMPowerStateQueue used to queue external power
957 // events, and to handle those events on the PM work loop.
958 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
959 this, OSMemberFunctionCast(IOEventSource::Action
, this,
960 &IOPMrootDomain::dispatchPowerEvent
));
961 getPMworkloop()->addEventSource(pmPowerStateQueue
);
962 #ifdef CHECK_THREAD_CONTEXT
963 gIOPMWorkLoop
= getPMworkloop();
966 // create our power parent
967 patriarch
= new IORootParent
;
969 patriarch
->attach(this);
970 patriarch
->start(this);
971 patriarch
->addPowerChild(this);
973 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
974 changePowerStateToPriv(ON_STATE
);
976 if (gIOKitDebug
& (kIOLogDriverPower1
| kIOLogDriverPower2
))
978 // Setup our PM logging & recording code
979 timeline
= IOPMTimeline::timeline(this);
981 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
985 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
991 // install power change handler
992 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
995 // Register for a notification when IODisplayWrangler is published
996 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
998 _displayWranglerNotifier
= addMatchingNotification(
999 gIOPublishNotification
, tmpDict
,
1000 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1006 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1007 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1008 ucClassName
->release();
1010 // IOBacklightDisplay can take a long time to load at boot, or it may
1011 // not load at all if you're booting with clamshell closed. We publish
1012 // 'DisplayDims' here redundantly to get it published early and at all.
1013 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
1014 if( psIterator
&& psIterator
->getNextObject() )
1016 // There's at least one battery on the system, so we publish
1017 // 'DisplayDims' support for the LCD.
1018 publishFeature("DisplayDims");
1021 psIterator
->release();
1025 pmSuspendedCapacity
= pmSuspendedSize
= 0;
1026 pmSuspendedPIDS
= NULL
;
1029 sysctl_register_oid(&sysctl__kern_sleeptime
);
1030 sysctl_register_oid(&sysctl__kern_waketime
);
1031 sysctl_register_oid(&sysctl__kern_willshutdown
);
1032 #if !CONFIG_EMBEDDED
1033 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1034 sysctl_register_oid(&sysctl__kern_progressmeter
);
1035 #endif /* !CONFIG_EMBEDDED */
1038 IOHibernateSystemInit(this);
1041 registerService(); // let clients find us
1049 void IOPMrootDomain::handleSuspendPMNotificationClient(uint32_t pid
, bool doSuspend
)
1056 if (!pmSuspendedPIDS
) {
1057 pmSuspendedCapacity
= 8;
1058 pmSuspendedSize
= pmSuspendedCapacity
* sizeof(PMNotifySuspendedStruct
);
1059 pmSuspendedPIDS
= (PMNotifySuspendedStruct
*)IOMalloc(pmSuspendedSize
);
1060 bzero(pmSuspendedPIDS
, pmSuspendedSize
);
1063 /* Find the existing pid in the existing array */
1065 for (i
=0; i
< pmSuspendedCapacity
; i
++) {
1066 if (pmSuspendedPIDS
[i
].pid
== pid
) {
1074 /* Find an unused slot in the suspended pids table. */
1076 for (i
=0; i
< pmSuspendedCapacity
; i
++) {
1077 if (pmSuspendedPIDS
[i
].refcount
== 0) {
1082 if (pmSuspendedCapacity
== i
)
1084 /* GROW if necessary */
1086 PMNotifySuspendedStruct
*newSuspended
= NULL
;
1087 pmSuspendedCapacity
*= 2;
1088 pmSuspendedSize
= pmSuspendedCapacity
* sizeof(PMNotifySuspendedStruct
);
1089 newSuspended
= (PMNotifySuspendedStruct
*)IOMalloc(pmSuspendedSize
);
1091 bzero(newSuspended
, pmSuspendedSize
);
1092 bcopy(pmSuspendedPIDS
, newSuspended
, pmSuspendedSize
/2);
1093 IOFree(pmSuspendedPIDS
, pmSuspendedSize
/2);
1095 pmSuspendedPIDS
= newSuspended
;
1099 pmSuspendedPIDS
[index
].pid
= pid
;
1103 pmSuspendedPIDS
[index
].refcount
++;
1105 pmSuspendedPIDS
[index
].refcount
--;
1109 * Publish array of suspended pids in IOPMrootDomain
1111 OSArray
*publish
= OSArray::withCapacity(pmSuspendedCapacity
);
1113 for (i
=0; i
<pmSuspendedCapacity
; i
++)
1115 if (pmSuspendedPIDS
[i
].refcount
> 0) {
1116 OSDictionary
*suspended
= OSDictionary::withCapacity(2);
1119 n
= OSNumber::withNumber(pmSuspendedPIDS
[i
].pid
, 32);
1120 suspended
->setObject("pid", n
);
1123 n
= OSNumber::withNumber(pmSuspendedPIDS
[i
].refcount
, 32);
1124 suspended
->setObject("refcount", n
);
1127 publish
->setObject(suspended
);
1128 suspended
->release();
1133 if (0 != publish
->getCount()) {
1134 setProperty(kPMSuspendedNotificationClients
, publish
);
1136 removeProperty(kPMSuspendedNotificationClients
);
1144 bool IOPMrootDomain::pmNotificationIsSuspended(uint32_t pid
)
1148 for (index
=0; index
< pmSuspendedCapacity
; index
++) {
1149 if (pmSuspendedPIDS
[index
].pid
== pid
) {
1150 return pmSuspendedPIDS
[index
].refcount
> 0;
1158 void IOPMrootDomain::suspendPMNotificationsForPID(uint32_t pid
, bool doSuspend
)
1160 if(pmPowerStateQueue
) {
1161 pmPowerStateQueue
->submitPowerEvent(kPowerEventSuspendClient
, (void *)pid
, (uint64_t)doSuspend
);
1166 //******************************************************************************
1169 // Receive a setProperty call
1170 // The "System Boot" property means the system is completely booted.
1171 //******************************************************************************
1173 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1175 IOReturn return_value
= kIOReturnSuccess
;
1176 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1180 const OSSymbol
*key
;
1182 OSCollectionIterator
* iter
= 0;
1184 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1185 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1186 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1187 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1188 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1189 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1190 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1191 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1192 const OSSymbol
*loginwindow_tracepoint_string
= OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
1193 const OSSymbol
*pmTimelineLogging_string
= OSSymbol::withCString(kIOPMTimelineDictionaryKey
);
1195 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1196 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1197 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1198 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1200 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1201 const OSSymbol
*suspendPMClient_string
= OSSymbol::withCString(kPMSuspendedNotificationClients
);
1206 return_value
= kIOReturnBadArgument
;
1210 iter
= OSCollectionIterator::withCollection(dict
);
1213 return_value
= kIOReturnNoMemory
;
1217 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1218 (obj
= dict
->getObject(key
)))
1220 if (key
->isEqualTo(publish_simulated_battery_string
))
1222 if (OSDynamicCast(OSBoolean
, obj
))
1223 publishResource(key
, kOSBooleanTrue
);
1225 else if (key
->isEqualTo(idle_seconds_string
))
1227 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1229 setProperty(key
, n
);
1230 idleSeconds
= n
->unsigned32BitValue();
1233 else if (key
->isEqualTo(boot_complete_string
))
1235 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1237 else if (key
->isEqualTo(sys_shutdown_string
))
1239 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1240 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1242 else if (key
->isEqualTo(battery_warning_disabled_string
))
1244 setProperty(key
, obj
);
1246 else if (key
->isEqualTo(pmTimelineLogging_string
))
1248 if ((d
= OSDynamicCast(OSDictionary
, obj
)) &&
1249 timeline
&& timeline
->setProperties(d
))
1251 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
1253 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
1259 else if (key
->isEqualTo(hibernatemode_string
) ||
1260 key
->isEqualTo(hibernatefreeratio_string
) ||
1261 key
->isEqualTo(hibernatefreetime_string
))
1263 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1264 setProperty(key
, n
);
1266 else if (key
->isEqualTo(hibernatefile_string
))
1268 OSString
* str
= OSDynamicCast(OSString
, obj
);
1269 if (str
) setProperty(key
, str
);
1272 else if (key
->isEqualTo(sleepdisabled_string
))
1274 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1276 setProperty(key
, b
);
1277 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1280 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1283 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1285 else if (key
->isEqualTo(loginwindow_tracepoint_string
))
1287 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
)))
1288 pmTracer
->traceLoginWindowPhase(n
->unsigned8BitValue());
1290 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1291 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1292 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1293 key
->isEqualTo(stall_halt_string
))
1295 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1296 setProperty(key
, b
);
1298 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1299 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
))
1301 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1302 setProperty(key
, n
);
1304 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1305 else if (key
->isEqualTo(suspendPMClient_string
))
1307 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1309 // Toggle the suspended status for pid n.
1310 uint32_t pid_int
= n
->unsigned32BitValue();
1311 suspendPMNotificationsForPID(pid_int
, !pmNotificationIsSuspended(pid_int
));
1315 // Relay our allowed PM settings onto our registered PM clients
1316 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1318 if ((gIOPMSettingAutoWakeSecondsKey
== key
) && ((n
= OSDynamicCast(OSNumber
, obj
))))
1320 UInt32 rsecs
= n
->unsigned32BitValue();
1322 autoWakeStart
= autoWakeEnd
= 0;
1325 AbsoluteTime deadline
;
1326 clock_interval_to_deadline(rsecs
+ kAutoWakePostWindow
, kSecondScale
, &deadline
);
1327 autoWakeEnd
= AbsoluteTime_to_scalar(&deadline
);
1328 if (rsecs
> kAutoWakePreWindow
)
1329 rsecs
-= kAutoWakePreWindow
;
1332 clock_interval_to_deadline(rsecs
, kSecondScale
, &deadline
);
1333 autoWakeStart
= AbsoluteTime_to_scalar(&deadline
);
1337 return_value
= setPMSetting(key
, obj
);
1338 if (kIOReturnSuccess
!= return_value
)
1341 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1343 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1344 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1346 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1350 _debugWakeSeconds
= 0;
1351 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1353 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1355 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1358 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1359 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1361 const IOPMCalendarStruct
* cs
=
1362 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1365 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1367 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1368 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1374 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1379 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1380 if(boot_complete_string
) boot_complete_string
->release();
1381 if(sys_shutdown_string
) sys_shutdown_string
->release();
1382 if(stall_halt_string
) stall_halt_string
->release();
1383 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1384 if(idle_seconds_string
) idle_seconds_string
->release();
1385 if(sleepdisabled_string
) sleepdisabled_string
->release();
1386 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1387 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1388 if(pmTimelineLogging_string
) pmTimelineLogging_string
->release();
1390 if(hibernatemode_string
) hibernatemode_string
->release();
1391 if(hibernatefile_string
) hibernatefile_string
->release();
1392 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1393 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1395 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1396 if(suspendPMClient_string
) suspendPMClient_string
->release();
1398 if (iter
) iter
->release();
1399 return return_value
;
1403 // MARK: Aggressiveness
1405 //******************************************************************************
1406 // setAggressiveness
1408 // Override IOService::setAggressiveness()
1409 //******************************************************************************
1411 IOReturn
IOPMrootDomain::setAggressiveness(
1413 unsigned long value
)
1415 return setAggressiveness( type
, value
, 0 );
1419 * Private setAggressiveness() with an internal options argument.
1421 IOReturn
IOPMrootDomain::setAggressiveness(
1423 unsigned long value
,
1424 IOOptionBits options
)
1426 AggressivesRequest
* entry
;
1427 AggressivesRequest
* request
;
1430 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1431 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1433 request
= IONew(AggressivesRequest
, 1);
1435 return kIOReturnNoMemory
;
1437 memset(request
, 0, sizeof(*request
));
1438 request
->options
= options
;
1439 request
->dataType
= kAggressivesRequestTypeRecord
;
1440 request
->data
.record
.type
= (uint32_t) type
;
1441 request
->data
.record
.value
= (uint32_t) value
;
1445 // Update disk quick spindown flag used by getAggressiveness().
1446 // Never merge requests with quick spindown flags set.
1448 if (options
& kAggressivesOptionQuickSpindownEnable
)
1449 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1450 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1451 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1454 // Coalesce requests with identical aggressives types.
1455 // Deal with callers that calls us too "aggressively".
1457 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1459 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1460 (entry
->data
.record
.type
== type
) &&
1461 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1463 entry
->data
.record
.value
= value
;
1472 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1475 AGGRESSIVES_UNLOCK();
1478 IODelete(request
, AggressivesRequest
, 1);
1480 if (options
& kAggressivesOptionSynchronous
)
1481 handleAggressivesRequests(); // not truly synchronous
1483 thread_call_enter(aggressivesThreadCall
);
1485 return kIOReturnSuccess
;
1488 //******************************************************************************
1489 // getAggressiveness
1491 // Override IOService::setAggressiveness()
1492 // Fetch the aggressiveness factor with the given type.
1493 //******************************************************************************
1495 IOReturn
IOPMrootDomain::getAggressiveness (
1497 unsigned long * outLevel
)
1503 return kIOReturnBadArgument
;
1507 // Disk quick spindown in effect, report value = 1
1509 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1510 (type
== kPMMinutesToSpinDown
))
1512 value
= kAggressivesMinValue
;
1516 // Consult the pending request queue.
1520 AggressivesRequest
* entry
;
1522 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1524 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1525 (entry
->data
.record
.type
== type
) &&
1526 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1528 value
= entry
->data
.record
.value
;
1535 // Consult the backend records.
1537 if (!source
&& aggressivesData
)
1539 AggressivesRecord
* record
;
1542 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1543 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1545 for (i
= 0; i
< count
; i
++, record
++)
1547 if (record
->type
== type
)
1549 value
= record
->value
;
1556 AGGRESSIVES_UNLOCK();
1560 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1561 source
, (uint32_t) type
, value
);
1562 *outLevel
= (unsigned long) value
;
1563 return kIOReturnSuccess
;
1567 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1568 *outLevel
= 0; // default return = 0, driver may not check for error
1569 return kIOReturnInvalid
;
1573 //******************************************************************************
1574 // joinAggressiveness
1576 // Request from IOService to join future aggressiveness broadcasts.
1577 //******************************************************************************
1579 IOReturn
IOPMrootDomain::joinAggressiveness(
1580 IOService
* service
)
1582 AggressivesRequest
* request
;
1584 if (!service
|| (service
== this))
1585 return kIOReturnBadArgument
;
1587 DLOG("joinAggressiveness %s %p\n", service
->getName(), service
);
1589 request
= IONew(AggressivesRequest
, 1);
1591 return kIOReturnNoMemory
;
1593 service
->retain(); // released by synchronizeAggressives()
1595 memset(request
, 0, sizeof(*request
));
1596 request
->dataType
= kAggressivesRequestTypeService
;
1597 request
->data
.service
= service
;
1600 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1601 AGGRESSIVES_UNLOCK();
1603 thread_call_enter(aggressivesThreadCall
);
1605 return kIOReturnSuccess
;
1608 //******************************************************************************
1609 // handleAggressivesRequests
1611 // Backend thread processes all incoming aggressiveness requests in the queue.
1612 //******************************************************************************
1615 handleAggressivesFunction(
1616 thread_call_param_t param1
,
1617 thread_call_param_t param2
)
1621 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1625 void IOPMrootDomain::handleAggressivesRequests( void )
1627 AggressivesRecord
* start
;
1628 AggressivesRecord
* record
;
1629 AggressivesRequest
* request
;
1630 queue_head_t joinedQueue
;
1634 bool pingSelf
= false;
1638 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1639 queue_empty(&aggressivesQueue
))
1642 gAggressivesState
|= kAggressivesStateBusy
;
1643 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1644 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1649 queue_init(&joinedQueue
);
1653 // Remove request from the incoming queue in FIFO order.
1654 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1655 switch (request
->dataType
)
1657 case kAggressivesRequestTypeRecord
:
1658 // Update existing record if found.
1660 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1662 if (record
->type
== request
->data
.record
.type
)
1666 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1668 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1671 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1672 kAggressivesRecordFlagModified
);
1673 DLOG("disk spindown accelerated, was %u min\n",
1677 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1679 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1682 record
->flags
|= kAggressivesRecordFlagModified
;
1683 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1684 DLOG("disk spindown restored to %u min\n",
1688 else if (record
->value
!= request
->data
.record
.value
)
1690 record
->value
= request
->data
.record
.value
;
1691 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1694 record
->flags
|= kAggressivesRecordFlagModified
;
1701 // No matching record, append a new record.
1703 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1705 AggressivesRecord newRecord
;
1707 newRecord
.flags
= kAggressivesRecordFlagModified
;
1708 newRecord
.type
= request
->data
.record
.type
;
1709 newRecord
.value
= request
->data
.record
.value
;
1710 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1712 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1713 DLOG("disk spindown accelerated\n");
1716 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1718 // OSData may have switched to another (larger) buffer.
1719 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1720 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1724 // Finished processing the request, release it.
1725 IODelete(request
, AggressivesRequest
, 1);
1728 case kAggressivesRequestTypeService
:
1729 // synchronizeAggressives() will free request.
1730 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1734 panic("bad aggressives request type %x\n", request
->dataType
);
1737 } while (!queue_empty(&aggressivesQueue
));
1739 // Release the lock to perform work, with busy flag set.
1740 if (!queue_empty(&joinedQueue
) || broadcast
)
1742 AGGRESSIVES_UNLOCK();
1743 if (!queue_empty(&joinedQueue
))
1744 synchronizeAggressives(&joinedQueue
, start
, count
);
1746 broadcastAggressives(start
, count
);
1750 // Remove the modified flag from all records.
1751 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1753 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1754 ((record
->type
== kPMMinutesToDim
) ||
1755 (record
->type
== kPMMinutesToSleep
)))
1758 record
->flags
&= ~kAggressivesRecordFlagModified
;
1761 // Check the incoming queue again since new entries may have been
1762 // added while lock was released above.
1764 } while (!queue_empty(&aggressivesQueue
));
1766 gAggressivesState
&= ~kAggressivesStateBusy
;
1769 AGGRESSIVES_UNLOCK();
1771 // Root domain is interested in system and display sleep slider changes.
1772 // Submit a power event to handle those changes on the PM work loop.
1774 if (pingSelf
&& pmPowerStateQueue
) {
1775 pmPowerStateQueue
->submitPowerEvent(
1776 kPowerEventPolicyStimulus
,
1777 (void *) kStimulusAggressivenessChanged
);
1781 //******************************************************************************
1782 // synchronizeAggressives
1784 // Push all known aggressiveness records to one or more IOService.
1785 //******************************************************************************
1787 void IOPMrootDomain::synchronizeAggressives(
1788 queue_head_t
* joinedQueue
,
1789 const AggressivesRecord
* array
,
1792 IOService
* service
;
1793 AggressivesRequest
* request
;
1794 const AggressivesRecord
* record
;
1795 IOPMDriverCallEntry callEntry
;
1799 while (!queue_empty(joinedQueue
))
1801 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1802 if (request
->dataType
== kAggressivesRequestTypeService
)
1803 service
= request
->data
.service
;
1807 IODelete(request
, AggressivesRequest
, 1);
1812 if (service
->assertPMDriverCall(&callEntry
))
1814 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1816 value
= record
->value
;
1817 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1818 value
= kAggressivesMinValue
;
1820 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1821 record
->type
, value
, service
->getName());
1822 service
->setAggressiveness(record
->type
, value
);
1824 service
->deassertPMDriverCall(&callEntry
);
1826 service
->release(); // retained by joinAggressiveness()
1831 //******************************************************************************
1832 // broadcastAggressives
1834 // Traverse PM tree and call setAggressiveness() for records that have changed.
1835 //******************************************************************************
1837 void IOPMrootDomain::broadcastAggressives(
1838 const AggressivesRecord
* array
,
1841 IORegistryIterator
* iter
;
1842 IORegistryEntry
* entry
;
1843 IOPowerConnection
* connect
;
1844 IOService
* service
;
1845 const AggressivesRecord
* record
;
1846 IOPMDriverCallEntry callEntry
;
1850 iter
= IORegistryIterator::iterateOver(
1851 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1857 while ((entry
= iter
->getNextObject()))
1859 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1860 if (!connect
|| !connect
->getReadyFlag())
1863 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1865 if (service
->assertPMDriverCall(&callEntry
))
1867 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1869 if (record
->flags
& kAggressivesRecordFlagModified
)
1871 value
= record
->value
;
1872 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1873 value
= kAggressivesMinValue
;
1874 _LOG("broadcastAggressives %x = %u to %s\n",
1875 record
->type
, value
, service
->getName());
1876 service
->setAggressiveness(record
->type
, value
);
1879 service
->deassertPMDriverCall(&callEntry
);
1885 while (!entry
&& !iter
->isValid());
1891 // MARK: System Sleep
1893 //******************************************************************************
1894 // startIdleSleepTimer
1896 //******************************************************************************
1898 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1900 AbsoluteTime deadline
;
1905 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1906 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1907 idleSleepTimerPending
= true;
1911 thread_call_enter(extraSleepTimer
);
1913 DLOG("idle timer set for %u seconds\n", inSeconds
);
1916 //******************************************************************************
1917 // cancelIdleSleepTimer
1919 //******************************************************************************
1921 void IOPMrootDomain::cancelIdleSleepTimer( void )
1924 if (idleSleepTimerPending
)
1926 DLOG("idle timer cancelled\n");
1927 thread_call_cancel(extraSleepTimer
);
1928 idleSleepTimerPending
= false;
1932 //******************************************************************************
1933 // idleSleepTimerExpired
1935 //******************************************************************************
1937 static void idleSleepTimerExpired(
1938 thread_call_param_t us
, thread_call_param_t
)
1940 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
1943 //******************************************************************************
1944 // handleSleepTimerExpiration
1946 // The time between the sleep idle timeout and the next longest one has elapsed.
1947 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1948 //******************************************************************************
1950 void IOPMrootDomain::handleSleepTimerExpiration( void )
1952 if (!getPMworkloop()->inGate())
1954 getPMworkloop()->runAction(
1955 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1956 &IOPMrootDomain::handleSleepTimerExpiration
),
1963 DLOG("sleep timer expired\n");
1966 idleSleepTimerPending
= false;
1968 clock_get_uptime(&time
);
1969 if ((AbsoluteTime_to_scalar(&time
) > autoWakeStart
) &&
1970 (AbsoluteTime_to_scalar(&time
) < autoWakeEnd
))
1972 thread_call_enter_delayed(extraSleepTimer
, *((AbsoluteTime
*) &autoWakeEnd
));
1976 setQuickSpinDownTimeout();
1977 adjustPowerState(true);
1980 //******************************************************************************
1981 // setQuickSpinDownTimeout
1983 //******************************************************************************
1985 void IOPMrootDomain::setQuickSpinDownTimeout( void )
1989 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
1992 //******************************************************************************
1993 // restoreUserSpinDownTimeout
1995 //******************************************************************************
1997 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2001 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2004 //******************************************************************************
2007 //******************************************************************************
2010 IOReturn
IOPMrootDomain::sleepSystem( void )
2012 return sleepSystemOptions(NULL
);
2016 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2018 /* sleepSystem is a public function, and may be called by any kernel driver.
2019 * And that's bad - drivers should sleep the system by calling
2020 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2022 * Note that user space app calls to IOPMSleepSystem() will also travel
2023 * this code path and thus be correctly identified as software sleeps.
2026 if (options
&& options
->getObject("OSSwitch"))
2028 // Log specific sleep cause for OS Switch hibernation
2029 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2031 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2036 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2038 static const char * IOPMSleepReasons
[] = {
2040 kIOPMClamshellSleepKey
,
2041 kIOPMPowerButtonSleepKey
,
2042 kIOPMSoftwareSleepKey
,
2043 kIOPMOSSwitchHibernationKey
,
2045 kIOPMLowPowerSleepKey
,
2046 kIOPMThermalEmergencySleepKey
,
2047 kIOPMMaintenanceSleepKey
,
2048 kIOPMSleepServiceExitKey
,
2049 kIOPMDarkWakeThermalEmergencyKey
2052 PMEventDetails
*details
;
2054 if (!checkSystemCanSleep())
2056 // Record why the system couldn't sleep
2057 details
= PMEventDetails::eventDetails(kIOPMEventTypeSleep
, NULL
,
2058 sleepReason
, kIOReturnNotPermitted
);
2060 recordAndReleasePMEvent( details
);
2061 return kIOReturnNotPermitted
;
2064 if (kIOPMSleepReasonDarkWakeThermalEmergency
== sleepReason
)
2065 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
2068 timeline
->setSleepCycleInProgressFlag(true);
2070 // Time to publish a UUID for the Sleep --> Wake cycle
2071 if(pmPowerStateQueue
) {
2072 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
2075 // Log the beginning of system sleep.
2076 details
= PMEventDetails::eventDetails(kIOPMEventTypeSleep
, NULL
,
2077 sleepReason
, kIOReturnSuccess
);
2079 recordAndReleasePMEvent( details
);
2081 // Record sleep cause in IORegistry
2082 lastSleepReason
= sleepReason
;
2083 sleepReason
-= (kIOPMSleepReasonClamshell
- 1);
2084 if (sleepReason
&& (sleepReason
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0]))) {
2085 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[sleepReason
]);
2088 if (pmPowerStateQueue
)
2089 pmPowerStateQueue
->submitPowerEvent(
2090 kPowerEventPolicyStimulus
,
2091 (void *) kStimulusDemandSystemSleep
);
2093 return kIOReturnSuccess
;
2096 IOReturn
IOPMrootDomain::recordPMEventGated(PMEventDetails
*record
)
2098 // If we don't have a place to log to, we can't actually
2099 // log anything. Chances are, the person who is asking us to do
2100 // the PM logging has forgotten to set the right bootflags
2102 return kIOReturnSuccess
;
2104 if(gIOPMWorkLoop
->inGate() == false) {
2106 IOReturn ret
= gIOPMWorkLoop
->runAction(
2107 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::recordPMEventGated
),
2114 // Now that we're guaranteed to be running in gate ...
2116 // Check the validity of the argument we are given
2118 return kIOReturnBadArgument
;
2120 // Record a driver event, or a system event
2121 if(record
->eventClassifier
== kIOPMEventClassDriverEvent
2122 || record
->eventClassifier
== kIOPMEventClassSystemEvent
)
2123 return this->recordPMEvent(record
);
2126 return kIOReturnBadArgument
;
2130 IOReturn
IOPMrootDomain::recordAndReleasePMEventGated(PMEventDetails
*record
)
2132 IOReturn ret
= kIOReturnBadArgument
;
2136 ret
= recordPMEventGated(record
);
2143 //******************************************************************************
2146 // This overrides powerChangeDone in IOService.
2147 //******************************************************************************
2149 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2151 PMEventDetails
*details
;
2154 DLOG("PowerChangeDone: %u->%u\n",
2155 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2157 switch ( getPowerState() )
2160 if (previousPowerState
!= ON_STATE
)
2163 details
= PMEventDetails::eventDetails(
2164 kIOPMEventTypeSleepDone
,
2169 recordAndReleasePMEvent( details
);
2171 // re-enable this timer for next sleep
2172 cancelIdleSleepTimer();
2175 clock_usec_t microsecs
;
2176 clock_get_calendar_microtime(&secs
, µsecs
);
2178 gIOLastSleepTime
.tv_sec
= secs
;
2179 gIOLastSleepTime
.tv_usec
= microsecs
;
2180 gIOLastWakeTime
.tv_sec
= 0;
2181 gIOLastWakeTime
.tv_usec
= 0;
2184 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2186 IOHibernateSystemHasSlept();
2188 evaluateSystemSleepPolicyFinal();
2190 LOG("System Sleep\n");
2193 getPlatform()->sleepKernel();
2195 // The CPU(s) are off at this point,
2196 // Code will resume execution here upon wake.
2198 clock_get_uptime(&systemWakeTime
);
2201 IOHibernateSystemWake();
2204 // sleep transition complete
2205 gSleepOrShutdownPending
= 0;
2207 // trip the reset of the calendar clock
2208 clock_wakeup_calendar();
2211 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2215 getPlatform()->PMLog(kIOPMrootDomainClass
, kPMLogSystemWake
, 0, 0);
2216 lowBatteryCondition
= false;
2217 lastSleepReason
= 0;
2219 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2220 _debugWakeSeconds
= 0;
2221 _scheduledAlarms
= 0;
2223 // And start logging the wake event here
2224 // TODO: Publish the wakeReason string as an integer
2225 details
= PMEventDetails::eventDetails(
2231 recordAndReleasePMEvent( details
);
2237 #if defined(__i386__) || defined(__x86_64__)
2238 wranglerTickled
= false;
2239 graphicsSuppressed
= false;
2240 darkWakePostTickle
= false;
2241 logGraphicsClamp
= true;
2242 logWranglerTickle
= true;
2243 sleepTimerMaintenance
= false;
2244 wranglerTickleLatched
= false;
2245 darkWakeThermalAlarm
= false;
2246 darkWakeThermalEmergency
= false;
2248 OSString
* wakeType
= OSDynamicCast(
2249 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2250 OSString
* wakeReason
= OSDynamicCast(
2251 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2253 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2255 lowBatteryCondition
= true;
2256 darkWakeMaintenance
= true;
2257 darkWakeToSleepASAP
= true;
2259 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2261 OSNumber
* hibOptions
= OSDynamicCast(
2262 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2264 if (hibernateAborted
|| ((hibOptions
&&
2265 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2267 // Hibernate aborted, or EFI brought up graphics
2268 wranglerTickled
= true;
2272 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2273 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2275 // User wake or RTC alarm
2276 wranglerTickled
= true;
2280 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2282 // SMC standby timer trumps SleepX
2283 darkWakeMaintenance
= true;
2284 darkWakeToSleepASAP
= true;
2285 sleepTimerMaintenance
= true;
2288 if ((_lastDebugWakeSeconds
!= 0) &&
2289 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2291 // SleepX before maintenance
2292 wranglerTickled
= true;
2296 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2298 darkWakeMaintenance
= true;
2299 darkWakeToSleepASAP
= true;
2303 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2305 darkWakeToSleepASAP
= true;
2306 // darkWakeMaintenance = true; // ????
2307 darkWakeSleepService
= true;
2311 // Unidentified wake source, resume to full wake if debug
2312 // alarm is pending.
2314 if (_lastDebugWakeSeconds
&&
2315 (!wakeReason
|| wakeReason
->isEqualTo("")))
2316 wranglerTickled
= true;
2318 darkWakeToSleepASAP
= true;
2324 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2326 darkWakeMaintenance
= true;
2327 darkWakeToSleepASAP
= true;
2328 sleepTimerMaintenance
= true;
2330 else if (hibernateAborted
|| !wakeType
||
2331 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2332 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2334 // Post a HID tickle immediately - except for RTC maintenance wake.
2335 wranglerTickled
= true;
2339 darkWakeMaintenance
= true;
2340 darkWakeToSleepASAP
= true;
2344 if (wranglerTickled
)
2346 else if (!darkWakeMaintenance
)
2348 // Early/late tickle for non-maintenance wake.
2349 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2350 kDarkWakeFlagHIDTickleEarly
) ||
2351 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2352 kDarkWakeFlagHIDTickleLate
))
2354 darkWakePostTickle
= true;
2357 #else /* !__i386__ && !__x86_64__ */
2358 // stay awake for at least 30 seconds
2359 wranglerTickled
= true;
2360 startIdleSleepTimer(30);
2363 changePowerStateToPriv(ON_STATE
);
2367 if (previousPowerState
!= ON_STATE
)
2369 details
= PMEventDetails::eventDetails(
2370 kIOPMEventTypeWakeDone
,
2375 recordAndReleasePMEvent( details
);
2381 //******************************************************************************
2382 // requestPowerDomainState
2384 // Extend implementation in IOService. Running on PM work loop thread.
2385 //******************************************************************************
2387 IOReturn
IOPMrootDomain::requestPowerDomainState (
2388 IOPMPowerFlags childDesire
,
2389 IOPowerConnection
* childConnection
,
2390 unsigned long specification
)
2392 // Idle and system sleep prevention flags affects driver desire.
2393 // Children desire are irrelevant so they are cleared.
2395 return super::requestPowerDomainState(0, childConnection
, specification
);
2398 //******************************************************************************
2399 // updatePreventIdleSleepList
2401 // Called by IOService on PM work loop.
2402 //******************************************************************************
2404 void IOPMrootDomain::updatePreventIdleSleepList(
2405 IOService
* service
, bool addNotRemove
)
2407 unsigned int oldCount
, newCount
;
2411 // Disregard disk I/O (anything besides the display wrangler)
2412 // as a factor preventing idle sleep,except in the case of legacy disk I/O
2414 if ((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOAlways
) &&
2415 addNotRemove
&& (service
!= wrangler
) && (service
!= this))
2420 oldCount
= preventIdleSleepList
->getCount();
2423 preventIdleSleepList
->setObject(service
);
2424 DLOG("prevent idle sleep list: %s+ (%u)\n",
2425 service
->getName(), preventIdleSleepList
->getCount());
2427 else if (preventIdleSleepList
->member(service
))
2429 preventIdleSleepList
->removeObject(service
);
2430 DLOG("prevent idle sleep list: %s- (%u)\n",
2431 service
->getName(), preventIdleSleepList
->getCount());
2433 newCount
= preventIdleSleepList
->getCount();
2435 if ((oldCount
== 0) && (newCount
!= 0))
2437 // Driver added to empty prevent list.
2438 // Update the driver desire to prevent idle sleep.
2439 // Driver desire does not prevent demand sleep.
2441 changePowerStateTo(ON_STATE
);
2443 else if ((oldCount
!= 0) && (newCount
== 0))
2445 // Last driver removed from prevent list.
2446 // Drop the driver clamp to allow idle sleep.
2448 changePowerStateTo(SLEEP_STATE
);
2449 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2453 //******************************************************************************
2454 // preventSystemSleepListUpdate
2456 // Called by IOService on PM work loop.
2457 //******************************************************************************
2459 void IOPMrootDomain::updatePreventSystemSleepList(
2460 IOService
* service
, bool addNotRemove
)
2462 unsigned int oldCount
;
2465 if (this == service
)
2468 oldCount
= preventSystemSleepList
->getCount();
2471 preventSystemSleepList
->setObject(service
);
2472 DLOG("prevent system sleep list: %s+ (%u)\n",
2473 service
->getName(), preventSystemSleepList
->getCount());
2475 else if (preventSystemSleepList
->member(service
))
2477 preventSystemSleepList
->removeObject(service
);
2478 DLOG("prevent system sleep list: %s- (%u)\n",
2479 service
->getName(), preventSystemSleepList
->getCount());
2481 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2483 // Lost all system sleep preventers.
2484 // Send stimulus if system sleep was blocked, and is in dark wake.
2485 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2490 //******************************************************************************
2493 // Override the superclass implementation to send a different message type.
2494 //******************************************************************************
2496 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2498 DLOG("tellChangeDown %u->%u\n",
2499 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2501 if (SLEEP_STATE
== stateNum
)
2503 if (!ignoreTellChangeDown
)
2504 tracePoint( kIOPMTracePointSleepApplications
);
2506 tracePoint( kIOPMTracePointSleepPriorityClients
);
2509 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2511 userActivityAtSleep
= userActivityCount
;
2512 hibernateAborted
= false;
2513 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2515 // Direct callout into OSKext so it can disable kext unloads
2516 // during sleep/wake to prevent deadlocks.
2517 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2519 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2521 // Notify platform that sleep has begun
2522 getPlatform()->callPlatformFunction(
2523 sleepMessagePEFunction
, false,
2524 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2527 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2528 // But tellClientsWithResponse() must be called for both.
2529 ignoreTellChangeDown
= true;
2532 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2535 //******************************************************************************
2538 // Override the superclass implementation to send a different message type.
2539 // This must be idle sleep since we don't ask during any other power change.
2540 //******************************************************************************
2542 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2544 DLOG("askChangeDown %u->%u\n",
2545 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2547 // Don't log for dark wake entry
2548 if (kSystemTransitionSleep
== _systemTransitionType
)
2549 tracePoint( kIOPMTracePointSleepApplications
);
2551 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2554 //******************************************************************************
2555 // askChangeDownDone
2557 // Called by PM after all apps have responded to kIOMessageCanSystemSleep.
2558 // pmconfigd may create a deny sleep assertion before ack'ing.
2559 //******************************************************************************
2561 void IOPMrootDomain::askChangeDownDone(
2562 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2564 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2565 *inOutChangeFlags
, *cancel
,
2566 _systemTransitionType
,
2567 _currentCapability
, _pendingCapability
);
2569 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2571 // Dark->Sleep transition.
2572 // Check if there are any deny sleep assertions.
2573 // Full->Dark transition is never cancelled.
2575 if (!checkSystemCanSleep(true))
2577 // Cancel dark wake to sleep transition.
2578 // Must re-scan assertions upon entering dark wake.
2581 DLOG("cancel dark->sleep\n");
2586 //******************************************************************************
2589 // Notify registered applications and kernel clients that we are not dropping
2592 // We override the superclass implementation so we can send a different message
2593 // type to the client or application being notified.
2595 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2596 //******************************************************************************
2598 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2600 DLOG("tellNoChangeDown %u->%u\n",
2601 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2603 // Sleep canceled, clear the sleep trace point.
2604 tracePoint(kIOPMTracePointSystemUp
);
2610 // stay awake for at least idleSeconds
2611 startIdleSleepTimer(idleSeconds
);
2614 else if (sleepSlider
&& wranglerAsleep
)
2616 // Display wrangler is already asleep, it won't trigger the next
2617 // idle sleep attempt. Schedule a future idle sleep attempt, and
2618 // also push out the next idle sleep attempt.
2620 startIdleSleepTimer( kIdleSleepRetryInterval
);
2623 return tellClients( kIOMessageSystemWillNotSleep
);
2626 //******************************************************************************
2629 // Notify registered applications and kernel clients that we are raising power.
2631 // We override the superclass implementation so we can send a different message
2632 // type to the client or application being notified.
2633 //******************************************************************************
2635 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2638 DLOG("tellChangeUp %u->%u\n",
2639 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2641 ignoreTellChangeDown
= false;
2643 if ( stateNum
== ON_STATE
)
2645 // Direct callout into OSKext so it can disable kext unloads
2646 // during sleep/wake to prevent deadlocks.
2647 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2649 // Notify platform that sleep was cancelled or resumed.
2650 getPlatform()->callPlatformFunction(
2651 sleepMessagePEFunction
, false,
2652 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2655 if (getPowerState() == ON_STATE
)
2657 // this is a quick wake from aborted sleep
2658 if (idleSeconds
&& !wrangler
)
2660 // stay awake for at least idleSeconds
2661 startIdleSleepTimer(idleSeconds
);
2663 tellClients( kIOMessageSystemWillPowerOn
);
2666 tracePoint( kIOPMTracePointWakeApplications
);
2668 if (pmStatsAppResponses
)
2670 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
2671 pmStatsAppResponses
->release();
2672 pmStatsAppResponses
= OSArray::withCapacity(5);
2675 tellClients( kIOMessageSystemHasPoweredOn
);
2679 //******************************************************************************
2680 // sysPowerDownHandler
2682 // Perform a vfs sync before system sleep.
2683 //******************************************************************************
2685 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2686 void * target
, void * refCon
,
2687 UInt32 messageType
, IOService
* service
,
2688 void * messageArgs
, vm_size_t argSize
)
2692 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2695 return kIOReturnUnsupported
;
2697 if (messageType
== kIOMessageSystemCapabilityChange
)
2699 IOPMSystemCapabilityChangeParameters
* params
=
2700 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2702 // Interested applications have been notified of an impending power
2703 // change and have acked (when applicable).
2704 // This is our chance to save whatever state we can before powering
2706 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2709 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2710 params
->fromCapabilities
, params
->toCapabilities
,
2711 params
->changeFlags
);
2713 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2714 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2715 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2717 // We will ack within 20 seconds
2718 params
->maxWaitForReply
= 20 * 1000 * 1000;
2720 gRootDomain
->evaluateSystemSleepPolicyEarly();
2722 // add in time we could spend freeing pages
2723 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2725 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2727 DLOG("sysPowerDownHandler timeout %d s\n", (int) (params
->maxWaitForReply
/ 1000 / 1000));
2730 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2732 // Purposely delay the ack and hope that shutdown occurs quickly.
2733 // Another option is not to schedule the thread and wait for
2735 AbsoluteTime deadline
;
2736 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2737 thread_call_enter1_delayed(
2738 gRootDomain
->diskSyncCalloutEntry
,
2739 (thread_call_param_t
) params
->notifyRef
,
2744 gRootDomain
->diskSyncCalloutEntry
,
2745 (thread_call_param_t
) params
->notifyRef
);
2749 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2750 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2751 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2753 // We will ack within 110 seconds
2754 params
->maxWaitForReply
= 110 * 1000 * 1000;
2757 gRootDomain
->diskSyncCalloutEntry
,
2758 (thread_call_param_t
) params
->notifyRef
);
2761 ret
= kIOReturnSuccess
;
2767 //******************************************************************************
2768 // handleQueueSleepWakeUUID
2770 // Called from IOPMrootDomain when we're initiating a sleep,
2771 // or indirectly from PM configd when PM decides to clear the UUID.
2772 // PM clears the UUID several minutes after successful wake from sleep,
2773 // so that we might associate App spindumps with the immediately previous
2776 // @param obj has a retain on it. We're responsible for releasing that retain.
2777 //******************************************************************************
2779 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2781 OSString
*str
= NULL
;
2783 if (kOSBooleanFalse
== obj
)
2785 handlePublishSleepWakeUUID(NULL
);
2787 else if ((str
= OSDynamicCast(OSString
, obj
)))
2789 // This branch caches the UUID for an upcoming sleep/wake
2790 if (queuedSleepWakeUUIDString
) {
2791 queuedSleepWakeUUIDString
->release();
2792 queuedSleepWakeUUIDString
= NULL
;
2794 queuedSleepWakeUUIDString
= str
;
2795 queuedSleepWakeUUIDString
->retain();
2797 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2806 //******************************************************************************
2807 // handlePublishSleepWakeUUID
2809 // Called from IOPMrootDomain when we're initiating a sleep,
2810 // or indirectly from PM configd when PM decides to clear the UUID.
2811 // PM clears the UUID several minutes after successful wake from sleep,
2812 // so that we might associate App spindumps with the immediately previous
2814 //******************************************************************************
2816 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2821 * Clear the current UUID
2823 if (gSleepWakeUUIDIsSet
)
2825 DLOG("SleepWake UUID cleared\n");
2827 OSString
*UUIDstring
= NULL
;
2830 (UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))))
2832 PMEventDetails
*details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDClear
,
2833 UUIDstring
->getCStringNoCopy(), NULL
, 0);
2835 timeline
->recordSystemPowerEvent( details
);
2838 timeline
->setNumEventsLoggedThisPeriod(0);
2841 gSleepWakeUUIDIsSet
= false;
2843 removeProperty(kIOPMSleepWakeUUIDKey
);
2844 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2848 * Optionally, publish a new UUID
2850 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2852 OSString
*publishThisUUID
= NULL
;
2854 publishThisUUID
= queuedSleepWakeUUIDString
;
2855 publishThisUUID
->retain();
2858 PMEventDetails
*details
;
2859 details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDSet
,
2860 publishThisUUID
->getCStringNoCopy(), NULL
, 0);
2862 timeline
->recordSystemPowerEvent( details
);
2867 if (publishThisUUID
)
2869 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
2870 publishThisUUID
->release();
2873 gSleepWakeUUIDIsSet
= true;
2874 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
2876 queuedSleepWakeUUIDString
->release();
2877 queuedSleepWakeUUIDString
= NULL
;
2881 //******************************************************************************
2882 // changePowerStateTo & changePowerStateToPriv
2884 // Override of these methods for logging purposes.
2885 //******************************************************************************
2887 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
2889 DLOG("changePowerStateTo(%lu)\n", ordinal
);
2891 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2892 return kIOReturnUnsupported
;
2894 return super::changePowerStateTo(ordinal
);
2897 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
2899 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
2901 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2902 return kIOReturnUnsupported
;
2904 return super::changePowerStateToPriv(ordinal
);
2907 //******************************************************************************
2910 //******************************************************************************
2912 bool IOPMrootDomain::activitySinceSleep(void)
2914 return (userActivityCount
!= userActivityAtSleep
);
2917 bool IOPMrootDomain::abortHibernation(void)
2919 bool ret
= activitySinceSleep();
2921 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
2923 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
2924 hibernateAborted
= true;
2930 hibernate_should_abort(void)
2933 return (gRootDomain
->abortHibernation());
2938 //******************************************************************************
2939 // sleepOnClamshellClosed
2941 // contains the logic to determine if the system should sleep when the clamshell
2943 //******************************************************************************
2945 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2947 if (!clamshellExists
)
2950 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d\n",
2951 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
);
2953 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) );
2956 void IOPMrootDomain::sendClientClamshellNotification( void )
2958 /* Only broadcast clamshell alert if clamshell exists. */
2959 if (!clamshellExists
)
2962 setProperty(kAppleClamshellStateKey
,
2963 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
2965 setProperty(kAppleClamshellCausesSleepKey
,
2966 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
2968 /* Argument to message is a bitfiel of
2969 * ( kClamshellStateBit | kClamshellSleepBit )
2971 messageClients(kIOPMMessageClamshellStateChange
,
2972 (void *) ( (clamshellClosed
? kClamshellStateBit
: 0)
2973 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
2976 //******************************************************************************
2977 // getSleepSupported
2980 //******************************************************************************
2982 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
2984 return( platformSleepSupport
);
2987 //******************************************************************************
2988 // setSleepSupported
2991 //******************************************************************************
2993 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
2995 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
2996 OSBitOrAtomic(flags
, &platformSleepSupport
);
2999 //******************************************************************************
3003 //******************************************************************************
3005 void IOPMrootDomain::wakeFromDoze( void )
3007 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3013 //******************************************************************************
3016 // Adds a new feature to the supported features dictionary
3017 //******************************************************************************
3019 void IOPMrootDomain::publishFeature( const char * feature
)
3021 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3024 //******************************************************************************
3025 // publishFeature (with supported power source specified)
3027 // Adds a new feature to the supported features dictionary
3028 //******************************************************************************
3030 void IOPMrootDomain::publishFeature(
3031 const char *feature
,
3032 uint32_t supportedWhere
,
3033 uint32_t *uniqueFeatureID
)
3035 static uint16_t next_feature_id
= 500;
3037 OSNumber
*new_feature_data
= NULL
;
3038 OSNumber
*existing_feature
= NULL
;
3039 OSArray
*existing_feature_arr
= NULL
;
3040 OSObject
*osObj
= NULL
;
3041 uint32_t feature_value
= 0;
3043 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3045 if(!supportedWhere
) {
3046 // Feature isn't supported anywhere!
3050 if(next_feature_id
> 5000) {
3051 // Far, far too many features!
3055 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3057 OSDictionary
*features
=
3058 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3060 // Create new features dict if necessary
3061 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3062 features
= OSDictionary::withDictionary(features
);
3064 features
= OSDictionary::withCapacity(1);
3067 // Create OSNumber to track new feature
3069 next_feature_id
+= 1;
3070 if( uniqueFeatureID
) {
3071 // We don't really mind if the calling kext didn't give us a place
3072 // to stash their unique id. Many kexts don't plan to unload, and thus
3073 // have no need to remove themselves later.
3074 *uniqueFeatureID
= next_feature_id
;
3077 feature_value
= (uint32_t)next_feature_id
;
3078 feature_value
<<= 16;
3079 feature_value
+= supportedWhere
;
3081 new_feature_data
= OSNumber::withNumber(
3082 (unsigned long long)feature_value
, 32);
3084 // Does features object already exist?
3085 if( (osObj
= features
->getObject(feature
)) )
3087 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3089 // We need to create an OSArray to hold the now 2 elements.
3090 existing_feature_arr
= OSArray::withObjects(
3091 (const OSObject
**)&existing_feature
, 1, 2);
3092 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3094 // Add object to existing array
3095 existing_feature_arr
= OSArray::withArray(
3096 existing_feature_arr
,
3097 existing_feature_arr
->getCount() + 1);
3100 if (existing_feature_arr
)
3102 existing_feature_arr
->setObject(new_feature_data
);
3103 features
->setObject(feature
, existing_feature_arr
);
3104 existing_feature_arr
->release();
3105 existing_feature_arr
= 0;
3108 // The easy case: no previously existing features listed. We simply
3109 // set the OSNumber at key 'feature' and we're on our way.
3110 features
->setObject(feature
, new_feature_data
);
3113 new_feature_data
->release();
3115 setProperty(kRootDomainSupportedFeatures
, features
);
3117 features
->release();
3119 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3121 // Notify EnergySaver and all those in user space so they might
3122 // re-populate their feature specific UI
3123 if(pmPowerStateQueue
) {
3124 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3128 //******************************************************************************
3129 // removePublishedFeature
3131 // Removes previously published feature
3132 //******************************************************************************
3134 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3136 IOReturn ret
= kIOReturnError
;
3137 uint32_t feature_value
= 0;
3138 uint16_t feature_id
= 0;
3139 bool madeAChange
= false;
3141 OSSymbol
*dictKey
= NULL
;
3142 OSCollectionIterator
*dictIterator
= NULL
;
3143 OSArray
*arrayMember
= NULL
;
3144 OSNumber
*numberMember
= NULL
;
3145 OSObject
*osObj
= NULL
;
3146 OSNumber
*osNum
= NULL
;
3147 OSArray
*arrayMemberCopy
;
3149 if (kBadPMFeatureID
== removeFeatureID
)
3150 return kIOReturnNotFound
;
3152 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3154 OSDictionary
*features
=
3155 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3157 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3159 // Any modifications to the dictionary are made to the copy to prevent
3160 // races & crashes with userland clients. Dictionary updated
3161 // automically later.
3162 features
= OSDictionary::withDictionary(features
);
3165 ret
= kIOReturnNotFound
;
3169 // We iterate 'features' dictionary looking for an entry tagged
3170 // with 'removeFeatureID'. If found, we remove it from our tracking
3171 // structures and notify the OS via a general interest message.
3173 dictIterator
= OSCollectionIterator::withCollection(features
);
3178 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3180 osObj
= features
->getObject(dictKey
);
3182 // Each Feature is either tracked by an OSNumber
3183 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3185 feature_value
= numberMember
->unsigned32BitValue();
3186 feature_id
= (uint16_t)(feature_value
>> 16);
3188 if( feature_id
== (uint16_t)removeFeatureID
)
3191 features
->removeObject(dictKey
);
3196 // Or tracked by an OSArray of OSNumbers
3197 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3199 unsigned int arrayCount
= arrayMember
->getCount();
3201 for(unsigned int i
=0; i
<arrayCount
; i
++)
3203 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3208 feature_value
= osNum
->unsigned32BitValue();
3209 feature_id
= (uint16_t)(feature_value
>> 16);
3211 if( feature_id
== (uint16_t)removeFeatureID
)
3214 if( 1 == arrayCount
) {
3215 // If the array only contains one element, remove
3217 features
->removeObject(dictKey
);
3219 // Otherwise remove the element from a copy of the array.
3220 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3221 if (arrayMemberCopy
)
3223 arrayMemberCopy
->removeObject(i
);
3224 features
->setObject(dictKey
, arrayMemberCopy
);
3225 arrayMemberCopy
->release();
3236 dictIterator
->release();
3240 ret
= kIOReturnSuccess
;
3242 setProperty(kRootDomainSupportedFeatures
, features
);
3244 // Notify EnergySaver and all those in user space so they might
3245 // re-populate their feature specific UI
3246 if(pmPowerStateQueue
) {
3247 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3250 ret
= kIOReturnNotFound
;
3254 if(features
) features
->release();
3255 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3259 //******************************************************************************
3260 // publishPMSetting (private)
3262 // Should only be called by PMSettingObject to publish a PM Setting as a
3263 // supported feature.
3264 //******************************************************************************
3266 void IOPMrootDomain::publishPMSetting(
3267 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3269 if (noPublishPMSettings
&&
3270 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3272 // Setting found in noPublishPMSettings array
3273 *featureID
= kBadPMFeatureID
;
3278 feature
->getCStringNoCopy(), where
, featureID
);
3281 //******************************************************************************
3282 // setPMSetting (private)
3284 // Internal helper to relay PM settings changes from user space to individual
3285 // drivers. Should be called only by IOPMrootDomain::setProperties.
3286 //******************************************************************************
3288 IOReturn
IOPMrootDomain::setPMSetting(
3289 const OSSymbol
*type
,
3292 PMSettingCallEntry
*entries
= 0;
3293 OSArray
*chosen
= 0;
3294 const OSArray
*array
;
3295 PMSettingObject
*pmso
;
3296 thread_t thisThread
;
3297 int i
, j
, count
, capacity
;
3300 return kIOReturnBadArgument
;
3304 // Update settings dict so changes are visible from copyPMSetting().
3305 fPMSettingsDict
->setObject(type
, object
);
3307 // Prep all PMSetting objects with the given 'type' for callout.
3308 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3309 if (!array
|| ((capacity
= array
->getCount()) == 0))
3312 // Array to retain PMSetting objects targeted for callout.
3313 chosen
= OSArray::withCapacity(capacity
);
3315 goto unlock_exit
; // error
3317 entries
= IONew(PMSettingCallEntry
, capacity
);
3319 goto unlock_exit
; // error
3320 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3322 thisThread
= current_thread();
3324 for (i
= 0, j
= 0; i
<capacity
; i
++)
3326 pmso
= (PMSettingObject
*) array
->getObject(i
);
3329 entries
[j
].thread
= thisThread
;
3330 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3331 chosen
->setObject(pmso
);
3340 // Call each pmso in the chosen array.
3341 for (i
=0; i
<count
; i
++)
3343 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3344 pmso
->dispatchPMSetting(type
, object
);
3348 for (i
=0; i
<count
; i
++)
3350 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3351 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3352 if (pmso
->waitThread
)
3354 PMSETTING_WAKEUP(pmso
);
3360 if (chosen
) chosen
->release();
3361 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3363 return kIOReturnSuccess
;
3366 //******************************************************************************
3367 // copyPMSetting (public)
3369 // Allows kexts to safely read setting values, without being subscribed to
3371 //******************************************************************************
3373 OSObject
* IOPMrootDomain::copyPMSetting(
3374 OSSymbol
*whichSetting
)
3376 OSObject
*obj
= NULL
;
3378 if(!whichSetting
) return NULL
;
3381 obj
= fPMSettingsDict
->getObject(whichSetting
);
3390 //******************************************************************************
3391 // registerPMSettingController (public)
3393 // direct wrapper to registerPMSettingController with uint32_t power source arg
3394 //******************************************************************************
3396 IOReturn
IOPMrootDomain::registerPMSettingController(
3397 const OSSymbol
* settings
[],
3398 IOPMSettingControllerCallback func
,
3403 return registerPMSettingController(
3405 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3406 func
, target
, refcon
, handle
);
3409 //******************************************************************************
3410 // registerPMSettingController (public)
3412 // Kexts may register for notifications when a particular setting is changed.
3413 // A list of settings is available in IOPM.h.
3415 // * settings - An OSArray containing OSSymbols. Caller should populate this
3416 // array with a list of settings caller wants notifications from.
3417 // * func - A C function callback of the type IOPMSettingControllerCallback
3418 // * target - caller may provide an OSObject *, which PM will pass as an
3419 // target to calls to "func"
3420 // * refcon - caller may provide an void *, which PM will pass as an
3421 // argument to calls to "func"
3422 // * handle - This is a return argument. We will populate this pointer upon
3423 // call success. Hold onto this and pass this argument to
3424 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3426 // kIOReturnSuccess on success
3427 //******************************************************************************
3429 IOReturn
IOPMrootDomain::registerPMSettingController(
3430 const OSSymbol
* settings
[],
3431 uint32_t supportedPowerSources
,
3432 IOPMSettingControllerCallback func
,
3437 PMSettingObject
*pmso
= NULL
;
3438 OSObject
*pmsh
= NULL
;
3439 OSArray
*list
= NULL
;
3442 if (NULL
== settings
||
3446 return kIOReturnBadArgument
;
3449 pmso
= PMSettingObject::pmSettingObject(
3450 (IOPMrootDomain
*) this, func
, target
,
3451 refcon
, supportedPowerSources
, settings
, &pmsh
);
3455 return kIOReturnInternalError
;
3459 for (i
=0; settings
[i
]; i
++)
3461 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3463 // New array of callbacks for this setting
3464 list
= OSArray::withCapacity(1);
3465 settingsCallbacks
->setObject(settings
[i
], list
);
3469 // Add caller to the callback list
3470 list
->setObject(pmso
);
3474 // Return handle to the caller, the setting object is private.
3477 return kIOReturnSuccess
;
3480 //******************************************************************************
3481 // deregisterPMSettingObject (private)
3483 // Only called from PMSettingObject.
3484 //******************************************************************************
3486 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3488 thread_t thisThread
= current_thread();
3489 PMSettingCallEntry
*callEntry
;
3490 OSCollectionIterator
*iter
;
3498 pmso
->disabled
= true;
3500 // Wait for all callout threads to finish.
3503 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3505 if (callEntry
->thread
!= thisThread
)
3513 assert(0 == pmso
->waitThread
);
3514 pmso
->waitThread
= thisThread
;
3515 PMSETTING_WAIT(pmso
);
3516 pmso
->waitThread
= 0;
3520 // Search each PM settings array in the kernel.
3521 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3524 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3526 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3527 index
= array
->getNextIndexOfObject(pmso
, 0);
3529 array
->removeObject(index
);
3540 //******************************************************************************
3541 // informCPUStateChange
3543 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3544 // running on battery, with the lid closed, etc.
3546 // informCPUStateChange is a no-op on non x86 systems
3547 // only x86 has explicit support in the IntelCPUPowerManagement kext
3548 //******************************************************************************
3550 void IOPMrootDomain::informCPUStateChange(
3554 #if defined(__i386__) || defined(__x86_64__)
3556 pmioctlVariableInfo_t varInfoStruct
;
3558 const char *varNameStr
= NULL
;
3559 int32_t *varIndex
= NULL
;
3561 if (kInformAC
== type
) {
3562 varNameStr
= kIOPMRootDomainBatPowerCString
;
3563 varIndex
= &idxPMCPULimitedPower
;
3564 } else if (kInformLid
== type
) {
3565 varNameStr
= kIOPMRootDomainLidCloseCString
;
3566 varIndex
= &idxPMCPUClamshell
;
3571 // Set the new value!
3572 // pmCPUControl will assign us a new ID if one doesn't exist yet
3573 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3574 varInfoStruct
.varID
= *varIndex
;
3575 varInfoStruct
.varType
= vBool
;
3576 varInfoStruct
.varInitValue
= value
;
3577 varInfoStruct
.varCurValue
= value
;
3578 strncpy( (char *)varInfoStruct
.varName
,
3579 (const char *)varNameStr
,
3580 strlen(varNameStr
) + 1 );
3583 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3585 // pmCPU only assigns numerical id's when a new varName is specified
3587 && (*varIndex
== kCPUUnknownIndex
))
3589 // pmCPUControl has assigned us a new variable ID.
3590 // Let's re-read the structure we just SET to learn that ID.
3591 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3595 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3596 *varIndex
= varInfoStruct
.varID
;
3602 #endif /* __i386__ || __x86_64__ */
3606 // MARK: Deep Sleep Policy
3610 //******************************************************************************
3611 // evaluateSystemSleepPolicy
3612 //******************************************************************************
3614 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3618 kIOPMSleepFlagHibernate
= 0x00000001,
3619 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3622 struct IOPMSystemSleepPolicyEntry
3624 uint32_t factorMask
;
3625 uint32_t factorBits
;
3626 uint32_t sleepFlags
;
3627 uint32_t wakeEvents
;
3628 } __attribute__((packed
));
3630 struct IOPMSystemSleepPolicyTable
3634 uint16_t entryCount
;
3635 IOPMSystemSleepPolicyEntry entries
[];
3636 } __attribute__((packed
));
3638 bool IOPMrootDomain::evaluateSystemSleepPolicy(
3639 IOPMSystemSleepParameters
* params
, int sleepPhase
)
3641 const IOPMSystemSleepPolicyTable
* pt
;
3642 OSObject
* prop
= 0;
3643 OSData
* policyData
;
3644 uint64_t currentFactors
= 0;
3645 uint32_t standbyDelay
= 0;
3646 uint32_t powerOffDelay
= 0;
3648 bool standbyEnabled
;
3649 bool powerOffEnabled
;
3652 // Get platform's sleep policy table
3653 if (!gSleepPolicyHandler
)
3655 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3656 if (!prop
) goto done
;
3659 // Fetch additional settings
3660 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
3661 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
3662 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
3663 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
3664 DLOG("standby %d delay %u, powerOff %d delay %u, hibernate %u\n",
3665 standbyEnabled
, standbyDelay
, powerOffEnabled
, powerOffDelay
,
3668 // pmset level overrides
3669 if ((hibernateMode
& kIOHibernateModeOn
) == 0)
3671 if (!gSleepPolicyHandler
)
3673 standbyEnabled
= false;
3674 powerOffEnabled
= false;
3677 else if (!(hibernateMode
& kIOHibernateModeSleep
))
3679 // Force hibernate (i.e. mode 25)
3680 // If standby is enabled, force standy.
3681 // If poweroff is enabled, force poweroff.
3683 currentFactors
|= kIOPMSleepFactorStandbyForced
;
3684 else if (powerOffEnabled
)
3685 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
3687 currentFactors
|= kIOPMSleepFactorHibernateForced
;
3690 // Current factors based on environment and assertions
3691 if (sleepTimerMaintenance
)
3692 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3693 if (!clamshellClosed
)
3694 currentFactors
|= kIOPMSleepFactorLidOpen
;
3695 if (acAdaptorConnected
)
3696 currentFactors
|= kIOPMSleepFactorACPower
;
3697 if (lowBatteryCondition
)
3698 currentFactors
|= kIOPMSleepFactorBatteryLow
;
3700 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
3701 if (!standbyEnabled
)
3702 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
3703 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3704 kIOPMDriverAssertionLevelOff
)
3705 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3706 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3707 kIOPMDriverAssertionLevelOff
)
3708 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3709 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3710 kIOPMDriverAssertionLevelOff
)
3711 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3712 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
3713 kIOPMDriverAssertionLevelOff
)
3714 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
3715 if (_scheduledAlarms
!= 0)
3716 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
3717 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
3718 kIOPMDriverAssertionLevelOff
)
3719 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
3720 if (!powerOffEnabled
)
3721 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
3723 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
3725 DLOG("sleep factors 0x%llx\n", currentFactors
);
3727 // Clear the output params
3728 bzero(params
, sizeof(*params
));
3730 if (gSleepPolicyHandler
)
3732 if (!gSleepPolicyVars
)
3734 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
3735 if (!gSleepPolicyVars
)
3737 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
3739 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
3740 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
3741 if (kIOPMSleepPhase1
== sleepPhase
)
3743 gSleepPolicyVars
->currentCapability
= _currentCapability
;
3744 gSleepPolicyVars
->highestCapability
= _highestCapability
;
3745 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
3746 gSleepPolicyVars
->hibernateMode
= hibernateMode
;
3747 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
3748 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
3750 gSleepPolicyVars
->sleepFactors
= currentFactors
;
3751 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
3752 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
;
3754 if ((gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
) !=
3755 kIOReturnSuccess
) || (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
3756 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
3757 (kIOPMSystemSleepParametersVersion
!= params
->version
))
3759 MSG("sleep policy handler error\n");
3763 if ((params
->sleepType
>= kIOPMSleepTypeSafeSleep
) &&
3764 ((hibernateMode
& kIOHibernateModeOn
) == 0))
3766 hibernateMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
3769 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
3770 params
->version
, params
->sleepType
, params
->sleepFlags
,
3771 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
3776 // Policy table is meaningless without standby enabled
3777 if (!standbyEnabled
)
3780 // Validate the sleep policy table
3781 policyData
= OSDynamicCast(OSData
, prop
);
3782 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
3785 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
3786 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
3787 (pt
->version
!= 1) || (0 == pt
->entryCount
))
3790 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
3791 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
3794 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
3796 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
3797 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
3799 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
3800 entry
->factorMask
, entry
->factorBits
,
3801 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
3805 DLOG("^ found match\n");
3808 params
->version
= kIOPMSystemSleepParametersVersion
;
3809 params
->reserved1
= 1;
3810 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
3811 params
->sleepType
= kIOPMSleepTypeStandby
;
3813 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
3815 params
->ecWakeEvents
= entry
->wakeEvents
;
3816 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
3818 if (kIOPMSleepPhase2
== sleepPhase
)
3820 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
3822 if (!_standbyTimerResetSeconds
||
3823 (now_secs
<= _standbyTimerResetSeconds
))
3825 // Reset standby timer adjustment
3826 _standbyTimerResetSeconds
= now_secs
;
3827 DLOG("standby delay %u, reset %u\n",
3828 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
3830 else if (standbyDelay
)
3832 // Shorten the standby delay timer
3833 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
3834 if (standbyDelay
> elapsed
)
3835 standbyDelay
-= elapsed
;
3837 standbyDelay
= 1; // must be > 0
3839 DLOG("standby delay %u, elapsed %u\n",
3840 standbyDelay
, (uint32_t) elapsed
);
3843 params
->ecWakeTimer
= standbyDelay
;
3845 else if (kIOPMSleepPhase2
== sleepPhase
)
3847 // A sleep that does not enable the sleep timer will reset
3848 // the standby delay adjustment.
3849 _standbyTimerResetSeconds
= 0;
3861 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
3863 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
3865 // Evaluate early (priority interest phase), before drivers sleep.
3867 DLOG("%s\n", __FUNCTION__
);
3868 removeProperty(kIOPMSystemSleepParametersKey
);
3870 // Full wake resets the standby timer delay adjustment
3871 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
3872 _standbyTimerResetSeconds
= 0;
3874 hibernateDisabled
= false;
3876 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
3878 // Save for late evaluation if sleep is aborted
3879 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
3881 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
))
3883 if (!hibernateNoDefeat
&&
3884 (gEarlySystemSleepParams
.sleepType
== kIOPMSleepTypeNormalSleep
))
3886 // Disable hibernate setup for normal sleep
3887 hibernateDisabled
= true;
3891 // Publish IOPMSystemSleepType
3892 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
3893 if (sleepType
== kIOPMSleepTypeInvalid
)
3896 sleepType
= kIOPMSleepTypeNormalSleep
;
3897 if (hibernateMode
& kIOHibernateModeOn
)
3898 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
3899 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
3901 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
3902 (gEarlySystemSleepParams
.ecPoweroffTimer
))
3904 // report the lowest possible sleep state
3905 sleepType
= kIOPMSleepTypePowerOff
;
3908 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
3911 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
3913 IOPMSystemSleepParameters params
;
3914 OSData
* paramsData
;
3916 // Evaluate sleep policy after sleeping drivers but before platform sleep.
3918 DLOG("%s\n", __FUNCTION__
);
3920 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
))
3922 if ((hibernateDisabled
|| hibernateAborted
) &&
3923 (params
.sleepType
!= kIOPMSleepTypeNormalSleep
))
3925 // Final evaluation picked a state requiring hibernation,
3926 // but hibernate setup was skipped. Retry using the early
3927 // sleep parameters.
3929 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
3930 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
3931 params
.ecWakeTimer
= 1;
3932 hibernateNoDefeat
= true;
3933 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
3934 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
);
3938 hibernateNoDefeat
= false;
3941 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
3944 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
3945 paramsData
->release();
3948 if (params
.sleepType
>= kIOPMSleepTypeHibernate
)
3950 // Disable safe sleep to force the hibernate path
3951 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
3956 bool IOPMrootDomain::getHibernateSettings(
3957 uint32_t * hibernateModePtr
,
3958 uint32_t * hibernateFreeRatio
,
3959 uint32_t * hibernateFreeTime
)
3961 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
3962 // has updated the hibernateDisabled flag.
3964 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
3965 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
3966 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
3967 if (hibernateDisabled
)
3968 *hibernateModePtr
= 0;
3969 else if (gSleepPolicyHandler
)
3970 *hibernateModePtr
= hibernateMode
;
3971 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
3975 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
3977 OSObject
* optionsProp
;
3978 OSDictionary
* optionsDict
;
3983 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
3984 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
3988 obj
= optionsDict
->getObject(key
);
3989 if (obj
) obj
->retain();
3993 obj
= copyProperty(key
);
3995 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)))
3997 *option
= num
->unsigned32BitValue();
4004 optionsProp
->release();
4008 #endif /* HIBERNATION */
4011 // MARK: Shutdown and Restart
4013 //******************************************************************************
4014 // handlePlatformHaltRestart
4016 //******************************************************************************
4018 struct HaltRestartApplierContext
{
4019 IOPMrootDomain
* RootDomain
;
4020 unsigned long PowerState
;
4021 IOPMPowerFlags PowerFlags
;
4027 platformHaltRestartApplier( OSObject
* object
, void * context
)
4029 IOPowerStateChangeNotification notify
;
4030 HaltRestartApplierContext
* ctx
;
4031 AbsoluteTime startTime
;
4034 ctx
= (HaltRestartApplierContext
*) context
;
4036 memset(¬ify
, 0, sizeof(notify
));
4037 notify
.powerRef
= (void *)ctx
->Counter
;
4038 notify
.returnValue
= 0;
4039 notify
.stateNumber
= ctx
->PowerState
;
4040 notify
.stateFlags
= ctx
->PowerFlags
;
4042 clock_get_uptime(&startTime
);
4043 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4044 deltaTime
= computeDeltaTimeMS(&startTime
);
4046 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4047 (gIOKitDebug
& kIOLogPMRootDomain
))
4049 _IOServiceInterestNotifier
* notifier
;
4050 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4052 // IOService children of IOPMrootDomain are not instrumented.
4053 // Only IORootParent currently falls under that group.
4057 LOG("%s handler %p took %u ms\n",
4058 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
4059 (ctx
->MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
4060 notifier
->handler
, (uint32_t) deltaTime
);
4067 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4069 HaltRestartApplierContext ctx
;
4070 AbsoluteTime startTime
;
4073 memset(&ctx
, 0, sizeof(ctx
));
4074 ctx
.RootDomain
= this;
4076 clock_get_uptime(&startTime
);
4080 case kPEUPSDelayHaltCPU
:
4081 ctx
.PowerState
= OFF_STATE
;
4082 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4086 ctx
.PowerState
= RESTART_STATE
;
4087 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4091 ctx
.PowerState
= ON_STATE
;
4092 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4093 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4094 IOHibernateSystemRestart();
4101 // Notify legacy clients
4102 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4104 // For normal shutdown, turn off File Server Mode.
4105 if (kPEHaltCPU
== pe_type
)
4107 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4108 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4111 setPMSetting(setting
, num
);
4117 if (kPEPagingOff
!= pe_type
)
4119 // Notify in power tree order
4120 notifySystemShutdown(this, ctx
.MessageType
);
4123 deltaTime
= computeDeltaTimeMS(&startTime
);
4124 LOG("%s all drivers took %u ms\n",
4125 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
4126 (ctx
.MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
4127 (uint32_t) deltaTime
);
4130 //******************************************************************************
4133 //******************************************************************************
4135 IOReturn
IOPMrootDomain::shutdownSystem( void )
4137 return kIOReturnUnsupported
;
4140 //******************************************************************************
4143 //******************************************************************************
4145 IOReturn
IOPMrootDomain::restartSystem( void )
4147 return kIOReturnUnsupported
;
4151 // MARK: System Capability
4153 //******************************************************************************
4154 // tagPowerPlaneService
4156 // Running on PM work loop thread.
4157 //******************************************************************************
4159 void IOPMrootDomain::tagPowerPlaneService(
4160 IOService
* service
,
4161 IOPMActions
* actions
)
4164 bool isDisplayWrangler
;
4166 memset(actions
, 0, sizeof(*actions
));
4167 actions
->target
= this;
4169 if (service
== this)
4171 actions
->actionPowerChangeStart
=
4172 OSMemberFunctionCast(
4173 IOPMActionPowerChangeStart
, this,
4174 &IOPMrootDomain::handleOurPowerChangeStart
);
4176 actions
->actionPowerChangeDone
=
4177 OSMemberFunctionCast(
4178 IOPMActionPowerChangeDone
, this,
4179 &IOPMrootDomain::handleOurPowerChangeDone
);
4181 actions
->actionPowerChangeOverride
=
4182 OSMemberFunctionCast(
4183 IOPMActionPowerChangeOverride
, this,
4184 &IOPMrootDomain::overrideOurPowerChange
);
4189 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4190 if (isDisplayWrangler
)
4195 isDisplayWrangler
= false;
4198 #if defined(__i386__) || defined(__x86_64__)
4199 if (isDisplayWrangler
)
4200 flags
|= kPMActionsFlagIsDisplayWrangler
;
4201 if (service
->getProperty("IOPMStrictTreeOrder"))
4202 flags
|= kPMActionsFlagIsGraphicsDevice
;
4203 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4204 flags
|= kPMActionsFlagIsAudioDevice
;
4207 // Find the power connection object that is a child of the PCI host
4208 // bridge, and has a graphics/audio device attached below. Mark the
4209 // power branch for delayed child notifications.
4213 IORegistryEntry
* child
= service
;
4214 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4216 while (child
!= this)
4218 if ((parent
== pciHostBridgeDriver
) ||
4221 if (OSDynamicCast(IOPowerConnection
, child
))
4223 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4224 conn
->delayChildNotification
= true;
4229 parent
= child
->getParentEntry(gIOPowerPlane
);
4235 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4236 actions
->parameter
|= flags
;
4237 actions
->actionPowerChangeOverride
=
4238 OSMemberFunctionCast(
4239 IOPMActionPowerChangeOverride
, this,
4240 &IOPMrootDomain::overridePowerChangeForUIService
);
4242 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4244 actions
->actionActivityTickle
=
4245 OSMemberFunctionCast(
4246 IOPMActionActivityTickle
, this,
4247 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4252 // Locate the first PCI host bridge for PMTrace.
4253 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4255 IOService
* provider
= service
->getProvider();
4256 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4257 provider
->inPlane(gIODTPlane
))
4259 pciHostBridgeDevice
= provider
;
4260 pciHostBridgeDriver
= service
;
4261 DLOG("PMTrace found PCI host bridge %s->%s\n",
4262 provider
->getName(), service
->getName());
4266 // Tag top-level PCI devices. The order of PMinit() call does not
4267 // change across boots and is used as the PCI bit number.
4268 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4270 // Would prefer to check built-in property, but tagPowerPlaneService()
4271 // is called before pciDevice->registerService().
4272 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4273 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4275 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4278 // Save the assigned bit for fast lookup.
4279 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4281 actions
->actionPowerChangeStart
=
4282 OSMemberFunctionCast(
4283 IOPMActionPowerChangeStart
, this,
4284 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4286 actions
->actionPowerChangeDone
=
4287 OSMemberFunctionCast(
4288 IOPMActionPowerChangeDone
, this,
4289 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4295 //******************************************************************************
4296 // PM actions for root domain
4297 //******************************************************************************
4299 void IOPMrootDomain::overrideOurPowerChange(
4300 IOService
* service
,
4301 IOPMActions
* actions
,
4302 unsigned long * inOutPowerState
,
4303 uint32_t * inOutChangeFlags
)
4305 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4306 uint32_t changeFlags
= *inOutChangeFlags
;
4307 uint32_t currentPowerState
= (uint32_t) getPowerState();
4309 if ((currentPowerState
== powerState
) ||
4310 (changeFlags
& kIOPMParentInitiated
))
4312 // FIXME: cancel any parent change (unexpected)
4313 // Root parent is permanently pegged at max power,
4314 // kIOPMParentInitiated is unexpected.
4318 if (powerState
< currentPowerState
)
4320 if ((changeFlags
& kIOPMSkipAskPowerDown
) == 0)
4322 /* Convenient place to run any code at idle sleep time
4323 * IOPMrootDomain initiates an idle sleep here
4325 * Set last sleep cause accordingly.
4327 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
4329 lastSleepReason
= kIOPMSleepReasonIdle
;
4330 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
4332 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4334 // Root domain is dropping power state ON->SLEEP.
4335 // If system is in full wake, first drop to dark wake.
4337 darkWakeToSleepASAP
= true;
4339 // Drop graphics capability.
4340 // No transition if system is already in dark wake.
4342 _desiredCapability
&= ~(
4343 kIOPMSystemCapabilityGraphics
|
4344 kIOPMSystemCapabilityAudio
);
4346 *inOutPowerState
= ON_STATE
;
4347 *inOutChangeFlags
|= kIOPMSynchronize
;
4349 // Revert device desire from SLEEP->ON.
4350 changePowerStateToPriv(ON_STATE
);
4355 void IOPMrootDomain::handleOurPowerChangeStart(
4356 IOService
* service
,
4357 IOPMActions
* actions
,
4358 uint32_t powerState
,
4359 uint32_t * inOutChangeFlags
)
4361 uint32_t changeFlags
= *inOutChangeFlags
;
4362 uint32_t currentPowerState
= (uint32_t) getPowerState();
4364 _systemTransitionType
= kSystemTransitionNone
;
4365 _systemMessageClientMask
= 0;
4366 capabilityLoss
= false;
4368 // 1. Explicit capability change.
4370 if (changeFlags
& kIOPMSynchronize
)
4372 if (powerState
== ON_STATE
)
4374 if (changeFlags
& kIOPMSyncNoChildNotify
)
4375 _systemTransitionType
= kSystemTransitionNewCapClient
;
4377 _systemTransitionType
= kSystemTransitionCapability
;
4381 // 2. Going to sleep (cancellation still possible).
4383 else if (powerState
< currentPowerState
)
4384 _systemTransitionType
= kSystemTransitionSleep
;
4386 // 3. Woke from (idle or demand) sleep.
4388 else if (!systemBooting
&&
4389 (changeFlags
& kIOPMSelfInitiated
) &&
4390 (powerState
> currentPowerState
))
4392 _systemTransitionType
= kSystemTransitionWake
;
4393 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4394 kIOPMSystemCapabilityNetwork
;
4396 // Check for early HID events (e.g. LID open)
4397 if (wranglerTickled
)
4399 _desiredCapability
|= (
4400 kIOPMSystemCapabilityGraphics
|
4401 kIOPMSystemCapabilityAudio
);
4405 // Update pending wake capability at the beginning of every
4406 // state transition (including synchronize). This will become
4407 // the current capability at the end of the transition.
4409 if (kSystemTransitionSleep
== _systemTransitionType
)
4411 _pendingCapability
= 0;
4412 capabilityLoss
= true;
4414 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4416 _pendingCapability
= _desiredCapability
|
4417 kIOPMSystemCapabilityCPU
|
4418 kIOPMSystemCapabilityNetwork
;
4420 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4421 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4423 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4424 (_pendingCapability
== _currentCapability
))
4426 // Cancel the PM state change.
4427 _systemTransitionType
= kSystemTransitionNone
;
4428 *inOutChangeFlags
|= kIOPMNotDone
;
4430 if (__builtin_popcount(_pendingCapability
) <
4431 __builtin_popcount(_currentCapability
))
4432 capabilityLoss
= true;
4433 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4434 rejectWranglerTickle
= true;
4437 // 1. Capability change.
4439 if (kSystemTransitionCapability
== _systemTransitionType
)
4441 // Dark to Full transition.
4442 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4444 tracePoint( kIOPMTracePointDarkWakeExit
);
4445 wranglerSleepIgnored
= false;
4446 sleepTimerMaintenance
= false;
4447 hibernateNoDefeat
= false;
4448 _systemMessageClientMask
= kSystemMessageClientUser
;
4449 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4450 _systemMessageClientMask
|= kSystemMessageClientKernel
;
4452 tellClients(kIOMessageSystemWillPowerOn
);
4455 // Full to Dark transition.
4456 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4458 tracePoint( kIOPMTracePointDarkWakeEntry
);
4459 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4460 _systemMessageClientMask
= kSystemMessageClientUser
;
4466 else if (kSystemTransitionSleep
== _systemTransitionType
)
4468 // Beginning of a system sleep transition.
4469 // Cancellation is still possible.
4470 tracePoint( kIOPMTracePointSleepStarted
, lastSleepReason
);
4472 _systemMessageClientMask
= kSystemMessageClientAll
;
4473 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4474 _systemMessageClientMask
&= ~kSystemMessageClientApp
;
4475 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4476 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4478 // Optimization to ignore wrangler power down thus skipping
4479 // the disk spindown and arming the idle timer for demand sleep.
4481 if (changeFlags
& kIOPMIgnoreChildren
)
4483 wranglerSleepIgnored
= true;
4486 logWranglerTickle
= false;
4491 else if (kSystemTransitionWake
== _systemTransitionType
)
4493 wranglerSleepIgnored
= false;
4495 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4497 _systemMessageClientMask
= kSystemMessageClientAll
;
4501 _systemMessageClientMask
= kSystemMessageClientConfigd
;
4504 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4505 tellClients(kIOMessageSystemWillPowerOn
);
4508 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4509 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4511 _systemStateGeneration
++;
4512 systemDarkWake
= false;
4514 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4516 currentPowerState
, powerState
, *inOutChangeFlags
,
4517 _systemTransitionType
, _systemStateGeneration
,
4518 _systemMessageClientMask
,
4519 _desiredCapability
, _currentCapability
, _pendingCapability
);
4523 void IOPMrootDomain::handleOurPowerChangeDone(
4524 IOService
* service
,
4525 IOPMActions
* actions
,
4526 uint32_t powerState
,
4527 uint32_t changeFlags
)
4529 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4531 _systemTransitionType
= kSystemTransitionNone
;
4535 if (_systemTransitionType
!= kSystemTransitionNone
)
4537 uint32_t currentPowerState
= (uint32_t) getPowerState();
4539 if (changeFlags
& kIOPMNotDone
)
4541 // Power down was cancelled or vetoed.
4542 _pendingCapability
= _currentCapability
;
4543 lastSleepReason
= 0;
4545 if (((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4546 (_currentCapability
& kIOPMSystemCapabilityCPU
))
4548 pmPowerStateQueue
->submitPowerEvent(
4549 kPowerEventPolicyStimulus
,
4550 (void *) kStimulusDarkWakeReentry
,
4551 _systemStateGeneration
);
4554 // Revert device desire to max.
4555 changePowerStateToPriv(ON_STATE
);
4559 // Send message on dark wake to full wake promotion.
4560 // tellChangeUp() handles the normal SLEEP->ON case.
4562 if (kSystemTransitionCapability
== _systemTransitionType
)
4564 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4566 tellClients(kIOMessageSystemHasPoweredOn
);
4567 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4568 // Re-evaluate clamshell state ourselves when graphics
4569 // will not get kIOMessageSystemHasPoweredOn.
4571 if (clamshellClosed
&&
4572 ((_systemMessageClientMask
& kSystemMessageClientKernel
) == 0))
4574 receivePowerNotification( kLocalEvalClamshellCommand
);
4578 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4579 wranglerTickled
= false;
4582 // Reset state after exiting from dark wake.
4584 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
4585 CAP_LOSS(kIOPMSystemCapabilityCPU
))
4587 darkWakeMaintenance
= false;
4588 darkWakeToSleepASAP
= false;
4589 pciCantSleepValid
= false;
4590 rejectWranglerTickle
= false;
4591 darkWakeSleepService
= false;
4594 // Entered dark mode.
4596 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4597 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
4599 if (((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOInDark
) == 0) &&
4600 (kSystemTransitionWake
== _systemTransitionType
) &&
4601 (_lastDebugWakeSeconds
== 0))
4603 OSObject
* prop
= copyProperty(kIOPMRootDomainWakeTypeKey
);
4606 OSString
* wakeType
= OSDynamicCast(OSString
, prop
);
4608 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeNetwork
))
4610 // Woke from network and entered dark wake.
4611 if (darkWakeToSleepASAP
)
4613 DLOG("cleared darkWakeToSleepASAP\n");
4614 darkWakeToSleepASAP
= false;
4621 // Queue an evaluation of whether to remain in dark wake,
4622 // and for how long. This serves the purpose of draining
4623 // any assertions from the queue.
4625 pmPowerStateQueue
->submitPowerEvent(
4626 kPowerEventPolicyStimulus
,
4627 (void *) kStimulusDarkWakeEntry
,
4628 _systemStateGeneration
);
4632 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4633 "dcp %x:%x:%x, dbgtimer %u\n",
4634 currentPowerState
, powerState
, changeFlags
,
4635 _systemTransitionType
, _systemStateGeneration
,
4636 _systemMessageClientMask
,
4637 _desiredCapability
, _currentCapability
, _pendingCapability
,
4638 _lastDebugWakeSeconds
);
4640 // Update current system capability.
4642 if (_currentCapability
!= _pendingCapability
)
4643 _currentCapability
= _pendingCapability
;
4645 // Update highest system capability.
4647 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU
))
4648 _highestCapability
= 0; // reset at sleep state
4650 _highestCapability
|= _currentCapability
;
4652 if (darkWakePostTickle
&&
4653 (kSystemTransitionWake
== _systemTransitionType
) &&
4654 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4655 kDarkWakeFlagHIDTickleLate
)
4657 darkWakePostTickle
= false;
4661 // Reset tracepoint at completion of capability change,
4662 // completion of wake transition, and aborted sleep transition.
4664 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
4665 (_systemTransitionType
== kSystemTransitionWake
) ||
4666 ((_systemTransitionType
== kSystemTransitionSleep
) &&
4667 (changeFlags
& kIOPMNotDone
)))
4669 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
4670 tracePoint( kIOPMTracePointSystemUp
, 0 );
4672 // kIOPMDWOverTemp notification handling was postponed
4673 if (darkWakeThermalAlarm
)
4675 if (!wranglerTickled
&& !darkWakeThermalEmergency
&&
4676 CAP_CURRENT(kIOPMSystemCapabilityCPU
) &&
4677 !CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4679 darkWakeThermalEmergency
= true;
4680 privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
4681 MSG("DarkWake thermal limits breached. Going to sleep!\n");
4683 darkWakeThermalAlarm
= false;
4687 _systemTransitionType
= kSystemTransitionNone
;
4688 _systemMessageClientMask
= 0;
4690 logGraphicsClamp
= false;
4694 //******************************************************************************
4695 // PM actions for graphics and audio.
4696 //******************************************************************************
4698 void IOPMrootDomain::overridePowerChangeForUIService(
4699 IOService
* service
,
4700 IOPMActions
* actions
,
4701 unsigned long * inOutPowerState
,
4702 uint32_t * inOutChangeFlags
)
4704 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4705 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
4707 if (kSystemTransitionNone
== _systemTransitionType
)
4709 // Not in midst of a system transition.
4710 // Do not modify power limit enable state.
4712 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4714 // Activate power limiter.
4716 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4717 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4718 (changeFlags
& kIOPMSynchronize
))
4720 actions
->parameter
|= kPMActionsFlagLimitPower
;
4722 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4723 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
4724 (changeFlags
& kIOPMSynchronize
))
4726 actions
->parameter
|= kPMActionsFlagLimitPower
;
4728 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
4729 (_systemTransitionType
== kSystemTransitionSleep
))
4731 // For graphics devices, arm the limiter when entering
4732 // system sleep. Not when dropping to dark wake.
4733 actions
->parameter
|= kPMActionsFlagLimitPower
;
4736 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4738 DLOG("+ plimit %s %p\n",
4739 service
->getName(), service
);
4744 // Remove power limit.
4746 if ((actions
->parameter
& (
4747 kPMActionsFlagIsDisplayWrangler
|
4748 kPMActionsFlagIsGraphicsDevice
)) &&
4749 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
4751 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4753 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4754 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
4756 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4759 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4761 DLOG("- plimit %s %p\n",
4762 service
->getName(), service
);
4766 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4768 uint32_t maxPowerState
= (uint32_t)(-1);
4770 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
4772 // Enforce limit for system power/cap transitions.
4775 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4776 (service
->getPowerState() > 0))
4778 // Forces a 3->1 transition sequence
4779 if (changeFlags
& kIOPMDomainWillChange
)
4784 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
4791 // Deny all self-initiated changes when power is limited.
4792 // Wrangler tickle should never defeat the limiter.
4794 maxPowerState
= service
->getPowerState();
4797 if (powerState
> maxPowerState
)
4799 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4800 service
->getName(), service
, powerState
, maxPowerState
,
4802 *inOutPowerState
= maxPowerState
;
4804 if (darkWakePostTickle
&&
4805 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4806 (changeFlags
& kIOPMDomainWillChange
) &&
4807 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4808 kDarkWakeFlagHIDTickleEarly
))
4810 darkWakePostTickle
= false;
4815 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
4817 if (logGraphicsClamp
)
4822 clock_get_uptime(&now
);
4823 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
4824 absolutetime_to_nanoseconds(now
, &nsec
);
4825 MSG("Graphics suppressed %u ms\n",
4826 ((int)((nsec
) / 1000000ULL)));
4828 graphicsSuppressed
= true;
4833 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4834 IOService
* service
,
4835 IOPMActions
* actions
)
4837 // Warning: Not running in PM work loop context - don't modify state !!!
4838 // Trap tickle directed to IODisplayWrangler while running with graphics
4839 // capability suppressed.
4841 assert(service
== wrangler
);
4843 if (service
== wrangler
)
4845 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
4846 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
4848 userActivityCount
++;
4849 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
4853 if (!wranglerTickled
&&
4854 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4856 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
4857 DLOG("display wrangler tickled\n");
4858 if (kIOLogPMRootDomain
& gIOKitDebug
)
4859 OSReportWithBacktrace("Dark wake display tickle");
4860 if (pmPowerStateQueue
)
4862 pmPowerStateQueue
->submitPowerEvent(
4863 kPowerEventPolicyStimulus
,
4864 (void *) kStimulusDarkWakeActivityTickle
);
4869 //******************************************************************************
4870 // Approve usage of delayed child notification by PM.
4871 //******************************************************************************
4873 bool IOPMrootDomain::shouldDelayChildNotification(
4874 IOService
* service
)
4876 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
4878 (kSystemTransitionWake
== _systemTransitionType
))
4880 DLOG("%s: delay child notify\n", service
->getName());
4886 //******************************************************************************
4887 // PM actions for PCI device.
4888 //******************************************************************************
4890 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
4891 IOService
* service
,
4892 IOPMActions
* actions
,
4893 uint32_t powerState
,
4894 uint32_t * inOutChangeFlags
)
4896 pmTracer
->tracePCIPowerChange(
4897 PMTraceWorker::kPowerChangeStart
,
4898 service
, *inOutChangeFlags
,
4899 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
4902 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
4903 IOService
* service
,
4904 IOPMActions
* actions
,
4905 uint32_t powerState
,
4906 uint32_t changeFlags
)
4908 pmTracer
->tracePCIPowerChange(
4909 PMTraceWorker::kPowerChangeCompleted
,
4910 service
, changeFlags
,
4911 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
4914 //******************************************************************************
4917 // Override IOService::registerInterest() to intercept special clients.
4918 //******************************************************************************
4920 IONotifier
* IOPMrootDomain::registerInterest(
4921 const OSSymbol
* typeOfInterest
,
4922 IOServiceInterestHandler handler
,
4923 void * target
, void * ref
)
4925 IONotifier
* notifier
;
4926 bool isSystemCapabilityClient
;
4927 bool isKernelCapabilityClient
;
4929 isSystemCapabilityClient
=
4931 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
4933 isKernelCapabilityClient
=
4935 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
4937 if (isSystemCapabilityClient
)
4938 typeOfInterest
= gIOAppPowerStateInterest
;
4940 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
4941 if (notifier
&& pmPowerStateQueue
)
4943 if (isSystemCapabilityClient
)
4946 if (pmPowerStateQueue
->submitPowerEvent(
4947 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
4948 notifier
->release();
4951 if (isKernelCapabilityClient
)
4954 if (pmPowerStateQueue
->submitPowerEvent(
4955 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
4956 notifier
->release();
4963 //******************************************************************************
4964 // systemMessageFilter
4966 //******************************************************************************
4968 bool IOPMrootDomain::systemMessageFilter(
4969 void * object
, void * arg1
, void * arg2
, void * arg3
)
4971 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
4972 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
4973 bool isCapClient
= false;
4977 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
4978 (!isCapMsg
|| !_joinedCapabilityClients
||
4979 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
4982 // Capability change message for app and kernel clients.
4986 if ((context
->notifyType
== kNotifyPriority
) ||
4987 (context
->notifyType
== kNotifyCapabilityChangePriority
))
4990 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
4991 (object
== (void *) systemCapabilityNotifier
))
4997 IOPMSystemCapabilityChangeParameters
* capArgs
=
4998 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5000 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5002 capArgs
->fromCapabilities
= 0;
5003 capArgs
->toCapabilities
= _currentCapability
;
5004 capArgs
->changeFlags
= 0;
5008 capArgs
->fromCapabilities
= _currentCapability
;
5009 capArgs
->toCapabilities
= _pendingCapability
;
5011 if (context
->isPreChange
)
5012 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5014 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5017 // Capability change messages only go to the PM configd plugin.
5018 // Wait for response post-change if capabilitiy is increasing.
5019 // Wait for response pre-change if capability is decreasing.
5021 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5022 ( (capabilityLoss
&& context
->isPreChange
) ||
5023 (!capabilityLoss
&& !context
->isPreChange
) ) )
5025 // app has not replied yet, wait for it
5026 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5033 // Capability client will always see kIOMessageCanSystemSleep,
5034 // even for demand sleep.
5036 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5037 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5039 if (object
== (OSObject
*) systemCapabilityNotifier
)
5045 // Not idle sleep, don't ask apps.
5046 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5052 // Reject capability change messages for legacy clients.
5053 // Reject legacy system sleep messages for capability client.
5055 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5060 // Filter system sleep messages.
5062 if ((context
->notifyType
== kNotifyApps
) &&
5063 (_systemMessageClientMask
& kSystemMessageClientApp
))
5067 else if ((context
->notifyType
== kNotifyPriority
) &&
5068 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5075 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5077 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5078 if (_joinedCapabilityClients
->getCount() == 0)
5080 DLOG("destroyed capability client set %p\n",
5081 _joinedCapabilityClients
);
5082 _joinedCapabilityClients
->release();
5083 _joinedCapabilityClients
= 0;
5090 //******************************************************************************
5091 // setMaintenanceWakeCalendar
5093 //******************************************************************************
5095 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5096 const IOPMCalendarStruct
* calendar
)
5102 return kIOReturnBadArgument
;
5104 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5106 return kIOReturnNoMemory
;
5108 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5109 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5110 if (kIOReturnSuccess
== ret
)
5111 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5113 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5115 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5116 if (kIOReturnSuccess
== ret
)
5117 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5119 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5126 // MARK: Display Wrangler
5128 //******************************************************************************
5129 // displayWranglerNotification
5131 // Handle the notification when the IODisplayWrangler changes power state.
5132 //******************************************************************************
5134 IOReturn
IOPMrootDomain::displayWranglerNotification(
5135 void * target
, void * refCon
,
5136 UInt32 messageType
, IOService
* service
,
5137 void * messageArgument
, vm_size_t argSize
)
5140 int displayPowerState
;
5141 IOPowerStateChangeNotification
* params
=
5142 (IOPowerStateChangeNotification
*) messageArgument
;
5144 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5145 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5146 return kIOReturnUnsupported
;
5150 return kIOReturnUnsupported
;
5152 displayPowerState
= params
->stateNumber
;
5153 DLOG("DisplayWrangler message 0x%x, power state %d\n",
5154 (uint32_t) messageType
, displayPowerState
);
5156 switch (messageType
) {
5157 case kIOMessageDeviceWillPowerOff
:
5159 // Display wrangler has dropped power due to display idle
5160 // or force system sleep.
5165 // 1 Not visible to user
5166 // 0 Not visible to user
5168 if (displayPowerState
> 2)
5171 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5174 case kIOMessageDeviceHasPoweredOn
:
5176 // Display wrangler has powered on due to user activity
5177 // or wake from sleep.
5179 if ( 4 != displayPowerState
)
5182 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5186 return kIOReturnUnsupported
;
5189 //******************************************************************************
5190 // displayWranglerMatchPublished
5192 // Receives a notification when the IODisplayWrangler is published.
5193 // When it's published we install a power state change handler.
5194 //******************************************************************************
5196 bool IOPMrootDomain::displayWranglerMatchPublished(
5199 IOService
* newService
,
5200 IONotifier
* notifier __unused
)
5203 // found the display wrangler, now install a handler
5204 if( !newService
->registerInterest( gIOGeneralInterest
,
5205 &displayWranglerNotification
, target
, 0) )
5213 //******************************************************************************
5216 //******************************************************************************
5218 void IOPMrootDomain::reportUserInput( void )
5225 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
5228 wrangler
= (IOService
*) iter
->getNextObject();
5234 wrangler
->activityTickle(0,0);
5238 //******************************************************************************
5239 // blockDisplayWranglerTickle
5240 //******************************************************************************
5242 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
5247 // Not too late to prevent the display from lighting up
5248 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
5249 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5250 !checkSystemCanSustainFullWake())
5252 wranglerTickleLatched
= true;
5256 wranglerTickleLatched
= false;
5259 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
5261 wranglerTickleLatched
= false;
5263 pmPowerStateQueue
->submitPowerEvent(
5264 kPowerEventPolicyStimulus
,
5265 (void *) kStimulusDarkWakeActivityTickle
);
5268 return wranglerTickleLatched
;
5277 //******************************************************************************
5280 // Notification on battery class IOPowerSource appearance
5281 //******************************************************************************
5283 bool IOPMrootDomain::batteryPublished(
5286 IOService
* resourceService
,
5287 IONotifier
* notifier __unused
)
5289 // rdar://2936060&4435589
5290 // All laptops have dimmable LCD displays
5291 // All laptops have batteries
5292 // So if this machine has a battery, publish the fact that the backlight
5293 // supports dimming.
5294 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
5300 // MARK: System PM Policy
5302 //******************************************************************************
5303 // checkSystemCanSleep
5305 //******************************************************************************
5307 bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options
)
5311 // Conditions that prevent idle and demand system sleep.
5314 if (userDisabledAllSleep
)
5316 err
= 1; // 1. user-space sleep kill switch
5320 if (systemBooting
|| systemShutdown
)
5322 err
= 2; // 2. restart or shutdown in progress
5329 // Conditions above pegs the system at full wake.
5330 // Conditions below prevent system sleep but does not prevent
5331 // dark wake, and must be called from gated context.
5334 err
= 3; // 3. config does not support sleep
5338 if (lowBatteryCondition
)
5340 break; // always sleep on low battery
5343 if(darkWakeThermalEmergency
)
5345 break; // always sleep on dark wake thermal emergencies
5348 if (preventSystemSleepList
->getCount() != 0)
5350 err
= 4; // 4. child prevent system sleep clamp
5354 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
5355 kIOPMDriverAssertionLevelOn
)
5357 err
= 5; // 5. CPU assertion
5361 if (pciCantSleepValid
)
5363 if (pciCantSleepFlag
)
5364 err
= 6; // 6. PCI card does not support PM (cached)
5367 else if (sleepSupportedPEFunction
&&
5368 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5371 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
5372 ret
= getPlatform()->callPlatformFunction(
5373 sleepSupportedPEFunction
, false,
5374 NULL
, NULL
, NULL
, NULL
);
5375 pciCantSleepValid
= true;
5376 pciCantSleepFlag
= false;
5377 if ((platformSleepSupport
& kPCICantSleep
) ||
5378 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
5380 err
= 6; // 6. PCI card does not support PM
5381 pciCantSleepFlag
= true;
5390 DLOG("System sleep prevented by %d\n", err
);
5396 //******************************************************************************
5397 // checkSystemCanSustainFullWake
5398 //******************************************************************************
5400 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
5403 if (lowBatteryCondition
)
5405 // Low battery wake, or received a low battery notification
5406 // while system is awake.
5410 if (clamshellExists
&& clamshellClosed
&& !acAdaptorConnected
)
5412 // Lid closed on battery power
5419 //******************************************************************************
5422 // Conditions that affect our wake/sleep decision has changed.
5423 // If conditions dictate that the system must remain awake, clamp power
5424 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
5425 // is TRUE, then remove the power clamp and allow the power state to drop
5427 //******************************************************************************
5429 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
5431 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
5432 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
5436 if ((sleepSlider
== 0) || !checkSystemCanSleep())
5438 changePowerStateToPriv(ON_STATE
);
5440 else if ( sleepASAP
)
5442 changePowerStateToPriv(SLEEP_STATE
);
5446 //******************************************************************************
5447 // dispatchPowerEvent
5449 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
5450 //******************************************************************************
5452 void IOPMrootDomain::dispatchPowerEvent(
5453 uint32_t event
, void * arg0
, uint64_t arg1
)
5455 DLOG("power event %u args %p 0x%llx\n", event
, arg0
, arg1
);
5460 case kPowerEventFeatureChanged
:
5461 messageClients(kIOPMMessageFeatureChange
, this);
5464 case kPowerEventReceivedPowerNotification
:
5465 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
5468 case kPowerEventSystemBootCompleted
:
5471 systemBooting
= false;
5473 if (lowBatteryCondition
)
5475 privateSleepSystem (kIOPMSleepReasonLowPower
);
5477 // The rest is unnecessary since the system is expected
5478 // to sleep immediately. The following wake will update
5483 // If lid is closed, re-send lid closed notification
5484 // now that booting is complete.
5485 if ( clamshellClosed
)
5487 handlePowerNotification(kLocalEvalClamshellCommand
);
5489 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
5493 case kPowerEventSystemShutdown
:
5494 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
5496 /* We set systemShutdown = true during shutdown
5497 to prevent sleep at unexpected times while loginwindow is trying
5498 to shutdown apps and while the OS is trying to transition to
5501 Set to true during shutdown, as soon as loginwindow shows
5502 the "shutdown countdown dialog", through individual app
5503 termination, and through black screen kernel shutdown.
5505 systemShutdown
= true;
5508 A shutdown was initiated, but then the shutdown
5509 was cancelled, clearing systemShutdown to false here.
5511 systemShutdown
= false;
5515 case kPowerEventUserDisabledSleep
:
5516 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
5519 case kPowerEventRegisterSystemCapabilityClient
:
5520 if (systemCapabilityNotifier
)
5522 systemCapabilityNotifier
->release();
5523 systemCapabilityNotifier
= 0;
5527 systemCapabilityNotifier
= (IONotifier
*) arg0
;
5528 systemCapabilityNotifier
->retain();
5530 /* intentional fall-through */
5532 case kPowerEventRegisterKernelCapabilityClient
:
5533 if (!_joinedCapabilityClients
)
5534 _joinedCapabilityClients
= OSSet::withCapacity(8);
5537 IONotifier
* notify
= (IONotifier
*) arg0
;
5538 if (_joinedCapabilityClients
)
5540 _joinedCapabilityClients
->setObject(notify
);
5541 synchronizePowerTree( kIOPMSyncNoChildNotify
);
5547 case kPowerEventPolicyStimulus
:
5550 int stimulus
= (uintptr_t) arg0
;
5551 evaluatePolicy( stimulus
, (uint32_t) arg1
);
5555 case kPowerEventAssertionCreate
:
5557 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
5562 case kPowerEventAssertionRelease
:
5564 pmAssertions
->handleReleaseAssertion(arg1
);
5568 case kPowerEventAssertionSetLevel
:
5570 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
5574 case kPowerEventQueueSleepWakeUUID
:
5575 handleQueueSleepWakeUUID((OSObject
*)arg0
);
5577 case kPowerEventPublishSleepWakeUUID
:
5578 handlePublishSleepWakeUUID((bool)arg0
);
5580 case kPowerEventSuspendClient
:
5581 handleSuspendPMNotificationClient((uintptr_t)arg0
, (bool)arg1
);
5586 //******************************************************************************
5587 // systemPowerEventOccurred
5589 // The power controller is notifying us of a hardware-related power management
5590 // event that we must handle.
5592 // systemPowerEventOccurred covers the same functionality that
5593 // receivePowerNotification does; it simply provides a richer API for conveying
5594 // more information.
5595 //******************************************************************************
5597 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5598 const OSSymbol
*event
,
5601 IOReturn attempt
= kIOReturnSuccess
;
5602 OSNumber
*newNumber
= NULL
;
5605 return kIOReturnBadArgument
;
5607 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
5609 return kIOReturnInternalError
;
5611 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
5613 newNumber
->release();
5618 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5619 const OSSymbol
*event
,
5622 OSDictionary
*thermalsDict
= NULL
;
5623 bool shouldUpdate
= true;
5625 if (!event
|| !value
)
5626 return kIOReturnBadArgument
;
5629 // We reuse featuresDict Lock because it already exists and guards
5630 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5631 // of stepping on that lock.
5632 if (featuresDictLock
) IOLockLock(featuresDictLock
);
5634 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
5636 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
5637 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
5639 thermalsDict
= OSDictionary::withCapacity(1);
5642 if (!thermalsDict
) {
5643 shouldUpdate
= false;
5647 thermalsDict
->setObject (event
, value
);
5649 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
5651 thermalsDict
->release();
5655 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
5658 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
5660 return kIOReturnSuccess
;
5663 //******************************************************************************
5664 // receivePowerNotification
5666 // The power controller is notifying us of a hardware-related power management
5667 // event that we must handle. This may be a result of an 'environment' interrupt
5668 // from the power mgt micro.
5669 //******************************************************************************
5671 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
5673 pmPowerStateQueue
->submitPowerEvent(
5674 kPowerEventReceivedPowerNotification
, (void *) msg
);
5675 return kIOReturnSuccess
;
5678 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
5680 bool eval_clamshell
= false;
5685 * Local (IOPMrootDomain only) eval clamshell command
5687 if (msg
& kLocalEvalClamshellCommand
)
5689 eval_clamshell
= true;
5695 if (msg
& kIOPMOverTemp
)
5697 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
5698 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
5701 if (msg
& kIOPMDWOverTemp
)
5703 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU
) ||
5704 (_systemTransitionType
== kSystemTransitionSleep
) ||
5705 (_systemTransitionType
== kSystemTransitionWake
) ||
5706 (_systemTransitionType
== kSystemTransitionCapability
))
5708 // During early wake or when system capability is changing,
5709 // set flag and take action at end of transition.
5710 darkWakeThermalAlarm
= true;
5712 else if (!wranglerTickled
&& !darkWakeThermalEmergency
&&
5713 !CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
5715 // System in steady state and in dark wake
5716 darkWakeThermalEmergency
= true;
5717 privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
5718 MSG("DarkWake thermal limits breached. Going to sleep!\n");
5725 if (msg
& kIOPMSleepNow
)
5727 privateSleepSystem (kIOPMSleepReasonSoftware
);
5733 if (msg
& kIOPMPowerEmergency
)
5735 lowBatteryCondition
= true;
5736 privateSleepSystem (kIOPMSleepReasonLowPower
);
5742 if (msg
& kIOPMClamshellOpened
)
5744 // Received clamshel open message from clamshell controlling driver
5745 // Update our internal state and tell general interest clients
5746 clamshellClosed
= false;
5747 clamshellExists
= true;
5749 // Don't issue a hid tickle when lid is open and polled on wake
5750 if (msg
& kIOPMSetValue
)
5752 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
5757 informCPUStateChange(kInformLid
, 0);
5759 // Tell general interest clients
5760 sendClientClamshellNotification();
5762 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
5763 || (lastSleepReason
== kIOPMSleepReasonIdle
)
5764 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
5765 if (aborting
) userActivityCount
++;
5766 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
5771 * Send the clamshell interest notification since the lid is closing.
5773 if (msg
& kIOPMClamshellClosed
)
5775 // Received clamshel open message from clamshell controlling driver
5776 // Update our internal state and tell general interest clients
5777 clamshellClosed
= true;
5778 clamshellExists
= true;
5781 informCPUStateChange(kInformLid
, 1);
5783 // Tell general interest clients
5784 sendClientClamshellNotification();
5786 // And set eval_clamshell = so we can attempt
5787 eval_clamshell
= true;
5791 * Set Desktop mode (sent from graphics)
5793 * -> reevaluate lid state
5795 if (msg
& kIOPMSetDesktopMode
)
5797 desktopMode
= (0 != (msg
& kIOPMSetValue
));
5798 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
5800 sendClientClamshellNotification();
5802 // Re-evaluate the lid state
5803 if( clamshellClosed
)
5805 eval_clamshell
= true;
5810 * AC Adaptor connected
5812 * -> reevaluate lid state
5814 if (msg
& kIOPMSetACAdaptorConnected
)
5816 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
5817 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
5820 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
5822 // Tell BSD if AC is connected
5823 // 0 == external power source; 1 == on battery
5824 post_sys_powersource(acAdaptorConnected
? 0:1);
5826 sendClientClamshellNotification();
5828 // Re-evaluate the lid state
5829 if( clamshellClosed
)
5831 eval_clamshell
= true;
5834 // Lack of AC may have latched a display wrangler tickle.
5835 // This mirrors the hardware's USB wake event latch, where a latched
5836 // USB wake event followed by an AC attach will trigger a full wake.
5837 latchDisplayWranglerTickle( false );
5840 // AC presence will reset the standy timer delay adjustment.
5841 _standbyTimerResetSeconds
= 0;
5846 * Enable Clamshell (external display disappear)
5848 * -> reevaluate lid state
5850 if (msg
& kIOPMEnableClamshell
)
5852 // Re-evaluate the lid state
5853 // System should sleep on external display disappearance
5854 // in lid closed operation.
5855 if( clamshellClosed
&& (true == clamshellDisabled
) )
5857 eval_clamshell
= true;
5860 clamshellDisabled
= false;
5862 sendClientClamshellNotification();
5866 * Disable Clamshell (external display appeared)
5867 * We don't bother re-evaluating clamshell state. If the system is awake,
5868 * the lid is probably open.
5870 if (msg
& kIOPMDisableClamshell
)
5872 clamshellDisabled
= true;
5874 sendClientClamshellNotification();
5878 * Evaluate clamshell and SLEEP if appropiate
5880 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
5884 privateSleepSystem (kIOPMSleepReasonClamshell
);
5886 else if ( eval_clamshell
)
5888 evaluatePolicy( kStimulusDarkWakeEvaluate
);
5894 if (msg
& kIOPMPowerButton
)
5896 if (!wranglerAsleep
)
5898 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
5899 // Check that power button sleep is enabled
5901 if( kOSBooleanTrue
!= getProperty(pbs
))
5902 privateSleepSystem (kIOPMSleepReasonPowerButton
);
5910 //******************************************************************************
5913 // Evaluate root-domain policy in response to external changes.
5914 //******************************************************************************
5916 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
5920 int idleSleepEnabled
: 1;
5921 int idleSleepDisabled
: 1;
5922 int displaySleep
: 1;
5923 int sleepDelayChanged
: 1;
5924 int evaluateDarkWake
: 1;
5925 int adjustPowerState
: 1;
5930 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
5937 case kStimulusDisplayWranglerSleep
:
5938 if (!wranglerAsleep
)
5940 wranglerAsleep
= true;
5941 clock_get_uptime(&wranglerSleepTime
);
5942 flags
.bit
.displaySleep
= true;
5946 case kStimulusDisplayWranglerWake
:
5947 wranglerAsleep
= false;
5948 flags
.bit
.idleSleepDisabled
= true;
5951 case kStimulusAggressivenessChanged
:
5953 unsigned long minutesToIdleSleep
= 0;
5954 unsigned long minutesToDisplayDim
= 0;
5955 unsigned long minutesDelta
= 0;
5957 // Fetch latest display and system sleep slider values.
5958 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
5959 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
5960 DLOG("aggressiveness changed: system %u->%u, display %u\n",
5961 (uint32_t) sleepSlider
,
5962 (uint32_t) minutesToIdleSleep
,
5963 (uint32_t) minutesToDisplayDim
);
5965 DLOG("idle time -> %ld secs (ena %d)\n",
5966 idleSeconds
, (minutesToIdleSleep
!= 0));
5968 if (0x7fffffff == minutesToIdleSleep
)
5969 minutesToIdleSleep
= idleSeconds
;
5971 // How long to wait before sleeping the system once
5972 // the displays turns off is indicated by 'extraSleepDelay'.
5974 if ( minutesToIdleSleep
> minutesToDisplayDim
)
5975 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
5976 else if( minutesToIdleSleep
== minutesToDisplayDim
)
5979 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
5980 flags
.bit
.idleSleepEnabled
= true;
5982 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
5983 flags
.bit
.idleSleepDisabled
= true;
5985 if ((minutesDelta
!= extraSleepDelay
) &&
5986 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
5987 flags
.bit
.sleepDelayChanged
= true;
5989 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
5990 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
5992 // Reconsider decision to remain in dark wake
5993 flags
.bit
.evaluateDarkWake
= true;
5996 sleepSlider
= minutesToIdleSleep
;
5997 extraSleepDelay
= minutesDelta
;
6000 case kStimulusDemandSystemSleep
:
6001 changePowerStateWithOverrideTo( SLEEP_STATE
);
6004 case kStimulusAllowSystemSleepChanged
:
6005 flags
.bit
.adjustPowerState
= true;
6008 case kStimulusDarkWakeActivityTickle
:
6009 if (false == wranglerTickled
)
6011 uint32_t options
= 0;
6012 IOService
* pciRoot
= 0;
6014 if (rejectWranglerTickle
)
6016 DLOG("rejected tickle, type %u capability %x:%x\n",
6017 _systemTransitionType
,
6018 _currentCapability
, _pendingCapability
);
6022 if (latchDisplayWranglerTickle(true))
6024 DLOG("latched tickle\n");
6028 _desiredCapability
|=
6029 (kIOPMSystemCapabilityGraphics
|
6030 kIOPMSystemCapabilityAudio
);
6032 if ((kSystemTransitionWake
== _systemTransitionType
) &&
6033 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6034 !graphicsSuppressed
)
6036 DLOG("Promoting to full wake\n");
6038 // Elevate to full wake while waking up to dark wake.
6039 // PM will hold off notifying the graphics subsystem about
6040 // system wake as late as possible, so if a HID event does
6041 // arrive, we can turn on graphics on this wake cycle, and
6042 // not have to wait till the following cycle. That latency
6043 // can be huge on some systems. However, once any graphics
6044 // suppression has taken effect, it is too late. All other
6045 // graphics devices must be similarly suppressed. But the
6046 // delay till the following cycle should be very short.
6048 _pendingCapability
|=
6049 (kIOPMSystemCapabilityGraphics
|
6050 kIOPMSystemCapabilityAudio
);
6052 // Immediately bring up audio and graphics.
6053 pciRoot
= pciHostBridgeDriver
;
6055 // Notify clients about full wake.
6056 _systemMessageClientMask
= kSystemMessageClientAll
;
6057 tellClients(kIOMessageSystemWillPowerOn
);
6060 // Unsafe to cancel once graphics was powered.
6061 // If system woke from dark wake, the return to sleep can
6062 // be cancelled. But "awake -> dark -> sleep" transition
6063 // cannot be cancelled.
6065 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
6066 options
|= kIOPMSyncCancelPowerDown
;
6069 synchronizePowerTree( options
, pciRoot
);
6070 wranglerTickled
= true;
6071 // IOGraphics doesn't lit the display even though graphics
6072 // is enanbled in kIOMessageSystemCapabilityChange message(radar 9502104)
6073 // So, do an explicit activity tickle
6075 wrangler
->activityTickle(0,0);
6077 if (logWranglerTickle
)
6082 clock_get_uptime(&now
);
6083 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
6084 absolutetime_to_nanoseconds(now
, &nsec
);
6085 MSG("HID tickle %u ms\n",
6086 ((int)((nsec
) / 1000000ULL)));
6087 logWranglerTickle
= false;
6092 case kStimulusDarkWakeEntry
:
6093 case kStimulusDarkWakeReentry
:
6094 // Any system transitions since the last dark wake transition
6095 // will invalid the stimulus.
6097 if (arg
== _systemStateGeneration
)
6099 DLOG("dark wake entry\n");
6100 systemDarkWake
= true;
6101 wranglerAsleep
= true;
6102 clock_get_uptime(&wranglerSleepTime
);
6104 // Always accelerate disk spindown while in dark wake,
6105 // even if system does not support/allow sleep.
6107 cancelIdleSleepTimer();
6108 setQuickSpinDownTimeout();
6109 flags
.bit
.evaluateDarkWake
= true;
6113 case kStimulusDarkWakeEvaluate
:
6116 flags
.bit
.evaluateDarkWake
= true;
6118 #if !DARK_TO_FULL_EVALUATE_CLAMSHELL
6121 // Not through kLocalEvalClamshellCommand to avoid loop.
6122 if (clamshellClosed
&& shouldSleepOnClamshellClosed() &&
6123 checkSystemCanSleep(true))
6125 privateSleepSystem( kIOPMSleepReasonClamshell
);
6131 case kStimulusNoIdleSleepPreventers
:
6132 flags
.bit
.adjustPowerState
= true;
6135 } /* switch(stimulus) */
6137 if (flags
.bit
.evaluateDarkWake
&& !wranglerTickled
)
6139 if (darkWakeToSleepASAP
||
6140 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
6142 // System currently in dark wake, and no children and
6143 // assertion prevent system sleep.
6145 if (checkSystemCanSleep(true))
6147 if (lowBatteryCondition
)
6149 lastSleepReason
= kIOPMSleepReasonLowPower
;
6150 setProperty(kRootDomainSleepReasonKey
, kIOPMLowPowerSleepKey
);
6152 else if (darkWakeMaintenance
)
6154 lastSleepReason
= kIOPMSleepReasonMaintenance
;
6155 setProperty(kRootDomainSleepReasonKey
, kIOPMMaintenanceSleepKey
);
6157 else if (darkWakeSleepService
)
6159 lastSleepReason
= kIOPMSleepReasonSleepServiceExit
;
6160 setProperty(kRootDomainSleepReasonKey
, kIOPMSleepServiceExitKey
);
6162 changePowerStateWithOverrideTo( SLEEP_STATE
);
6166 // Parked in dark wake, a tickle will return to full wake
6167 rejectWranglerTickle
= false;
6170 else // non-maintenance (network) dark wake
6172 if (checkSystemCanSleep(true))
6174 // Release power clamp, and wait for children idle.
6175 adjustPowerState(true);
6179 changePowerStateToPriv(ON_STATE
);
6181 rejectWranglerTickle
= false;
6187 // The rest are irrelevant while system is in dark wake.
6191 if (flags
.bit
.displaySleep
|| flags
.bit
.sleepDelayChanged
)
6193 bool cancelQuickSpindown
= false;
6195 if (flags
.bit
.sleepDelayChanged
)
6197 DLOG("extra sleep timer changed\n");
6198 cancelIdleSleepTimer();
6199 cancelQuickSpindown
= true;
6203 DLOG("display sleep\n");
6206 if (wranglerAsleep
&& !wranglerSleepIgnored
)
6208 if ( extraSleepDelay
)
6210 // Start a timer here if the System Sleep timer is greater
6211 // than the Display Sleep timer.
6213 startIdleSleepTimer(gRootDomain
->extraSleepDelay
* 60);
6215 else if ( sleepSlider
)
6217 // Accelerate disk spindown if system sleep and display sleep
6218 // sliders are set to the same value (e.g. both set to 5 min),
6219 // and display is about to go dark. Check the system sleep is
6220 // not set to never sleep. Disk sleep setting is ignored.
6222 setQuickSpinDownTimeout();
6223 cancelQuickSpindown
= false;
6227 if (cancelQuickSpindown
)
6228 restoreUserSpinDownTimeout();
6231 if (flags
.bit
.idleSleepEnabled
)
6233 DLOG("idle sleep timer enabled\n");
6236 changePowerStateToPriv(ON_STATE
);
6239 startIdleSleepTimer( idleSeconds
);
6244 // Start idle sleep timer if wrangler went to sleep
6245 // while system sleep was disabled. Disk spindown is
6246 // accelerated upon timer expiration.
6252 uint32_t minutesSinceDisplaySleep
= 0;
6253 uint32_t sleepDelay
= 0;
6255 clock_get_uptime(&now
);
6256 if (CMP_ABSOLUTETIME(&now
, &wranglerSleepTime
) > 0)
6258 SUB_ABSOLUTETIME(&now
, &wranglerSleepTime
);
6259 absolutetime_to_nanoseconds(now
, &nanos
);
6260 minutesSinceDisplaySleep
= nanos
/ (60000000000ULL);
6263 if (extraSleepDelay
> minutesSinceDisplaySleep
)
6265 sleepDelay
= extraSleepDelay
- minutesSinceDisplaySleep
;
6268 startIdleSleepTimer(sleepDelay
* 60);
6269 DLOG("display slept %u min, set idle timer to %u min\n",
6270 minutesSinceDisplaySleep
, sleepDelay
);
6275 if (flags
.bit
.idleSleepDisabled
)
6277 DLOG("idle sleep timer disabled\n");
6278 cancelIdleSleepTimer();
6279 restoreUserSpinDownTimeout();
6283 if (flags
.bit
.adjustPowerState
)
6285 bool sleepASAP
= false;
6287 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
6291 changePowerStateToPriv(ON_STATE
);
6294 // stay awake for at least idleSeconds
6295 startIdleSleepTimer(idleSeconds
);
6298 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
6305 lastSleepReason
= kIOPMSleepReasonIdle
;
6306 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
6309 adjustPowerState(sleepASAP
);
6313 //******************************************************************************
6314 // evaluateAssertions
6316 //******************************************************************************
6317 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
6319 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
6321 messageClients(kIOPMMessageDriverAssertionsChanged
);
6323 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
6326 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
6328 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
6329 wrangler
->setIgnoreIdleTimer( value
);
6333 if (changedBits
& kIOPMDriverAssertionCPUBit
)
6334 evaluatePolicy(kStimulusDarkWakeEvaluate
);
6336 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
6337 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
6339 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
6340 updatePreventIdleSleepList(this, true);
6343 DLOG("Driver assertion ReservedBit7 dropped\n");
6344 updatePreventIdleSleepList(this, false);
6353 //******************************************************************************
6356 //******************************************************************************
6358 void IOPMrootDomain::pmStatsRecordEvent(
6360 AbsoluteTime timestamp
)
6362 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
6363 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
6366 OSData
*publishPMStats
= NULL
;
6368 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
6370 absolutetime_to_nanoseconds(timestamp
, &nsec
);
6372 switch (eventIndex
) {
6373 case kIOPMStatsHibernateImageWrite
:
6375 gPMStats
.hibWrite
.start
= nsec
;
6377 gPMStats
.hibWrite
.stop
= nsec
;
6380 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
6381 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
6384 case kIOPMStatsHibernateImageRead
:
6386 gPMStats
.hibRead
.start
= nsec
;
6388 gPMStats
.hibRead
.stop
= nsec
;
6391 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
6392 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
6394 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
6395 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
6396 publishPMStats
->release();
6397 bzero(&gPMStats
, sizeof(gPMStats
));
6404 * Appends a record of the application response to
6405 * IOPMrootDomain::pmStatsAppResponses
6407 void IOPMrootDomain::pmStatsRecordApplicationResponse(
6408 const OSSymbol
*response
,
6414 OSDictionary
*responseDescription
= NULL
;
6415 OSNumber
*delayNum
= NULL
;
6416 OSNumber
*pidNum
= NULL
;
6417 OSNumber
*msgNum
= NULL
;
6418 const OSSymbol
*appname
;
6419 const OSSymbol
*entryName
;
6420 OSObject
*entryType
;
6423 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
6427 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
6429 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
6430 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
6431 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
))
6433 OSNumber
* entryValue
;
6434 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
6435 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
6436 entryValue
->setValue(delay_ms
);
6441 responseDescription
= OSDictionary::withCapacity(5);
6442 if (responseDescription
)
6445 responseDescription
->setObject(_statsResponseTypeKey
, response
);
6448 if (messageType
!= 0) {
6449 msgNum
= OSNumber::withNumber(messageType
, 32);
6451 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
6456 if (name
&& (strlen(name
) > 0))
6458 appname
= OSSymbol::withCString(name
);
6460 responseDescription
->setObject(_statsNameKey
, appname
);
6465 if (app_pid
!= -1) {
6466 pidNum
= OSNumber::withNumber(app_pid
, 32);
6468 responseDescription
->setObject(_statsPIDKey
, pidNum
);
6473 delayNum
= OSNumber::withNumber(delay_ms
, 32);
6475 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
6476 delayNum
->release();
6479 if (pmStatsAppResponses
) {
6480 pmStatsAppResponses
->setObject(responseDescription
);
6483 responseDescription
->release();
6489 // MARK: PMTraceWorker
6491 //******************************************************************************
6492 // TracePoint support
6494 //******************************************************************************
6496 #define kIOPMRegisterNVRAMTracePointHandlerKey \
6497 "IOPMRegisterNVRAMTracePointHandler"
6499 IOReturn
IOPMrootDomain::callPlatformFunction(
6500 const OSSymbol
* functionName
,
6501 bool waitForFunction
,
6502 void * param1
, void * param2
,
6503 void * param3
, void * param4
)
6505 if (pmTracer
&& functionName
&&
6506 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
6507 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
6509 uint32_t tracePointPhases
, tracePointPCI
;
6510 uint64_t statusCode
;
6512 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
6513 pmTracer
->tracePointTarget
= (void *) param2
;
6514 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
6515 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
6516 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
6517 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
6519 MSG("Sleep failure code 0x%08x 0x%08x\n",
6520 tracePointPCI
, tracePointPhases
);
6522 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
6523 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
6525 return kIOReturnSuccess
;
6528 else if (functionName
&&
6529 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
6531 if (gSleepPolicyHandler
)
6532 return kIOReturnExclusiveAccess
;
6534 return kIOReturnBadArgument
;
6535 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
6536 gSleepPolicyTarget
= (void *) param2
;
6537 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
6538 return kIOReturnSuccess
;
6542 return super::callPlatformFunction(
6543 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
6546 void IOPMrootDomain::tracePoint( uint8_t point
)
6548 if (systemBooting
) return;
6550 pmTracer
->tracePoint(point
);
6553 if (kIOPMTracePointSleepPowerPlaneDrivers
== point
) IOHibernateIOKitSleep();
6557 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
6560 pmTracer
->tracePoint(point
, data
);
6563 void IOPMrootDomain::traceDetail( uint32_t detail
)
6566 pmTracer
->traceDetail( detail
);
6569 //******************************************************************************
6570 // PMTraceWorker Class
6572 //******************************************************************************
6575 #define super OSObject
6576 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
6578 #define kPMBestGuessPCIDevicesCount 25
6579 #define kPMMaxRTCBitfieldSize 32
6581 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
6585 me
= OSTypeAlloc( PMTraceWorker
);
6586 if (!me
|| !me
->init())
6591 DLOG("PMTraceWorker %p\n", me
);
6593 // Note that we cannot instantiate the PCI device -> bit mappings here, since
6594 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
6595 // this dictionary lazily.
6597 me
->pciDeviceBitMappings
= NULL
;
6598 me
->pciMappingLock
= IOLockAlloc();
6599 me
->tracePhase
= kIOPMTracePointSystemUp
;
6600 me
->loginWindowPhase
= 0;
6601 me
->traceData32
= 0;
6605 void PMTraceWorker::RTC_TRACE(void)
6607 if (tracePointHandler
&& tracePointTarget
)
6611 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
6614 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
6615 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
6619 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
6621 const OSSymbol
* deviceName
;
6624 IOLockLock(pciMappingLock
);
6626 if (!pciDeviceBitMappings
)
6628 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
6629 if (!pciDeviceBitMappings
)
6633 // Check for bitmask overflow.
6634 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
6637 if ((deviceName
= pciDevice
->copyName()) &&
6638 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
6639 pciDeviceBitMappings
->setObject(deviceName
))
6641 index
= pciDeviceBitMappings
->getCount() - 1;
6642 _LOG("PMTrace PCI array: set object %s => %d\n",
6643 deviceName
->getCStringNoCopy(), index
);
6646 deviceName
->release();
6647 if (!addedToRegistry
&& (index
>= 0))
6648 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
6651 IOLockUnlock(pciMappingLock
);
6655 bool PMTraceWorker::serialize(OSSerialize
*s
) const
6658 if (pciDeviceBitMappings
)
6660 IOLockLock(pciMappingLock
);
6661 ok
= pciDeviceBitMappings
->serialize(s
);
6662 IOLockUnlock(pciMappingLock
);
6667 void PMTraceWorker::tracePoint(uint8_t phase
)
6669 // clear trace detail when phase begins
6670 if (tracePhase
!= phase
)
6675 DLOG("trace point 0x%02x\n", tracePhase
);
6679 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
6681 // clear trace detail when phase begins
6682 if (tracePhase
!= phase
)
6688 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
6692 void PMTraceWorker::traceDetail(uint32_t detail
)
6694 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
6697 traceData32
= detail
;
6698 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
6703 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
6705 loginWindowPhase
= phase
;
6707 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
6711 void PMTraceWorker::tracePCIPowerChange(
6712 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
6715 uint32_t expectedFlag
;
6717 // Ignore PCI changes outside of system sleep/wake.
6718 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
6719 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
6722 // Only record the WillChange transition when going to sleep,
6723 // and the DidChange on the way up.
6724 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
6725 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
6726 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
6727 if (changeFlags
!= expectedFlag
)
6730 // Mark this device off in our bitfield
6731 if (bitNum
< kPMMaxRTCBitfieldSize
)
6733 bitMask
= (1 << bitNum
);
6735 if (kPowerChangeStart
== type
)
6737 traceData32
|= bitMask
;
6738 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
6739 service
->getName(), bitNum
, bitMask
, traceData32
);
6743 traceData32
&= ~bitMask
;
6744 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
6745 service
->getName(), bitNum
, bitMask
, traceData32
);
6753 // MARK: PMHaltWorker
6755 //******************************************************************************
6756 // PMHaltWorker Class
6758 //******************************************************************************
6760 static unsigned int gPMHaltBusyCount
;
6761 static unsigned int gPMHaltIdleCount
;
6762 static int gPMHaltDepth
;
6763 static unsigned long gPMHaltEvent
;
6764 static IOLock
* gPMHaltLock
= 0;
6765 static OSArray
* gPMHaltArray
= 0;
6766 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
6768 PMHaltWorker
* PMHaltWorker::worker( void )
6774 me
= OSTypeAlloc( PMHaltWorker
);
6775 if (!me
|| !me
->init())
6778 me
->lock
= IOLockAlloc();
6782 DLOG("PMHaltWorker %p\n", me
);
6783 me
->retain(); // thread holds extra retain
6784 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
6789 thread_deallocate(thread
);
6794 if (me
) me
->release();
6798 void PMHaltWorker::free( void )
6800 DLOG("PMHaltWorker free %p\n", this);
6806 return OSObject::free();
6809 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
6811 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
6813 IOLockLock( gPMHaltLock
);
6815 me
->depth
= gPMHaltDepth
;
6816 IOLockUnlock( gPMHaltLock
);
6818 while (me
->depth
>= 0)
6820 PMHaltWorker::work( me
);
6822 IOLockLock( gPMHaltLock
);
6823 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
6825 // This is the last thread to finish work on this level,
6826 // inform everyone to start working on next lower level.
6828 me
->depth
= gPMHaltDepth
;
6829 gPMHaltIdleCount
= 0;
6830 thread_wakeup((event_t
) &gPMHaltIdleCount
);
6834 // One or more threads are still working on this level,
6835 // this thread must wait.
6836 me
->depth
= gPMHaltDepth
- 1;
6838 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
6839 } while (me
->depth
!= gPMHaltDepth
);
6841 IOLockUnlock( gPMHaltLock
);
6844 // No more work to do, terminate thread
6845 DLOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
6846 thread_wakeup( &gPMHaltDepth
);
6850 void PMHaltWorker::work( PMHaltWorker
* me
)
6852 IOService
* service
;
6854 AbsoluteTime startTime
;
6863 // Claim an unit of work from the shared pool
6864 IOLockLock( gPMHaltLock
);
6865 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
6868 service
= (IOService
*)inner
->getAnyObject();
6872 inner
->removeObject(service
);
6875 IOLockUnlock( gPMHaltLock
);
6877 break; // no more work at this depth
6879 clock_get_uptime(&startTime
);
6881 if (!service
->isInactive() &&
6882 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
6884 IOLockLock(me
->lock
);
6885 me
->startTime
= startTime
;
6886 me
->service
= service
;
6887 me
->timeout
= false;
6888 IOLockUnlock(me
->lock
);
6890 service
->systemWillShutdown( gPMHaltEvent
);
6892 // Wait for driver acknowledgement
6893 IOLockLock(me
->lock
);
6894 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
6896 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
6899 timeout
= me
->timeout
;
6900 IOLockUnlock(me
->lock
);
6903 deltaTime
= computeDeltaTimeMS(&startTime
);
6904 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
6905 (gIOKitDebug
& kIOLogPMRootDomain
))
6907 LOG("%s driver %s (%p) took %u ms\n",
6908 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
6909 "PowerOff" : "Restart",
6910 service
->getName(), service
,
6911 (uint32_t) deltaTime
);
6919 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
6922 AbsoluteTime startTime
;
6923 AbsoluteTime endTime
;
6927 IOLockLock(me
->lock
);
6928 if (me
->service
&& !me
->timeout
)
6930 startTime
= me
->startTime
;
6932 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
6934 SUB_ABSOLUTETIME(&endTime
, &startTime
);
6935 absolutetime_to_nanoseconds(endTime
, &nano
);
6937 if (nano
> 3000000000ULL)
6940 MSG("%s still waiting on %s\n",
6941 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
6942 "PowerOff" : "Restart",
6943 me
->service
->getName());
6946 IOLockUnlock(me
->lock
);
6950 //******************************************************************************
6951 // acknowledgeSystemWillShutdown
6953 // Acknowledgement from drivers that they have prepared for shutdown/restart.
6954 //******************************************************************************
6956 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
6958 PMHaltWorker
* worker
;
6964 //DLOG("%s acknowledged\n", from->getName());
6965 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
6968 worker
= (PMHaltWorker
*) prop
;
6969 IOLockLock(worker
->lock
);
6970 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
6971 thread_wakeup((event_t
) worker
);
6972 IOLockUnlock(worker
->lock
);
6977 DLOG("%s acknowledged without worker property\n",
6983 //******************************************************************************
6984 // notifySystemShutdown
6986 // Notify all objects in PM tree that system will shutdown or restart
6987 //******************************************************************************
6990 notifySystemShutdown( IOService
* root
, unsigned long event
)
6992 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
6993 IORegistryIterator
* iter
;
6994 IORegistryEntry
* entry
;
6997 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
6998 AbsoluteTime deadline
;
6999 unsigned int totalNodes
= 0;
7001 unsigned int rootDepth
;
7002 unsigned int numWorkers
;
7008 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
7010 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
7012 // Iterate the entire PM tree starting from root
7014 rootDepth
= root
->getDepth( gIOPowerPlane
);
7015 if (!rootDepth
) goto done
;
7017 // debug - for repeated test runs
7018 while (PMHaltWorker::metaClass
->getInstanceCount())
7023 gPMHaltArray
= OSArray::withCapacity(40);
7024 if (!gPMHaltArray
) goto done
;
7027 gPMHaltArray
->flushCollection();
7031 gPMHaltLock
= IOLockAlloc();
7032 if (!gPMHaltLock
) goto done
;
7035 if (!gPMHaltClientAcknowledgeKey
)
7037 gPMHaltClientAcknowledgeKey
=
7038 OSSymbol::withCStringNoCopy("PMShutdown");
7039 if (!gPMHaltClientAcknowledgeKey
) goto done
;
7042 gPMHaltEvent
= event
;
7044 // Depth-first walk of PM plane
7046 iter
= IORegistryIterator::iterateOver(
7047 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
7051 while ((entry
= iter
->getNextObject()))
7053 node
= OSDynamicCast(IOService
, entry
);
7058 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
7061 depth
= node
->getDepth( gIOPowerPlane
);
7062 if (depth
<= rootDepth
)
7067 // adjust to zero based depth
7068 depth
-= (rootDepth
+ 1);
7070 // gPMHaltArray is an array of containers, each container
7071 // refers to nodes with the same depth.
7073 count
= gPMHaltArray
->getCount();
7074 while (depth
>= count
)
7076 // expand array and insert placeholders
7077 gPMHaltArray
->setObject(PLACEHOLDER
);
7080 count
= gPMHaltArray
->getCount();
7083 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
7084 if (inner
== PLACEHOLDER
)
7086 inner
= OSSet::withCapacity(40);
7089 gPMHaltArray
->replaceObject(depth
, inner
);
7094 // PM nodes that appear more than once in the tree will have
7095 // the same depth, OSSet will refuse to add the node twice.
7097 ok
= inner
->setObject(node
);
7100 DLOG("Skipped PM node %s\n", node
->getName());
7106 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
7109 if (inner
!= PLACEHOLDER
)
7110 count
= inner
->getCount();
7111 DLOG("Nodes at depth %u = %u\n", i
, count
);
7114 // strip placeholders (not all depths are populated)
7116 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
7118 if (inner
== PLACEHOLDER
)
7120 gPMHaltArray
->removeObject(i
);
7123 count
= inner
->getCount();
7124 if (count
> numWorkers
)
7126 totalNodes
+= count
;
7130 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
7133 gPMHaltBusyCount
= 0;
7134 gPMHaltIdleCount
= 0;
7135 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
7137 // Create multiple workers (and threads)
7139 if (numWorkers
> kPMHaltMaxWorkers
)
7140 numWorkers
= kPMHaltMaxWorkers
;
7142 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
7143 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
7145 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7146 workers
[i
] = PMHaltWorker::worker();
7148 // Wait for workers to exhaust all available work
7150 IOLockLock(gPMHaltLock
);
7151 while (gPMHaltDepth
>= 0)
7153 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
7155 waitResult
= IOLockSleepDeadline(
7156 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
7157 if (THREAD_TIMED_OUT
== waitResult
)
7160 clock_get_uptime(&now
);
7162 IOLockUnlock(gPMHaltLock
);
7163 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
7166 PMHaltWorker::checkTimeout(workers
[i
], &now
);
7168 IOLockLock(gPMHaltLock
);
7171 IOLockUnlock(gPMHaltLock
);
7173 // Release all workers
7175 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7178 workers
[i
]->release();
7179 // worker also retained by it's own thread
7183 DLOG("%s done\n", __FUNCTION__
);
7187 //*********************************************************************************
7188 // Sleep/Wake logging
7190 //*********************************************************************************
7192 IOMemoryDescriptor
*IOPMrootDomain::getPMTraceMemoryDescriptor(void)
7195 return timeline
->getPMTraceMemoryDescriptor();
7200 // Forwards external reports of detailed events to IOPMTimeline
7201 IOReturn
IOPMrootDomain::recordPMEvent(PMEventDetails
*details
)
7203 if (timeline
&& details
) {
7207 // Record a detailed driver power change event, or...
7208 if(details
->eventClassifier
== kIOPMEventClassDriverEvent
) {
7209 rc
= timeline
->recordDetailedPowerEvent( details
);
7212 // Record a system power management event
7213 else if(details
->eventClassifier
== kIOPMEventClassSystemEvent
) {
7214 rc
= timeline
->recordSystemPowerEvent( details
);
7217 return kIOReturnBadArgument
;
7220 // If we get to record this message, then we've reached the
7221 // end of another successful Sleep --> Wake cycle
7222 // At this point, we pat ourselves in the back and allow
7223 // our Sleep --> Wake UUID to be published
7224 if(details
->eventType
== kIOPMEventTypeWakeDone
) {
7225 timeline
->setSleepCycleInProgressFlag(false);
7229 // Check if its time to clear the timeline buffer
7230 if(getProperty(kIOPMSleepWakeUUIDKey)
7231 && timeline->isSleepCycleInProgress() == false
7232 && timeline->getNumEventsLoggedThisPeriod() > 500) {
7234 // Clear the old UUID
7235 if(pmPowerStateQueue) {
7236 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
7243 return kIOReturnNotReady
;
7246 IOReturn
IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails
*details
)
7248 IOReturn ret
= kIOReturnBadArgument
;
7252 ret
= recordPMEvent(details
);
7259 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7261 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
7262 IOPMDriverAssertionType whichAssertionBits
,
7263 IOPMDriverAssertionLevel assertionLevel
,
7264 IOService
*ownerService
,
7265 const char *ownerDescription
)
7268 IOPMDriverAssertionID newAssertion
;
7273 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
7275 if (kIOReturnSuccess
== ret
)
7276 return newAssertion
;
7281 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
7284 return kIOReturnInternalError
;
7286 return pmAssertions
->releaseAssertion(releaseAssertion
);
7289 IOReturn
IOPMrootDomain::setPMAssertionLevel(
7290 IOPMDriverAssertionID assertionID
,
7291 IOPMDriverAssertionLevel assertionLevel
)
7293 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
7296 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
7298 IOPMDriverAssertionType sysLevels
;
7300 if (!pmAssertions
|| whichAssertion
== 0)
7301 return kIOPMDriverAssertionLevelOff
;
7303 sysLevels
= pmAssertions
->getActivatedAssertions();
7305 // Check that every bit set in argument 'whichAssertion' is asserted
7306 // in the aggregate bits.
7307 if ((sysLevels
& whichAssertion
) == whichAssertion
)
7308 return kIOPMDriverAssertionLevelOn
;
7310 return kIOPMDriverAssertionLevelOff
;
7313 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
7316 return kIOReturnNotFound
;
7318 return pmAssertions
->setUserAssertionLevels(inLevels
);
7321 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
7325 pmAssertions
->publishProperties();
7327 return( IOService::serializeProperties(s
) );
7330 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7333 // MARK: PMSettingHandle
7335 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
7337 void PMSettingHandle::free( void )
7341 pmso
->clientHandleFreed();
7350 // MARK: PMSettingObject
7353 #define super OSObject
7354 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
7357 * Static constructor/initializer for PMSettingObject
7359 PMSettingObject
*PMSettingObject::pmSettingObject(
7360 IOPMrootDomain
*parent_arg
,
7361 IOPMSettingControllerCallback handler_arg
,
7362 OSObject
*target_arg
,
7363 uintptr_t refcon_arg
,
7364 uint32_t supportedPowerSources
,
7365 const OSSymbol
* settings
[],
7366 OSObject
**handle_obj
)
7368 uint32_t settingCount
= 0;
7369 PMSettingObject
*pmso
= 0;
7370 PMSettingHandle
*pmsh
= 0;
7372 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
7375 // count OSSymbol entries in NULL terminated settings array
7376 while (settings
[settingCount
]) {
7379 if (0 == settingCount
)
7382 pmso
= new PMSettingObject
;
7383 if (!pmso
|| !pmso
->init())
7386 pmsh
= new PMSettingHandle
;
7387 if (!pmsh
|| !pmsh
->init())
7390 queue_init(&pmso
->calloutQueue
);
7391 pmso
->parent
= parent_arg
;
7392 pmso
->func
= handler_arg
;
7393 pmso
->target
= target_arg
;
7394 pmso
->refcon
= refcon_arg
;
7395 pmso
->settingCount
= settingCount
;
7397 pmso
->retain(); // handle holds a retain on pmso
7401 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
7402 if (pmso
->publishedFeatureID
) {
7403 for (unsigned int i
=0; i
<settingCount
; i
++) {
7404 // Since there is now at least one listener to this setting, publish
7405 // PM root domain support for it.
7406 parent_arg
->publishPMSetting( settings
[i
],
7407 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
7415 if (pmso
) pmso
->release();
7416 if (pmsh
) pmsh
->release();
7420 void PMSettingObject::free( void )
7422 if (publishedFeatureID
) {
7423 for (uint32_t i
=0; i
<settingCount
; i
++) {
7424 if (publishedFeatureID
[i
]) {
7425 parent
->removePublishedFeature( publishedFeatureID
[i
] );
7429 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
7435 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
7437 (*func
)(target
, type
, object
, refcon
);
7440 void PMSettingObject::clientHandleFreed( void )
7442 parent
->deregisterPMSettingObject(this);
7446 // MARK: IOPMTimeline
7449 #define super OSObject
7451 //*********************************************************************************
7452 //*********************************************************************************
7453 //*********************************************************************************
7455 IOPMTimeline
*IOPMTimeline::timeline(IOPMrootDomain
*root_domain
)
7457 IOPMTimeline
*myself
;
7462 myself
= new IOPMTimeline
;
7465 myself
->owner
= root_domain
;
7472 bool IOPMTimeline::init(void)
7474 if (!super::init()) {
7478 logLock
= IOLockAlloc();
7480 // Fresh timeline, no events logged yet
7481 this->numEventsLoggedThisPeriod
= 0;
7482 this->sleepCycleInProgress
= false;
7484 //this->setEventsRecordingLevel(1); // TODO
7485 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked
);
7490 void IOPMTimeline::free(void)
7492 if (pmTraceMemoryDescriptor
) {
7493 pmTraceMemoryDescriptor
->release();
7494 pmTraceMemoryDescriptor
= NULL
;
7497 IOLockFree(logLock
);
7502 IOMemoryDescriptor
*IOPMTimeline::getPMTraceMemoryDescriptor()
7504 return pmTraceMemoryDescriptor
;
7507 //*********************************************************************************
7508 //*********************************************************************************
7509 //*********************************************************************************
7511 bool IOPMTimeline::setProperties(OSDictionary
*d
)
7514 OSBoolean
*b
= NULL
;
7515 bool changed
= false;
7517 /* Changes size of detailed events buffer */
7518 n
= (OSNumber
*)d
->getObject(kIOPMTimelineSystemNumberTrackedKey
);
7519 if (OSDynamicCast(OSNumber
, n
))
7522 this->setEventsTrackedCount(n
->unsigned32BitValue());
7526 /* enables or disables system events */
7527 b
= (OSBoolean
*)d
->getObject(kIOPMTimelineEnabledKey
);
7531 this->setEventsRecordingLevel((int)(kOSBooleanTrue
== b
));
7537 //*********************************************************************************
7538 //*********************************************************************************
7539 //*********************************************************************************
7541 OSDictionary
*IOPMTimeline::copyInfoDictionary(void)
7543 OSDictionary
*out
= OSDictionary::withCapacity(3);
7549 n
= OSNumber::withNumber(hdr
->sizeEntries
, 32);
7550 out
->setObject(kIOPMTimelineSystemNumberTrackedKey
, n
);
7553 n
= OSNumber::withNumber(hdr
->sizeBytes
, 32);
7554 out
->setObject(kIOPMTimelineSystemBufferSizeKey
, n
);
7558 out
->setObject(kIOPMTimelineEnabledKey
, eventsRecordingLevel
? kOSBooleanTrue
: kOSBooleanFalse
);
7563 //*********************************************************************************
7564 //*********************************************************************************
7565 //*********************************************************************************
7567 /* IOPMTimeline::recordSystemPowerEvent()
7569 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
7570 * Type arguments include "system events", and "Intermediate events"
7572 * - System Events have paired "start" and "stop" events.
7573 * - A start event shall be followed by a stop event.
7574 * - Any number of Intermediate Events may fall between the
7575 * start and stop events.
7576 * - Intermediate events are meaningless outside the bounds of a system event's
7577 * start & stoup routines.
7578 * - It's invalid to record a Start event without a following Stop event; e.g. two
7579 * Start events without an intervenining Stop event is invalid.
7582 * - The first recorded system event shall be preceded by an entry with type == 0
7583 * - IOPMTimeline may choose not to record intermediate events while there's not
7584 * a system event in process.
7586 IOReturn
IOPMTimeline::recordSystemPowerEvent( PMEventDetails
*details
)
7588 static bool wakeDonePending
= true;
7589 IOPMSystemEventRecord
*record_to
= NULL
;
7590 OSString
*swUUIDKey
= NULL
;
7591 uint32_t useIndex
= 0;
7594 return kIOReturnBadArgument
;
7597 return kIOReturnNotReady
;
7599 if (details
->eventType
== kIOPMEventTypeWakeDone
)
7601 if(!wakeDonePending
)
7602 return kIOReturnBadArgument
;
7605 IOLockLock(logLock
);
7607 if (details
->eventType
== kIOPMEventTypeWake
) {
7608 wakeDonePending
= true;
7609 } else if (details
->eventType
== kIOPMEventTypeWakeDone
) {
7610 wakeDonePending
= false;
7613 systemState
= details
->eventType
;
7615 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7617 // The entry immediately after the latest entry (and thus
7618 // immediately before the first entry) shall have a type 0.
7619 if (useIndex
+ 1 >= hdr
->sizeEntries
) {
7620 traceBuffer
[useIndex
+ 1].eventType
= 0;
7622 traceBuffer
[0].eventType
= 0;
7625 record_to
= &traceBuffer
[useIndex
];
7626 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7629 record_to
->eventType
= details
->eventType
;
7630 record_to
->eventReason
= details
->reason
;
7631 record_to
->eventResult
= details
->result
;
7632 pmEventTimeStamp(&record_to
->timestamp
);
7634 // If caller doesn't provide a UUID, we'll use the UUID that's posted
7635 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
7636 if (!details
->uuid
) {
7637 swUUIDKey
= OSDynamicCast(OSString
, owner
->copyProperty(kIOPMSleepWakeUUIDKey
));
7640 details
->uuid
= swUUIDKey
->getCStringNoCopy();
7644 strncpy(record_to
->uuid
, details
->uuid
, kMaxPMStringLength
);
7647 swUUIDKey
->release();
7649 numEventsLoggedThisPeriod
++;
7652 IOLockUnlock(logLock
);
7654 return kIOReturnSuccess
;
7658 //*********************************************************************************
7659 //*********************************************************************************
7660 //*********************************************************************************
7662 IOReturn
IOPMTimeline::recordDetailedPowerEvent( PMEventDetails
*details
)
7664 IOPMSystemEventRecord
*record_to
= NULL
;
7667 if (!details
->eventType
|| !details
->ownerName
)
7668 return kIOReturnBadArgument
;
7670 IOLockLock(logLock
);
7672 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7674 record_to
= (IOPMSystemEventRecord
*)&traceBuffer
[useIndex
];
7675 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7678 record_to
->eventType
= details
->eventType
;
7679 if (details
->ownerName
&& (strlen(details
->ownerName
) > 1)) {
7680 strlcpy( record_to
->ownerName
,
7682 sizeof(record_to
->ownerName
));
7685 record_to
->ownerDisambiguateID
= details
->ownerUnique
;
7687 if (details
->interestName
&& (strlen(details
->interestName
) > 1)) {
7688 strlcpy(record_to
->interestName
,
7689 details
->interestName
,
7690 sizeof(record_to
->interestName
));
7693 record_to
->oldState
= details
->oldState
;
7694 record_to
->newState
= details
->newState
;
7695 record_to
->eventResult
= details
->result
;
7696 record_to
->elapsedTimeUS
= details
->elapsedTimeUS
;
7697 pmEventTimeStamp(&record_to
->timestamp
);
7699 numEventsLoggedThisPeriod
++;
7702 IOLockUnlock(logLock
);
7703 return kIOReturnSuccess
;
7706 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
7707 return this->numEventsLoggedThisPeriod
;
7710 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount
) {
7711 this->numEventsLoggedThisPeriod
= newCount
;
7714 bool IOPMTimeline::isSleepCycleInProgress() {
7715 return this->sleepCycleInProgress
;
7718 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag
) {
7719 this->sleepCycleInProgress
= flag
;
7721 //*********************************************************************************
7722 //*********************************************************************************
7723 //*********************************************************************************
7725 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked
)
7727 size_t make_buf_size
= 0;
7729 make_buf_size
= sizeof(IOPMTraceBufferHeader
) + (newTracked
* sizeof(IOPMSystemEventRecord
));
7731 IOLockLock(logLock
);
7733 if (pmTraceMemoryDescriptor
) {
7734 pmTraceMemoryDescriptor
->release();
7735 pmTraceMemoryDescriptor
= NULL
;
7741 if (0 == newTracked
)
7743 IOLog("IOPMrootDomain -> erased buffer.\n");
7747 pmTraceMemoryDescriptor
= IOBufferMemoryDescriptor::withOptions(
7748 kIOMemoryKernelUserShared
| kIODirectionIn
, make_buf_size
);
7750 if (!pmTraceMemoryDescriptor
)
7752 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size
);
7756 pmTraceMemoryDescriptor
->prepare(kIODirectionIn
);
7758 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
7759 hdr
= (IOPMTraceBufferHeader
*)pmTraceMemoryDescriptor
->getBytesNoCopy();
7761 // Recorded events occupy the remaining bulk of the buffer
7762 traceBuffer
= (IOPMSystemEventRecord
*)((uint8_t *)hdr
+ sizeof(IOPMTraceBufferHeader
));
7764 bzero(hdr
, make_buf_size
);
7766 hdr
->sizeBytes
= make_buf_size
;
7767 hdr
->sizeEntries
= newTracked
;
7769 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size
, (unsigned int)(uintptr_t)traceBuffer
);
7772 IOLockUnlock(logLock
);
7775 //*********************************************************************************
7776 //*********************************************************************************
7777 //*********************************************************************************
7779 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits
)
7788 /* static helper to IOPMTimeline
7790 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index
, uint32_t limit
)
7800 inc_index
= (was_index
+1)%limit
;
7801 } while (!OSCompareAndSwap(was_index
, inc_index
, index
));
7807 // MARK: PMAssertionsTracker
7809 //*********************************************************************************
7810 //*********************************************************************************
7811 //*********************************************************************************
7812 // class PMAssertionsTracker Implementation
7814 #define kAssertUniqueIDStart 500
7816 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
7818 PMAssertionsTracker
*myself
;
7820 myself
= new PMAssertionsTracker
;
7824 myself
->owner
= rootDomain
;
7825 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
7826 myself
->assertionsArray
= OSArray::withCapacity(5);
7827 myself
->assertionsKernel
= 0;
7828 myself
->assertionsUser
= 0;
7829 myself
->assertionsCombined
= 0;
7830 myself
->assertionsArrayLock
= IOLockAlloc();
7831 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
7833 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
7841 * - Update assertionsKernel to reflect the state of all
7842 * assertions in the kernel.
7843 * - Update assertionsCombined to reflect both kernel & user space.
7845 void PMAssertionsTracker::tabulate(void)
7849 PMAssertStruct
*_a
= NULL
;
7852 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
7853 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
7857 assertionsKernel
= 0;
7858 assertionsCombined
= 0;
7860 if (!assertionsArray
)
7863 if ((count
= assertionsArray
->getCount()))
7865 for (i
=0; i
<count
; i
++)
7867 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7870 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7871 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
7872 assertionsKernel
|= _a
->assertionBits
;
7877 tabulateProducerCount
++;
7878 assertionsCombined
= assertionsKernel
| assertionsUser
;
7880 if ((assertionsKernel
!= oldKernel
) ||
7881 (assertionsCombined
!= oldCombined
))
7883 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
7887 void PMAssertionsTracker::publishProperties( void )
7889 OSArray
*assertionsSummary
= NULL
;
7891 if (tabulateConsumerCount
!= tabulateProducerCount
)
7893 IOLockLock(assertionsArrayLock
);
7895 tabulateConsumerCount
= tabulateProducerCount
;
7897 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
7899 assertionsSummary
= copyAssertionsArray();
7900 if (assertionsSummary
)
7902 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
7903 assertionsSummary
->release();
7907 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
7910 /* Publish the IOPMrootDomain property "DriverPMAssertions"
7912 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
7914 IOLockUnlock(assertionsArrayLock
);
7918 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
7920 PMAssertStruct
*_a
= NULL
;
7927 && (count
= assertionsArray
->getCount()))
7929 for (i
=0; i
<count
; i
++)
7931 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7934 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7935 if (_a
&& (_id
== _a
->id
)) {
7952 /* PMAssertionsTracker::handleCreateAssertion
7953 * Perform assertion work on the PM workloop. Do not call directly.
7955 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
7961 IOLockLock(assertionsArrayLock
);
7962 assertionsArray
->setObject(newAssertion
);
7963 IOLockUnlock(assertionsArrayLock
);
7964 newAssertion
->release();
7968 return kIOReturnSuccess
;
7971 /* PMAssertionsTracker::createAssertion
7972 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
7975 IOReturn
PMAssertionsTracker::createAssertion(
7976 IOPMDriverAssertionType which
,
7977 IOPMDriverAssertionLevel level
,
7978 IOService
*serviceID
,
7979 const char *whoItIs
,
7980 IOPMDriverAssertionID
*outID
)
7982 OSData
*dataStore
= NULL
;
7983 PMAssertStruct track
;
7985 // Warning: trillions and trillions of created assertions may overflow the unique ID.
7986 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
7987 track
.level
= level
;
7988 track
.assertionBits
= which
;
7989 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
) : 0;
7990 track
.ownerService
= serviceID
;
7991 track
.modifiedTime
= 0;
7992 pmEventTimeStamp(&track
.createdTime
);
7994 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
7997 if (track
.ownerString
)
7998 track
.ownerString
->release();
7999 return kIOReturnNoMemory
;
8004 if (owner
&& owner
->pmPowerStateQueue
) {
8005 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
8008 return kIOReturnSuccess
;
8011 /* PMAssertionsTracker::handleReleaseAssertion
8012 * Runs in PM workloop. Do not call directly.
8014 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
8015 IOPMDriverAssertionID _id
)
8020 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
8023 return kIOReturnNotFound
;
8025 IOLockLock(assertionsArrayLock
);
8026 if (assertStruct
->ownerString
)
8027 assertStruct
->ownerString
->release();
8029 assertionsArray
->removeObject(index
);
8030 IOLockUnlock(assertionsArrayLock
);
8033 return kIOReturnSuccess
;
8036 /* PMAssertionsTracker::releaseAssertion
8037 * Releases an assertion and affects system behavior if appropiate.
8038 * Actual work happens on PM workloop.
8040 IOReturn
PMAssertionsTracker::releaseAssertion(
8041 IOPMDriverAssertionID _id
)
8043 if (owner
&& owner
->pmPowerStateQueue
) {
8044 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
8046 return kIOReturnSuccess
;
8049 /* PMAssertionsTracker::handleSetAssertionLevel
8050 * Runs in PM workloop. Do not call directly.
8052 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
8053 IOPMDriverAssertionID _id
,
8054 IOPMDriverAssertionLevel _level
)
8056 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
8060 if (!assertStruct
) {
8061 return kIOReturnNotFound
;
8064 IOLockLock(assertionsArrayLock
);
8065 pmEventTimeStamp(&assertStruct
->modifiedTime
);
8066 assertStruct
->level
= _level
;
8067 IOLockUnlock(assertionsArrayLock
);
8070 return kIOReturnSuccess
;
8073 /* PMAssertionsTracker::setAssertionLevel
8075 IOReturn
PMAssertionsTracker::setAssertionLevel(
8076 IOPMDriverAssertionID _id
,
8077 IOPMDriverAssertionLevel _level
)
8079 if (owner
&& owner
->pmPowerStateQueue
) {
8080 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
8081 (void *)_level
, _id
);
8084 return kIOReturnSuccess
;
8087 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
8089 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
8093 if (new_user_levels
!= assertionsUser
)
8095 assertionsUser
= new_user_levels
;
8096 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
8100 return kIOReturnSuccess
;
8103 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
8104 IOPMDriverAssertionType new_user_levels
)
8106 if (gIOPMWorkLoop
) {
8107 gIOPMWorkLoop
->runAction(
8108 OSMemberFunctionCast(
8111 &PMAssertionsTracker::handleSetUserAssertionLevels
),
8113 (void *) &new_user_levels
, 0, 0, 0);
8116 return kIOReturnSuccess
;
8120 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
8124 OSArray
*outArray
= NULL
;
8126 if (!assertionsArray
||
8127 (0 == (count
= assertionsArray
->getCount())) ||
8128 (NULL
== (outArray
= OSArray::withCapacity(count
))))
8133 for (i
=0; i
<count
; i
++)
8135 PMAssertStruct
*_a
= NULL
;
8137 OSDictionary
*details
= NULL
;
8139 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8140 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
8142 OSNumber
*_n
= NULL
;
8144 details
= OSDictionary::withCapacity(7);
8148 outArray
->setObject(details
);
8151 _n
= OSNumber::withNumber(_a
->id
, 64);
8153 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
8156 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
8158 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
8161 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
8163 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
8166 _n
= OSNumber::withNumber((uintptr_t)_a
->ownerService
, 64);
8168 details
->setObject(kIOPMDriverAssertionOwnerServiceKey
, _n
);
8171 _n
= OSNumber::withNumber(_a
->level
, 64);
8173 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
8176 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
8178 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
8182 if (_a
->ownerString
) {
8183 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
8192 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
8194 return assertionsCombined
;
8197 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
8198 IOPMDriverAssertionType type
)
8200 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
8202 return kIOPMDriverAssertionLevelOn
;
8204 return kIOPMDriverAssertionLevelOff
;
8208 //*********************************************************************************
8209 //*********************************************************************************
8210 //*********************************************************************************
8213 static void pmEventTimeStamp(uint64_t *recordTS
)
8221 // We assume tsec fits into 32 bits; 32 bits holds enough
8222 // seconds for 136 years since the epoch in 1970.
8223 clock_get_calendar_microtime(&tsec
, &tusec
);
8226 // Pack the sec & microsec calendar time into a uint64_t, for fun.
8228 *recordTS
|= (uint32_t)tusec
;
8229 *recordTS
|= ((uint64_t)tsec
<< 32);
8235 // MARK: IORootParent
8237 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8239 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
8241 // The reason that root domain needs a root parent is to facilitate demand
8242 // sleep, since a power change from the root parent cannot be vetoed.
8244 // The above statement is no longer true since root domain now performs
8245 // demand sleep using overrides. But root parent remains to avoid changing
8246 // the power tree stacking. Root parent is parked at the max power state.
8249 static IOPMPowerState patriarchPowerStates
[2] =
8251 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
8252 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
8255 void IORootParent::initialize( void )
8259 bool IORootParent::start( IOService
* nub
)
8261 IOService::start(nub
);
8262 attachToParent( getRegistryRoot(), gIOPowerPlane
);
8264 registerPowerDriver(this, patriarchPowerStates
, 2);
8269 void IORootParent::shutDownSystem( void )
8273 void IORootParent::restartSystem( void )
8277 void IORootParent::sleepSystem( void )
8281 void IORootParent::dozeSystem( void )
8285 void IORootParent::sleepToDoze( void )
8289 void IORootParent::wakeSystem( void )
8293 OSObject
* IORootParent::copyProperty( const char * aKey
) const
8295 return (IOService::copyProperty(aKey
));