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,
272 kDarkWakeFlagGraphicsPowerState1
= 0x0200,
273 kDarkWakeFlagAudioNotSuppressed
= 0x0400
276 static IOPMrootDomain
* gRootDomain
;
277 static IONotifier
* gSysPowerDownNotifier
= 0;
278 static UInt32 gSleepOrShutdownPending
= 0;
279 static UInt32 gWillShutdown
= 0;
280 static UInt32 gPagingOff
= 0;
281 static UInt32 gSleepWakeUUIDIsSet
= false;
282 static uint32_t gAggressivesState
= 0;
283 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
| kDarkWakeFlagIgnoreDiskIOAlways
;
284 static PMStatsStruct gPMStats
;
287 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= 0;
288 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= 0;
289 static void * gSleepPolicyTarget
;
292 struct timeval gIOLastSleepTime
;
293 struct timeval gIOLastWakeTime
;
295 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
296 #define kCPUUnknownIndex 9999999
303 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
304 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
305 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
307 #define kBadPMFeatureID 0
311 * Opaque handle passed to clients of registerPMSettingController()
313 class PMSettingHandle
: public OSObject
315 OSDeclareFinalStructors( PMSettingHandle
)
316 friend class PMSettingObject
;
319 PMSettingObject
*pmso
;
325 * Internal object to track each PM setting controller
327 class PMSettingObject
: public OSObject
329 OSDeclareFinalStructors( PMSettingObject
)
330 friend class IOPMrootDomain
;
333 queue_head_t calloutQueue
;
335 IOPMrootDomain
*parent
;
336 PMSettingHandle
*pmsh
;
337 IOPMSettingControllerCallback func
;
340 uint32_t *publishedFeatureID
;
341 uint32_t settingCount
;
347 static PMSettingObject
*pmSettingObject(
348 IOPMrootDomain
*parent_arg
,
349 IOPMSettingControllerCallback handler_arg
,
350 OSObject
*target_arg
,
351 uintptr_t refcon_arg
,
352 uint32_t supportedPowerSources
,
353 const OSSymbol
*settings
[],
354 OSObject
**handle_obj
);
356 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
357 void clientHandleFreed(void);
360 struct PMSettingCallEntry
{
365 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
366 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
367 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
368 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
370 //*********************************************************************************
371 //*********************************************************************************
372 //*********************************************************************************
374 /* @class IOPMTimeline
375 * @astract Tracks & records PM activity.
376 * @discussion Intended for use only as a helper-class to IOPMrootDomain.
377 * Do not subclass or directly invoke iOPMTimeline
379 class IOPMTimeline
: public OSObject
381 OSDeclareDefaultStructors( IOPMTimeline
);
384 static IOPMTimeline
* timeline(IOPMrootDomain
*root_domain
);
386 bool setProperties(OSDictionary
*d
);
387 OSDictionary
*copyInfoDictionary(void);
389 IOReturn
recordSystemPowerEvent( PMEventDetails
*details
);
391 IOReturn
recordDetailedPowerEvent( PMEventDetails
*details
);
393 IOMemoryDescriptor
*getPMTraceMemoryDescriptor();
395 uint32_t getNumEventsLoggedThisPeriod();
396 void setNumEventsLoggedThisPeriod(uint32_t newCount
);
397 bool isSleepCycleInProgress();
398 void setSleepCycleInProgressFlag(bool flag
);
403 void setEventsTrackedCount(uint32_t newTracked
);
404 void setEventsRecordingLevel(uint32_t eventsTrackedBits
);
405 static uint32_t _atomicIndexIncrement(uint32_t *index
, uint32_t limit
);
408 kPMTimelineRecordTardyDrivers
= 1 << 0,
409 kPMTmielineRecordSystemEvents
= 1 << 1,
410 kPMTimelineRecordAllDrivers
= 1 << 2,
411 kPMTimelineRecordOff
= 0,
412 kPMTimelineRecordDefault
= 3,
413 kPMTimelineRecordDebug
= 7
416 // eventsRecordingLevel is a bitfield defining which PM driver events will get logged
417 // into the PM buffer.
418 uint32_t eventsRecordingLevel
;
420 // pmTraceMemoryDescriptor represents the memory block that IOPMTimeLine records PM trace points into.
421 IOBufferMemoryDescriptor
*pmTraceMemoryDescriptor
;
423 // Pointer to starting address in pmTraceMemoryDescriptor
424 IOPMSystemEventRecord
*traceBuffer
;
425 IOPMTraceBufferHeader
*hdr
;
427 uint16_t systemState
;
430 IOPMrootDomain
*owner
;
432 uint32_t numEventsLoggedThisPeriod
;
433 bool sleepCycleInProgress
;
436 OSDefineMetaClassAndStructors( IOPMTimeline
, OSObject
)
440 * Internal helper object for logging trace points to RTC
441 * IOPMrootDomain and only IOPMrootDomain should instantiate
442 * exactly one of these.
445 typedef void (*IOPMTracePointHandler
)(
446 void * target
, uint32_t code
, uint32_t data
);
448 class PMTraceWorker
: public OSObject
450 OSDeclareDefaultStructors(PMTraceWorker
)
452 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
454 static PMTraceWorker
*tracer( IOPMrootDomain
* );
455 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
456 void tracePoint(uint8_t phase
);
457 void tracePoint(uint8_t phase
, uint8_t data8
);
458 void traceDetail(uint32_t detail
);
459 void traceLoginWindowPhase(uint8_t phase
);
460 int recordTopLevelPCIDevice(IOService
*);
461 void RTC_TRACE(void);
462 virtual bool serialize(OSSerialize
*s
) const;
464 IOPMTracePointHandler tracePointHandler
;
465 void * tracePointTarget
;
467 IOPMrootDomain
*owner
;
468 IOLock
*pciMappingLock
;
469 OSArray
*pciDeviceBitMappings
;
471 uint8_t addedToRegistry
;
473 uint8_t loginWindowPhase
;
475 uint32_t traceData32
;
479 * PMAssertionsTracker
480 * Tracks kernel and user space PM assertions
482 class PMAssertionsTracker
: public OSObject
484 OSDeclareFinalStructors(PMAssertionsTracker
)
486 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
488 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
489 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
490 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
491 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
493 OSArray
*copyAssertionsArray(void);
494 IOPMDriverAssertionType
getActivatedAssertions(void);
495 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
497 IOReturn
handleCreateAssertion(OSData
*);
498 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
499 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
500 IOReturn
handleSetUserAssertionLevels(void * arg0
);
501 void publishProperties(void);
505 IOPMDriverAssertionID id
;
506 IOPMDriverAssertionType assertionBits
;
507 uint64_t createdTime
;
508 uint64_t modifiedTime
;
509 const OSSymbol
*ownerString
;
510 IOService
*ownerService
;
511 IOPMDriverAssertionLevel level
;
514 uint32_t tabulateProducerCount
;
515 uint32_t tabulateConsumerCount
;
517 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
520 IOPMrootDomain
*owner
;
521 OSArray
*assertionsArray
;
522 IOLock
*assertionsArrayLock
;
523 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
524 IOPMDriverAssertionType assertionsKernel
;
525 IOPMDriverAssertionType assertionsUser
;
526 IOPMDriverAssertionType assertionsCombined
;
529 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
533 * Internal helper object for Shutdown/Restart notifications.
535 #define kPMHaltMaxWorkers 8
536 #define kPMHaltTimeoutMS 100
538 class PMHaltWorker
: public OSObject
540 OSDeclareFinalStructors( PMHaltWorker
)
543 IOService
* service
; // service being worked on
544 AbsoluteTime startTime
; // time when work started
545 int depth
; // work on nubs at this PM-tree depth
546 int visits
; // number of nodes visited (debug)
548 bool timeout
; // service took too long
550 static PMHaltWorker
* worker( void );
551 static void main( void * arg
, wait_result_t waitResult
);
552 static void work( PMHaltWorker
* me
);
553 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
554 virtual void free( void );
557 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
560 #define super IOService
561 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
563 static void IOPMRootDomainWillShutdown(void)
565 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
567 OSKext::willShutdown();
568 for (int i
= 0; i
< 100; i
++)
570 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
578 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
580 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
583 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
585 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
588 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
590 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
593 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
595 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
598 IOReturn
rootDomainRestart ( void )
600 return gRootDomain
->restartSystem();
603 IOReturn
rootDomainShutdown ( void )
605 return gRootDomain
->shutdownSystem();
608 void IOSystemShutdownNotification(void)
610 IOPMRootDomainWillShutdown();
611 if (OSCompareAndSwap(0, 1, &gPagingOff
))
614 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
619 int sync_internal(void);
623 A device is always in the highest power state which satisfies its driver,
624 its policy-maker, and any power children it has, but within the constraint
625 of the power state provided by its parent. The driver expresses its desire by
626 calling changePowerStateTo(), the policy-maker expresses its desire by calling
627 changePowerStateToPriv(), and the children express their desires by calling
628 requestPowerDomainState().
630 The Root Power Domain owns the policy for idle and demand sleep for the system.
631 It is a power-managed IOService just like the others in the system.
632 It implements several power states which map to what we see as Sleep and On.
634 The sleep policy is as follows:
635 1. Sleep is prevented if the case is open so that nobody will think the machine
636 is off and plug/unplug cards.
637 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
638 3. System cannot Sleep if some object in the tree is in a power state marked
639 kIOPMPreventSystemSleep.
641 These three conditions are enforced using the "driver clamp" by calling
642 changePowerStateTo(). For example, if the case is opened,
643 changePowerStateTo(ON_STATE) is called to hold the system on regardless
644 of the desires of the children of the root or the state of the other clamp.
646 Demand Sleep is initiated by pressing the front panel power button, closing
647 the clamshell, or selecting the menu item. In this case the root's parent
648 actually initiates the power state change so that the root domain has no
649 choice and does not give applications the opportunity to veto the change.
651 Idle Sleep occurs if no objects in the tree are in a state marked
652 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
653 the root on, so it sets the "policy-maker clamp" by calling
654 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
655 This timer is set for the difference between the sleep timeout slider and the
656 display dim timeout slider. When the timer expires, it releases its clamp and
657 now nothing is holding it awake, so it falls asleep.
659 Demand sleep is prevented when the system is booting. When preferences are
660 transmitted by the loginwindow at the end of boot, a flag is cleared,
661 and this allows subsequent Demand Sleep.
664 //******************************************************************************
666 IOPMrootDomain
* IOPMrootDomain::construct( void )
668 IOPMrootDomain
*root
;
670 root
= new IOPMrootDomain
;
677 //******************************************************************************
679 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
681 IOService
* rootDomain
= (IOService
*) p0
;
682 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
683 uint32_t powerState
= rootDomain
->getPowerState();
685 DLOG("disk_sync_callout ps=%u\n", powerState
);
687 if (ON_STATE
== powerState
)
690 IOHibernateSystemSleep();
697 IOHibernateSystemPostWake();
701 rootDomain
->allowPowerChange(notifyRef
);
702 DLOG("disk_sync_callout finish\n");
705 //******************************************************************************
707 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
709 AbsoluteTime endTime
;
712 clock_get_uptime(&endTime
);
713 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
715 SUB_ABSOLUTETIME(&endTime
, startTime
);
716 absolutetime_to_nanoseconds(endTime
, &nano
);
719 return (UInt32
)(nano
/ 1000000ULL);
722 //******************************************************************************
725 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
727 struct timeval
*swt
= (struct timeval
*)arg1
;
728 struct proc
*p
= req
->p
;
731 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
732 } else if(proc_is64bit(p
)) {
733 struct user64_timeval t
;
734 t
.tv_sec
= swt
->tv_sec
;
735 t
.tv_usec
= swt
->tv_usec
;
736 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
738 struct user32_timeval t
;
739 t
.tv_sec
= swt
->tv_sec
;
740 t
.tv_usec
= swt
->tv_usec
;
741 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
745 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
746 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
747 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
749 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
750 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
751 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
756 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
758 int new_value
, changed
;
759 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
761 if (!gWillShutdown
&& (new_value
== 1)) {
762 IOPMRootDomainWillShutdown();
769 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
770 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
771 0, 0, sysctl_willshutdown
, "I", "");
776 sysctl_progressmeterenable
777 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
780 int new_value
, changed
;
782 error
= sysctl_io_number(req
, vc_progress_meter_enable
, sizeof(int), &new_value
, &changed
);
785 vc_enable_progressmeter(new_value
);
792 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
795 int new_value
, changed
;
797 error
= sysctl_io_number(req
, vc_progress_meter_value
, sizeof(int), &new_value
, &changed
);
800 vc_set_progressmeter(new_value
);
805 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
806 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
807 0, 0, sysctl_progressmeterenable
, "I", "");
809 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
810 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
811 0, 0, sysctl_progressmeter
, "I", "");
815 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
817 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
818 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
819 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
820 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
821 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
822 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
824 //******************************************************************************
827 //******************************************************************************
829 #define kRootDomainSettingsCount 17
831 bool IOPMrootDomain::start( IOService
* nub
)
833 OSIterator
*psIterator
;
834 OSDictionary
*tmpDict
;
835 IORootParent
* patriarch
;
840 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
841 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
842 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
843 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
844 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
845 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
847 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
848 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
849 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
851 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
852 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
854 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
856 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
857 gIOPMSettingAutoWakeSecondsKey
,
858 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
859 gIOPMSettingAutoWakeCalendarKey
,
860 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
861 gIOPMSettingDebugWakeRelativeKey
,
862 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
863 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
864 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
865 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
866 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
867 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
868 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
869 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
870 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
871 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
872 gIOPMSettingSilentRunningKey
875 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
877 queue_init(&aggressivesQueue
);
878 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
879 aggressivesData
= OSData::withCapacity(
880 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
882 featuresDictLock
= IOLockAlloc();
883 settingsCtrlLock
= IOLockAlloc();
884 setPMRootDomain(this);
886 extraSleepTimer
= thread_call_allocate(
887 idleSleepTimerExpired
,
888 (thread_call_param_t
) this);
890 diskSyncCalloutEntry
= thread_call_allocate(
892 (thread_call_param_t
) this);
894 setProperty(kIOSleepSupportedKey
, true);
896 bzero(&gPMStats
, sizeof(gPMStats
));
898 pmTracer
= PMTraceWorker::tracer(this);
900 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
902 userDisabledAllSleep
= false;
903 systemBooting
= true;
905 idleSleepTimerPending
= false;
907 clamshellClosed
= false;
908 clamshellExists
= false;
909 clamshellDisabled
= true;
910 acAdaptorConnected
= true;
911 clamshellSleepDisabled
= false;
913 // Set the default system capabilities at boot.
914 _currentCapability
= kIOPMSystemCapabilityCPU
|
915 kIOPMSystemCapabilityGraphics
|
916 kIOPMSystemCapabilityAudio
|
917 kIOPMSystemCapabilityNetwork
;
919 _pendingCapability
= _currentCapability
;
920 _desiredCapability
= _currentCapability
;
921 _highestCapability
= _currentCapability
;
922 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
924 queuedSleepWakeUUIDString
= NULL
;
925 pmStatsAppResponses
= OSArray::withCapacity(5);
926 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
927 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
928 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
929 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
930 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
932 idxPMCPUClamshell
= kCPUUnknownIndex
;
933 idxPMCPULimitedPower
= kCPUUnknownIndex
;
935 tmpDict
= OSDictionary::withCapacity(1);
936 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
939 settingsCallbacks
= OSDictionary::withCapacity(1);
941 // Create a list of the valid PM settings that we'll relay to
942 // interested clients in setProperties() => setPMSetting()
943 allowedPMSettings
= OSArray::withObjects(
944 (const OSObject
**)settingsArr
,
945 kRootDomainSettingsCount
,
948 // List of PM settings that should not automatically publish itself
949 // as a feature when registered by a listener.
950 noPublishPMSettings
= OSArray::withObjects(
951 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
953 fPMSettingsDict
= OSDictionary::withCapacity(5);
954 preventIdleSleepList
= OSSet::withCapacity(8);
955 preventSystemSleepList
= OSSet::withCapacity(2);
957 PMinit(); // creates gIOPMWorkLoop
959 // Create IOPMPowerStateQueue used to queue external power
960 // events, and to handle those events on the PM work loop.
961 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
962 this, OSMemberFunctionCast(IOEventSource::Action
, this,
963 &IOPMrootDomain::dispatchPowerEvent
));
964 getPMworkloop()->addEventSource(pmPowerStateQueue
);
965 #ifdef CHECK_THREAD_CONTEXT
966 gIOPMWorkLoop
= getPMworkloop();
969 // create our power parent
970 patriarch
= new IORootParent
;
972 patriarch
->attach(this);
973 patriarch
->start(this);
974 patriarch
->addPowerChild(this);
976 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
977 changePowerStateToPriv(ON_STATE
);
979 if (gIOKitDebug
& (kIOLogDriverPower1
| kIOLogDriverPower2
))
981 // Setup our PM logging & recording code
982 timeline
= IOPMTimeline::timeline(this);
984 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
988 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
994 // install power change handler
995 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
998 // Register for a notification when IODisplayWrangler is published
999 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1001 _displayWranglerNotifier
= addMatchingNotification(
1002 gIOPublishNotification
, tmpDict
,
1003 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1009 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1010 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1011 ucClassName
->release();
1013 // IOBacklightDisplay can take a long time to load at boot, or it may
1014 // not load at all if you're booting with clamshell closed. We publish
1015 // 'DisplayDims' here redundantly to get it published early and at all.
1016 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
1017 if( psIterator
&& psIterator
->getNextObject() )
1019 // There's at least one battery on the system, so we publish
1020 // 'DisplayDims' support for the LCD.
1021 publishFeature("DisplayDims");
1024 psIterator
->release();
1028 pmSuspendedCapacity
= pmSuspendedSize
= 0;
1029 pmSuspendedPIDS
= NULL
;
1032 sysctl_register_oid(&sysctl__kern_sleeptime
);
1033 sysctl_register_oid(&sysctl__kern_waketime
);
1034 sysctl_register_oid(&sysctl__kern_willshutdown
);
1035 #if !CONFIG_EMBEDDED
1036 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1037 sysctl_register_oid(&sysctl__kern_progressmeter
);
1038 #endif /* !CONFIG_EMBEDDED */
1041 IOHibernateSystemInit(this);
1044 registerService(); // let clients find us
1052 void IOPMrootDomain::handleSuspendPMNotificationClient(uint32_t pid
, bool doSuspend
)
1059 if (!pmSuspendedPIDS
) {
1060 pmSuspendedCapacity
= 8;
1061 pmSuspendedSize
= pmSuspendedCapacity
* sizeof(PMNotifySuspendedStruct
);
1062 pmSuspendedPIDS
= (PMNotifySuspendedStruct
*)IOMalloc(pmSuspendedSize
);
1063 bzero(pmSuspendedPIDS
, pmSuspendedSize
);
1066 /* Find the existing pid in the existing array */
1068 for (i
=0; i
< pmSuspendedCapacity
; i
++) {
1069 if (pmSuspendedPIDS
[i
].pid
== pid
) {
1077 /* Find an unused slot in the suspended pids table. */
1079 for (i
=0; i
< pmSuspendedCapacity
; i
++) {
1080 if (pmSuspendedPIDS
[i
].refcount
== 0) {
1085 if (pmSuspendedCapacity
== i
)
1087 /* GROW if necessary */
1089 PMNotifySuspendedStruct
*newSuspended
= NULL
;
1090 pmSuspendedCapacity
*= 2;
1091 pmSuspendedSize
= pmSuspendedCapacity
* sizeof(PMNotifySuspendedStruct
);
1092 newSuspended
= (PMNotifySuspendedStruct
*)IOMalloc(pmSuspendedSize
);
1094 bzero(newSuspended
, pmSuspendedSize
);
1095 bcopy(pmSuspendedPIDS
, newSuspended
, pmSuspendedSize
/2);
1096 IOFree(pmSuspendedPIDS
, pmSuspendedSize
/2);
1098 pmSuspendedPIDS
= newSuspended
;
1102 pmSuspendedPIDS
[index
].pid
= pid
;
1106 pmSuspendedPIDS
[index
].refcount
++;
1108 pmSuspendedPIDS
[index
].refcount
--;
1112 * Publish array of suspended pids in IOPMrootDomain
1114 OSArray
*publish
= OSArray::withCapacity(pmSuspendedCapacity
);
1116 for (i
=0; i
<pmSuspendedCapacity
; i
++)
1118 if (pmSuspendedPIDS
[i
].refcount
> 0) {
1119 OSDictionary
*suspended
= OSDictionary::withCapacity(2);
1122 n
= OSNumber::withNumber(pmSuspendedPIDS
[i
].pid
, 32);
1123 suspended
->setObject("pid", n
);
1126 n
= OSNumber::withNumber(pmSuspendedPIDS
[i
].refcount
, 32);
1127 suspended
->setObject("refcount", n
);
1130 publish
->setObject(suspended
);
1131 suspended
->release();
1136 if (0 != publish
->getCount()) {
1137 setProperty(kPMSuspendedNotificationClients
, publish
);
1139 removeProperty(kPMSuspendedNotificationClients
);
1147 bool IOPMrootDomain::pmNotificationIsSuspended(uint32_t pid
)
1151 for (index
=0; index
< pmSuspendedCapacity
; index
++) {
1152 if (pmSuspendedPIDS
[index
].pid
== pid
) {
1153 return pmSuspendedPIDS
[index
].refcount
> 0;
1161 void IOPMrootDomain::suspendPMNotificationsForPID(uint32_t pid
, bool doSuspend
)
1163 if(pmPowerStateQueue
) {
1164 pmPowerStateQueue
->submitPowerEvent(kPowerEventSuspendClient
, (void *)pid
, (uint64_t)doSuspend
);
1169 //******************************************************************************
1172 // Receive a setProperty call
1173 // The "System Boot" property means the system is completely booted.
1174 //******************************************************************************
1176 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1178 IOReturn return_value
= kIOReturnSuccess
;
1179 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1183 const OSSymbol
*key
;
1185 OSCollectionIterator
* iter
= 0;
1187 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1188 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1189 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1190 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1191 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1192 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1193 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1194 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1195 const OSSymbol
*loginwindow_tracepoint_string
= OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
1196 const OSSymbol
*pmTimelineLogging_string
= OSSymbol::withCString(kIOPMTimelineDictionaryKey
);
1198 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1199 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1200 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1201 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1202 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1203 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1205 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1206 const OSSymbol
*suspendPMClient_string
= OSSymbol::withCString(kPMSuspendedNotificationClients
);
1211 return_value
= kIOReturnBadArgument
;
1215 iter
= OSCollectionIterator::withCollection(dict
);
1218 return_value
= kIOReturnNoMemory
;
1222 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1223 (obj
= dict
->getObject(key
)))
1225 if (key
->isEqualTo(publish_simulated_battery_string
))
1227 if (OSDynamicCast(OSBoolean
, obj
))
1228 publishResource(key
, kOSBooleanTrue
);
1230 else if (key
->isEqualTo(idle_seconds_string
))
1232 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1234 setProperty(key
, n
);
1235 idleSeconds
= n
->unsigned32BitValue();
1238 else if (key
->isEqualTo(boot_complete_string
))
1240 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1242 else if (key
->isEqualTo(sys_shutdown_string
))
1244 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1245 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1247 else if (key
->isEqualTo(battery_warning_disabled_string
))
1249 setProperty(key
, obj
);
1251 else if (key
->isEqualTo(pmTimelineLogging_string
))
1253 if ((d
= OSDynamicCast(OSDictionary
, obj
)) &&
1254 timeline
&& timeline
->setProperties(d
))
1256 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
1258 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
1264 else if (key
->isEqualTo(hibernatemode_string
) ||
1265 key
->isEqualTo(hibernatefilemin_string
) ||
1266 key
->isEqualTo(hibernatefilemax_string
) ||
1267 key
->isEqualTo(hibernatefreeratio_string
) ||
1268 key
->isEqualTo(hibernatefreetime_string
))
1270 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1271 setProperty(key
, n
);
1273 else if (key
->isEqualTo(hibernatefile_string
))
1275 OSString
* str
= OSDynamicCast(OSString
, obj
);
1276 if (str
) setProperty(key
, str
);
1279 else if (key
->isEqualTo(sleepdisabled_string
))
1281 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1283 setProperty(key
, b
);
1284 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1287 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1290 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1292 else if (key
->isEqualTo(loginwindow_tracepoint_string
))
1294 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
)))
1295 pmTracer
->traceLoginWindowPhase(n
->unsigned8BitValue());
1297 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1298 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1299 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1300 key
->isEqualTo(stall_halt_string
))
1302 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1303 setProperty(key
, b
);
1305 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1306 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1307 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1309 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1310 setProperty(key
, n
);
1312 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1314 if (kOSBooleanTrue
== obj
)
1315 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1317 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1318 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1320 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1321 else if (key
->isEqualTo(suspendPMClient_string
))
1323 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1325 // Toggle the suspended status for pid n.
1326 uint32_t pid_int
= n
->unsigned32BitValue();
1327 suspendPMNotificationsForPID(pid_int
, !pmNotificationIsSuspended(pid_int
));
1331 // Relay our allowed PM settings onto our registered PM clients
1332 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1334 if ((gIOPMSettingAutoWakeSecondsKey
== key
) && ((n
= OSDynamicCast(OSNumber
, obj
))))
1336 UInt32 rsecs
= n
->unsigned32BitValue();
1338 autoWakeStart
= autoWakeEnd
= 0;
1341 AbsoluteTime deadline
;
1342 clock_interval_to_deadline(rsecs
+ kAutoWakePostWindow
, kSecondScale
, &deadline
);
1343 autoWakeEnd
= AbsoluteTime_to_scalar(&deadline
);
1344 if (rsecs
> kAutoWakePreWindow
)
1345 rsecs
-= kAutoWakePreWindow
;
1348 clock_interval_to_deadline(rsecs
, kSecondScale
, &deadline
);
1349 autoWakeStart
= AbsoluteTime_to_scalar(&deadline
);
1353 return_value
= setPMSetting(key
, obj
);
1354 if (kIOReturnSuccess
!= return_value
)
1357 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1359 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1360 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1362 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1366 _debugWakeSeconds
= 0;
1367 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1369 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1371 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1374 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1375 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1377 const IOPMCalendarStruct
* cs
=
1378 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1381 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1383 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1384 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1390 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1395 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1396 if(boot_complete_string
) boot_complete_string
->release();
1397 if(sys_shutdown_string
) sys_shutdown_string
->release();
1398 if(stall_halt_string
) stall_halt_string
->release();
1399 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1400 if(idle_seconds_string
) idle_seconds_string
->release();
1401 if(sleepdisabled_string
) sleepdisabled_string
->release();
1402 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1403 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1404 if(pmTimelineLogging_string
) pmTimelineLogging_string
->release();
1406 if(hibernatemode_string
) hibernatemode_string
->release();
1407 if(hibernatefile_string
) hibernatefile_string
->release();
1408 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1409 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1411 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1412 if(suspendPMClient_string
) suspendPMClient_string
->release();
1414 if (iter
) iter
->release();
1415 return return_value
;
1419 // MARK: Aggressiveness
1421 //******************************************************************************
1422 // setAggressiveness
1424 // Override IOService::setAggressiveness()
1425 //******************************************************************************
1427 IOReturn
IOPMrootDomain::setAggressiveness(
1429 unsigned long value
)
1431 return setAggressiveness( type
, value
, 0 );
1435 * Private setAggressiveness() with an internal options argument.
1437 IOReturn
IOPMrootDomain::setAggressiveness(
1439 unsigned long value
,
1440 IOOptionBits options
)
1442 AggressivesRequest
* entry
;
1443 AggressivesRequest
* request
;
1446 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1447 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1449 request
= IONew(AggressivesRequest
, 1);
1451 return kIOReturnNoMemory
;
1453 memset(request
, 0, sizeof(*request
));
1454 request
->options
= options
;
1455 request
->dataType
= kAggressivesRequestTypeRecord
;
1456 request
->data
.record
.type
= (uint32_t) type
;
1457 request
->data
.record
.value
= (uint32_t) value
;
1461 // Update disk quick spindown flag used by getAggressiveness().
1462 // Never merge requests with quick spindown flags set.
1464 if (options
& kAggressivesOptionQuickSpindownEnable
)
1465 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1466 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1467 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1470 // Coalesce requests with identical aggressives types.
1471 // Deal with callers that calls us too "aggressively".
1473 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1475 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1476 (entry
->data
.record
.type
== type
) &&
1477 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1479 entry
->data
.record
.value
= value
;
1488 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1491 AGGRESSIVES_UNLOCK();
1494 IODelete(request
, AggressivesRequest
, 1);
1496 if (options
& kAggressivesOptionSynchronous
)
1497 handleAggressivesRequests(); // not truly synchronous
1499 thread_call_enter(aggressivesThreadCall
);
1501 return kIOReturnSuccess
;
1504 //******************************************************************************
1505 // getAggressiveness
1507 // Override IOService::setAggressiveness()
1508 // Fetch the aggressiveness factor with the given type.
1509 //******************************************************************************
1511 IOReturn
IOPMrootDomain::getAggressiveness (
1513 unsigned long * outLevel
)
1519 return kIOReturnBadArgument
;
1523 // Disk quick spindown in effect, report value = 1
1525 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1526 (type
== kPMMinutesToSpinDown
))
1528 value
= kAggressivesMinValue
;
1532 // Consult the pending request queue.
1536 AggressivesRequest
* entry
;
1538 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1540 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1541 (entry
->data
.record
.type
== type
) &&
1542 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1544 value
= entry
->data
.record
.value
;
1551 // Consult the backend records.
1553 if (!source
&& aggressivesData
)
1555 AggressivesRecord
* record
;
1558 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1559 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1561 for (i
= 0; i
< count
; i
++, record
++)
1563 if (record
->type
== type
)
1565 value
= record
->value
;
1572 AGGRESSIVES_UNLOCK();
1576 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1577 source
, (uint32_t) type
, value
);
1578 *outLevel
= (unsigned long) value
;
1579 return kIOReturnSuccess
;
1583 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1584 *outLevel
= 0; // default return = 0, driver may not check for error
1585 return kIOReturnInvalid
;
1589 //******************************************************************************
1590 // joinAggressiveness
1592 // Request from IOService to join future aggressiveness broadcasts.
1593 //******************************************************************************
1595 IOReturn
IOPMrootDomain::joinAggressiveness(
1596 IOService
* service
)
1598 AggressivesRequest
* request
;
1600 if (!service
|| (service
== this))
1601 return kIOReturnBadArgument
;
1603 DLOG("joinAggressiveness %s %p\n", service
->getName(), service
);
1605 request
= IONew(AggressivesRequest
, 1);
1607 return kIOReturnNoMemory
;
1609 service
->retain(); // released by synchronizeAggressives()
1611 memset(request
, 0, sizeof(*request
));
1612 request
->dataType
= kAggressivesRequestTypeService
;
1613 request
->data
.service
= service
;
1616 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1617 AGGRESSIVES_UNLOCK();
1619 thread_call_enter(aggressivesThreadCall
);
1621 return kIOReturnSuccess
;
1624 //******************************************************************************
1625 // handleAggressivesRequests
1627 // Backend thread processes all incoming aggressiveness requests in the queue.
1628 //******************************************************************************
1631 handleAggressivesFunction(
1632 thread_call_param_t param1
,
1633 thread_call_param_t param2
)
1637 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1641 void IOPMrootDomain::handleAggressivesRequests( void )
1643 AggressivesRecord
* start
;
1644 AggressivesRecord
* record
;
1645 AggressivesRequest
* request
;
1646 queue_head_t joinedQueue
;
1650 bool pingSelf
= false;
1654 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1655 queue_empty(&aggressivesQueue
))
1658 gAggressivesState
|= kAggressivesStateBusy
;
1659 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1660 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1665 queue_init(&joinedQueue
);
1669 // Remove request from the incoming queue in FIFO order.
1670 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1671 switch (request
->dataType
)
1673 case kAggressivesRequestTypeRecord
:
1674 // Update existing record if found.
1676 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1678 if (record
->type
== request
->data
.record
.type
)
1682 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1684 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1687 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1688 kAggressivesRecordFlagModified
);
1689 DLOG("disk spindown accelerated, was %u min\n",
1693 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1695 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1698 record
->flags
|= kAggressivesRecordFlagModified
;
1699 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1700 DLOG("disk spindown restored to %u min\n",
1704 else if (record
->value
!= request
->data
.record
.value
)
1706 record
->value
= request
->data
.record
.value
;
1707 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1710 record
->flags
|= kAggressivesRecordFlagModified
;
1717 // No matching record, append a new record.
1719 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1721 AggressivesRecord newRecord
;
1723 newRecord
.flags
= kAggressivesRecordFlagModified
;
1724 newRecord
.type
= request
->data
.record
.type
;
1725 newRecord
.value
= request
->data
.record
.value
;
1726 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1728 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1729 DLOG("disk spindown accelerated\n");
1732 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1734 // OSData may have switched to another (larger) buffer.
1735 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1736 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1740 // Finished processing the request, release it.
1741 IODelete(request
, AggressivesRequest
, 1);
1744 case kAggressivesRequestTypeService
:
1745 // synchronizeAggressives() will free request.
1746 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1750 panic("bad aggressives request type %x\n", request
->dataType
);
1753 } while (!queue_empty(&aggressivesQueue
));
1755 // Release the lock to perform work, with busy flag set.
1756 if (!queue_empty(&joinedQueue
) || broadcast
)
1758 AGGRESSIVES_UNLOCK();
1759 if (!queue_empty(&joinedQueue
))
1760 synchronizeAggressives(&joinedQueue
, start
, count
);
1762 broadcastAggressives(start
, count
);
1766 // Remove the modified flag from all records.
1767 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1769 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1770 ((record
->type
== kPMMinutesToDim
) ||
1771 (record
->type
== kPMMinutesToSleep
)))
1774 record
->flags
&= ~kAggressivesRecordFlagModified
;
1777 // Check the incoming queue again since new entries may have been
1778 // added while lock was released above.
1780 } while (!queue_empty(&aggressivesQueue
));
1782 gAggressivesState
&= ~kAggressivesStateBusy
;
1785 AGGRESSIVES_UNLOCK();
1787 // Root domain is interested in system and display sleep slider changes.
1788 // Submit a power event to handle those changes on the PM work loop.
1790 if (pingSelf
&& pmPowerStateQueue
) {
1791 pmPowerStateQueue
->submitPowerEvent(
1792 kPowerEventPolicyStimulus
,
1793 (void *) kStimulusAggressivenessChanged
);
1797 //******************************************************************************
1798 // synchronizeAggressives
1800 // Push all known aggressiveness records to one or more IOService.
1801 //******************************************************************************
1803 void IOPMrootDomain::synchronizeAggressives(
1804 queue_head_t
* joinedQueue
,
1805 const AggressivesRecord
* array
,
1808 IOService
* service
;
1809 AggressivesRequest
* request
;
1810 const AggressivesRecord
* record
;
1811 IOPMDriverCallEntry callEntry
;
1815 while (!queue_empty(joinedQueue
))
1817 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1818 if (request
->dataType
== kAggressivesRequestTypeService
)
1819 service
= request
->data
.service
;
1823 IODelete(request
, AggressivesRequest
, 1);
1828 if (service
->assertPMDriverCall(&callEntry
))
1830 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1832 value
= record
->value
;
1833 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1834 value
= kAggressivesMinValue
;
1836 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1837 record
->type
, value
, service
->getName());
1838 service
->setAggressiveness(record
->type
, value
);
1840 service
->deassertPMDriverCall(&callEntry
);
1842 service
->release(); // retained by joinAggressiveness()
1847 //******************************************************************************
1848 // broadcastAggressives
1850 // Traverse PM tree and call setAggressiveness() for records that have changed.
1851 //******************************************************************************
1853 void IOPMrootDomain::broadcastAggressives(
1854 const AggressivesRecord
* array
,
1857 IORegistryIterator
* iter
;
1858 IORegistryEntry
* entry
;
1859 IOPowerConnection
* connect
;
1860 IOService
* service
;
1861 const AggressivesRecord
* record
;
1862 IOPMDriverCallEntry callEntry
;
1866 iter
= IORegistryIterator::iterateOver(
1867 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1873 while ((entry
= iter
->getNextObject()))
1875 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1876 if (!connect
|| !connect
->getReadyFlag())
1879 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1881 if (service
->assertPMDriverCall(&callEntry
))
1883 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1885 if (record
->flags
& kAggressivesRecordFlagModified
)
1887 value
= record
->value
;
1888 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1889 value
= kAggressivesMinValue
;
1890 _LOG("broadcastAggressives %x = %u to %s\n",
1891 record
->type
, value
, service
->getName());
1892 service
->setAggressiveness(record
->type
, value
);
1895 service
->deassertPMDriverCall(&callEntry
);
1901 while (!entry
&& !iter
->isValid());
1907 // MARK: System Sleep
1909 //******************************************************************************
1910 // startIdleSleepTimer
1912 //******************************************************************************
1914 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1916 AbsoluteTime deadline
;
1921 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1922 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1923 idleSleepTimerPending
= true;
1927 thread_call_enter(extraSleepTimer
);
1929 DLOG("idle timer set for %u seconds\n", inSeconds
);
1932 //******************************************************************************
1933 // cancelIdleSleepTimer
1935 //******************************************************************************
1937 void IOPMrootDomain::cancelIdleSleepTimer( void )
1940 if (idleSleepTimerPending
)
1942 DLOG("idle timer cancelled\n");
1943 thread_call_cancel(extraSleepTimer
);
1944 idleSleepTimerPending
= false;
1948 //******************************************************************************
1949 // idleSleepTimerExpired
1951 //******************************************************************************
1953 static void idleSleepTimerExpired(
1954 thread_call_param_t us
, thread_call_param_t
)
1956 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
1959 //******************************************************************************
1960 // handleSleepTimerExpiration
1962 // The time between the sleep idle timeout and the next longest one has elapsed.
1963 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1964 //******************************************************************************
1966 void IOPMrootDomain::handleSleepTimerExpiration( void )
1968 if (!getPMworkloop()->inGate())
1970 getPMworkloop()->runAction(
1971 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1972 &IOPMrootDomain::handleSleepTimerExpiration
),
1979 DLOG("sleep timer expired\n");
1982 idleSleepTimerPending
= false;
1984 clock_get_uptime(&time
);
1985 if ((AbsoluteTime_to_scalar(&time
) > autoWakeStart
) &&
1986 (AbsoluteTime_to_scalar(&time
) < autoWakeEnd
))
1988 thread_call_enter_delayed(extraSleepTimer
, *((AbsoluteTime
*) &autoWakeEnd
));
1992 setQuickSpinDownTimeout();
1993 adjustPowerState(true);
1996 //******************************************************************************
1997 // setQuickSpinDownTimeout
1999 //******************************************************************************
2001 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2005 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2008 //******************************************************************************
2009 // restoreUserSpinDownTimeout
2011 //******************************************************************************
2013 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2017 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2020 //******************************************************************************
2023 //******************************************************************************
2026 IOReturn
IOPMrootDomain::sleepSystem( void )
2028 return sleepSystemOptions(NULL
);
2032 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2034 /* sleepSystem is a public function, and may be called by any kernel driver.
2035 * And that's bad - drivers should sleep the system by calling
2036 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2038 * Note that user space app calls to IOPMSleepSystem() will also travel
2039 * this code path and thus be correctly identified as software sleeps.
2042 if (options
&& options
->getObject("OSSwitch"))
2044 // Log specific sleep cause for OS Switch hibernation
2045 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2047 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2052 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2054 static const char * IOPMSleepReasons
[] = {
2056 kIOPMClamshellSleepKey
,
2057 kIOPMPowerButtonSleepKey
,
2058 kIOPMSoftwareSleepKey
,
2059 kIOPMOSSwitchHibernationKey
,
2061 kIOPMLowPowerSleepKey
,
2062 kIOPMThermalEmergencySleepKey
,
2063 kIOPMMaintenanceSleepKey
,
2064 kIOPMSleepServiceExitKey
,
2065 kIOPMDarkWakeThermalEmergencyKey
2068 PMEventDetails
*details
;
2070 if (!checkSystemCanSleep())
2072 // Record why the system couldn't sleep
2073 details
= PMEventDetails::eventDetails(kIOPMEventTypeSleep
, NULL
,
2074 sleepReason
, kIOReturnNotPermitted
);
2076 recordAndReleasePMEvent( details
);
2077 return kIOReturnNotPermitted
;
2080 if (kIOPMSleepReasonDarkWakeThermalEmergency
== sleepReason
)
2081 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
2084 timeline
->setSleepCycleInProgressFlag(true);
2086 // Time to publish a UUID for the Sleep --> Wake cycle
2087 if(pmPowerStateQueue
) {
2088 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
2091 // Log the beginning of system sleep.
2092 details
= PMEventDetails::eventDetails(kIOPMEventTypeSleep
, NULL
,
2093 sleepReason
, kIOReturnSuccess
);
2095 recordAndReleasePMEvent( details
);
2097 // Record sleep cause in IORegistry
2098 lastSleepReason
= sleepReason
;
2099 sleepReason
-= (kIOPMSleepReasonClamshell
- 1);
2100 if (sleepReason
&& (sleepReason
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0]))) {
2101 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[sleepReason
]);
2104 if (pmPowerStateQueue
)
2105 pmPowerStateQueue
->submitPowerEvent(
2106 kPowerEventPolicyStimulus
,
2107 (void *) kStimulusDemandSystemSleep
);
2109 return kIOReturnSuccess
;
2112 IOReturn
IOPMrootDomain::recordPMEventGated(PMEventDetails
*record
)
2114 // If we don't have a place to log to, we can't actually
2115 // log anything. Chances are, the person who is asking us to do
2116 // the PM logging has forgotten to set the right bootflags
2118 return kIOReturnSuccess
;
2120 if(gIOPMWorkLoop
->inGate() == false) {
2122 IOReturn ret
= gIOPMWorkLoop
->runAction(
2123 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::recordPMEventGated
),
2130 // Now that we're guaranteed to be running in gate ...
2132 // Check the validity of the argument we are given
2134 return kIOReturnBadArgument
;
2136 // Record a driver event, or a system event
2137 if(record
->eventClassifier
== kIOPMEventClassDriverEvent
2138 || record
->eventClassifier
== kIOPMEventClassSystemEvent
)
2139 return this->recordPMEvent(record
);
2142 return kIOReturnBadArgument
;
2146 IOReturn
IOPMrootDomain::recordAndReleasePMEventGated(PMEventDetails
*record
)
2148 IOReturn ret
= kIOReturnBadArgument
;
2152 ret
= recordPMEventGated(record
);
2159 //******************************************************************************
2162 // This overrides powerChangeDone in IOService.
2163 //******************************************************************************
2165 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2167 PMEventDetails
*details
;
2170 DLOG("PowerChangeDone: %u->%u\n",
2171 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2173 switch ( getPowerState() )
2176 if (previousPowerState
!= ON_STATE
)
2179 details
= PMEventDetails::eventDetails(
2180 kIOPMEventTypeSleepDone
,
2185 recordAndReleasePMEvent( details
);
2187 // re-enable this timer for next sleep
2188 cancelIdleSleepTimer();
2191 clock_usec_t microsecs
;
2192 clock_get_calendar_microtime(&secs
, µsecs
);
2194 gIOLastSleepTime
.tv_sec
= secs
;
2195 gIOLastSleepTime
.tv_usec
= microsecs
;
2196 gIOLastWakeTime
.tv_sec
= 0;
2197 gIOLastWakeTime
.tv_usec
= 0;
2200 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2202 IOHibernateSystemHasSlept();
2204 evaluateSystemSleepPolicyFinal();
2206 LOG("System Sleep\n");
2209 getPlatform()->sleepKernel();
2211 // The CPU(s) are off at this point,
2212 // Code will resume execution here upon wake.
2214 clock_get_uptime(&systemWakeTime
);
2215 _highestCapability
= 0;
2218 IOHibernateSystemWake();
2221 // sleep transition complete
2222 gSleepOrShutdownPending
= 0;
2224 // trip the reset of the calendar clock
2225 clock_wakeup_calendar();
2228 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2232 PMDebug(kPMLogSystemWake
, 0, 0);
2233 lowBatteryCondition
= false;
2234 lastSleepReason
= 0;
2236 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2237 _debugWakeSeconds
= 0;
2238 _scheduledAlarms
= 0;
2240 // And start logging the wake event here
2241 // TODO: Publish the wakeReason string as an integer
2242 details
= PMEventDetails::eventDetails(
2248 recordAndReleasePMEvent( details
);
2254 #if defined(__i386__) || defined(__x86_64__)
2255 wranglerTickled
= false;
2256 graphicsSuppressed
= false;
2257 darkWakePostTickle
= false;
2258 logGraphicsClamp
= true;
2259 logWranglerTickle
= true;
2260 sleepTimerMaintenance
= false;
2261 wranglerTickleLatched
= false;
2262 darkWakeThermalAlarm
= false;
2263 darkWakeThermalEmergency
= false;
2265 OSString
* wakeType
= OSDynamicCast(
2266 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2267 OSString
* wakeReason
= OSDynamicCast(
2268 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2270 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2272 lowBatteryCondition
= true;
2273 darkWakeMaintenance
= true;
2274 darkWakeToSleepASAP
= true;
2276 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2278 OSNumber
* hibOptions
= OSDynamicCast(
2279 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2281 if (hibernateAborted
|| ((hibOptions
&&
2282 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2284 // Hibernate aborted, or EFI brought up graphics
2285 wranglerTickled
= true;
2289 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2290 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2292 // User wake or RTC alarm
2293 wranglerTickled
= true;
2297 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2299 // SMC standby timer trumps SleepX
2300 darkWakeMaintenance
= true;
2301 darkWakeToSleepASAP
= true;
2302 sleepTimerMaintenance
= true;
2305 if ((_lastDebugWakeSeconds
!= 0) &&
2306 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2308 // SleepX before maintenance
2309 wranglerTickled
= true;
2313 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2315 darkWakeMaintenance
= true;
2316 darkWakeToSleepASAP
= true;
2320 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2322 darkWakeToSleepASAP
= true;
2323 // darkWakeMaintenance = true; // ????
2324 darkWakeSleepService
= true;
2328 // Unidentified wake source, resume to full wake if debug
2329 // alarm is pending.
2331 if (_lastDebugWakeSeconds
&&
2332 (!wakeReason
|| wakeReason
->isEqualTo("")))
2333 wranglerTickled
= true;
2335 darkWakeToSleepASAP
= true;
2341 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2343 darkWakeMaintenance
= true;
2344 darkWakeToSleepASAP
= true;
2345 sleepTimerMaintenance
= true;
2347 else if (hibernateAborted
|| !wakeType
||
2348 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2349 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2351 // Post a HID tickle immediately - except for RTC maintenance wake.
2352 wranglerTickled
= true;
2356 darkWakeMaintenance
= true;
2357 darkWakeToSleepASAP
= true;
2361 if (wranglerTickled
)
2363 else if (!darkWakeMaintenance
)
2365 // Early/late tickle for non-maintenance wake.
2366 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2367 kDarkWakeFlagHIDTickleEarly
) ||
2368 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2369 kDarkWakeFlagHIDTickleLate
))
2371 darkWakePostTickle
= true;
2374 #else /* !__i386__ && !__x86_64__ */
2375 // stay awake for at least 30 seconds
2376 wranglerTickled
= true;
2377 startIdleSleepTimer(30);
2380 changePowerStateToPriv(ON_STATE
);
2384 if (previousPowerState
!= ON_STATE
)
2386 details
= PMEventDetails::eventDetails(
2387 kIOPMEventTypeWakeDone
,
2392 recordAndReleasePMEvent( details
);
2398 //******************************************************************************
2399 // requestPowerDomainState
2401 // Extend implementation in IOService. Running on PM work loop thread.
2402 //******************************************************************************
2404 IOReturn
IOPMrootDomain::requestPowerDomainState (
2405 IOPMPowerFlags childDesire
,
2406 IOPowerConnection
* childConnection
,
2407 unsigned long specification
)
2409 // Idle and system sleep prevention flags affects driver desire.
2410 // Children desire are irrelevant so they are cleared.
2412 return super::requestPowerDomainState(0, childConnection
, specification
);
2415 //******************************************************************************
2416 // updatePreventIdleSleepList
2418 // Called by IOService on PM work loop.
2419 //******************************************************************************
2421 void IOPMrootDomain::updatePreventIdleSleepList(
2422 IOService
* service
, bool addNotRemove
)
2424 unsigned int oldCount
, newCount
;
2428 // Disregard disk I/O (anything besides the display wrangler)
2429 // as a factor preventing idle sleep,except in the case of legacy disk I/O
2431 if ((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOAlways
) &&
2432 addNotRemove
&& (service
!= wrangler
) && (service
!= this))
2437 oldCount
= preventIdleSleepList
->getCount();
2440 preventIdleSleepList
->setObject(service
);
2441 DLOG("prevent idle sleep list: %s+ (%u)\n",
2442 service
->getName(), preventIdleSleepList
->getCount());
2444 else if (preventIdleSleepList
->member(service
))
2446 preventIdleSleepList
->removeObject(service
);
2447 DLOG("prevent idle sleep list: %s- (%u)\n",
2448 service
->getName(), preventIdleSleepList
->getCount());
2450 newCount
= preventIdleSleepList
->getCount();
2452 if ((oldCount
== 0) && (newCount
!= 0))
2454 // Driver added to empty prevent list.
2455 // Update the driver desire to prevent idle sleep.
2456 // Driver desire does not prevent demand sleep.
2458 changePowerStateTo(ON_STATE
);
2460 else if ((oldCount
!= 0) && (newCount
== 0))
2462 // Last driver removed from prevent list.
2463 // Drop the driver clamp to allow idle sleep.
2465 changePowerStateTo(SLEEP_STATE
);
2466 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2470 //******************************************************************************
2471 // preventSystemSleepListUpdate
2473 // Called by IOService on PM work loop.
2474 //******************************************************************************
2476 void IOPMrootDomain::updatePreventSystemSleepList(
2477 IOService
* service
, bool addNotRemove
)
2479 unsigned int oldCount
;
2482 if (this == service
)
2485 oldCount
= preventSystemSleepList
->getCount();
2488 preventSystemSleepList
->setObject(service
);
2489 DLOG("prevent system sleep list: %s+ (%u)\n",
2490 service
->getName(), preventSystemSleepList
->getCount());
2492 else if (preventSystemSleepList
->member(service
))
2494 preventSystemSleepList
->removeObject(service
);
2495 DLOG("prevent system sleep list: %s- (%u)\n",
2496 service
->getName(), preventSystemSleepList
->getCount());
2498 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2500 // Lost all system sleep preventers.
2501 // Send stimulus if system sleep was blocked, and is in dark wake.
2502 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2507 //******************************************************************************
2510 // Override the superclass implementation to send a different message type.
2511 //******************************************************************************
2513 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2515 DLOG("tellChangeDown %u->%u\n",
2516 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2518 if (SLEEP_STATE
== stateNum
)
2520 if (!ignoreTellChangeDown
)
2521 tracePoint( kIOPMTracePointSleepApplications
);
2523 tracePoint( kIOPMTracePointSleepPriorityClients
);
2526 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2528 userActivityAtSleep
= userActivityCount
;
2529 hibernateAborted
= false;
2530 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2532 // Direct callout into OSKext so it can disable kext unloads
2533 // during sleep/wake to prevent deadlocks.
2534 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2536 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2538 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2539 // But tellClientsWithResponse() must be called for both.
2540 ignoreTellChangeDown
= true;
2543 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2546 //******************************************************************************
2549 // Override the superclass implementation to send a different message type.
2550 // This must be idle sleep since we don't ask during any other power change.
2551 //******************************************************************************
2553 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2555 DLOG("askChangeDown %u->%u\n",
2556 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2558 // Don't log for dark wake entry
2559 if (kSystemTransitionSleep
== _systemTransitionType
)
2560 tracePoint( kIOPMTracePointSleepApplications
);
2562 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2565 //******************************************************************************
2566 // askChangeDownDone
2568 // Called by PM after all apps have responded to kIOMessageCanSystemSleep.
2569 // pmconfigd may create a deny sleep assertion before ack'ing.
2570 //******************************************************************************
2572 void IOPMrootDomain::askChangeDownDone(
2573 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2575 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2576 *inOutChangeFlags
, *cancel
,
2577 _systemTransitionType
,
2578 _currentCapability
, _pendingCapability
);
2580 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2582 // Dark->Sleep transition.
2583 // Check if there are any deny sleep assertions.
2584 // Full->Dark transition is never cancelled.
2586 if (!checkSystemCanSleep(true))
2588 // Cancel dark wake to sleep transition.
2589 // Must re-scan assertions upon entering dark wake.
2592 DLOG("cancel dark->sleep\n");
2597 //******************************************************************************
2600 // Notify registered applications and kernel clients that we are not dropping
2603 // We override the superclass implementation so we can send a different message
2604 // type to the client or application being notified.
2606 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2607 //******************************************************************************
2609 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2611 DLOG("tellNoChangeDown %u->%u\n",
2612 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2614 // Sleep canceled, clear the sleep trace point.
2615 tracePoint(kIOPMTracePointSystemUp
);
2621 // stay awake for at least idleSeconds
2622 startIdleSleepTimer(idleSeconds
);
2625 else if (sleepSlider
&& wranglerAsleep
)
2627 // Display wrangler is already asleep, it won't trigger the next
2628 // idle sleep attempt. Schedule a future idle sleep attempt, and
2629 // also push out the next idle sleep attempt.
2631 startIdleSleepTimer( kIdleSleepRetryInterval
);
2634 IOService::setAdvisoryTickleEnable( true );
2635 return tellClients( kIOMessageSystemWillNotSleep
);
2638 //******************************************************************************
2641 // Notify registered applications and kernel clients that we are raising power.
2643 // We override the superclass implementation so we can send a different message
2644 // type to the client or application being notified.
2645 //******************************************************************************
2647 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2650 DLOG("tellChangeUp %u->%u\n",
2651 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2653 ignoreTellChangeDown
= false;
2655 if ( stateNum
== ON_STATE
)
2657 // Direct callout into OSKext so it can disable kext unloads
2658 // during sleep/wake to prevent deadlocks.
2659 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2661 // Notify platform that sleep was cancelled or resumed.
2662 getPlatform()->callPlatformFunction(
2663 sleepMessagePEFunction
, false,
2664 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2667 if (getPowerState() == ON_STATE
)
2669 // this is a quick wake from aborted sleep
2670 if (idleSeconds
&& !wrangler
)
2672 // stay awake for at least idleSeconds
2673 startIdleSleepTimer(idleSeconds
);
2675 IOService::setAdvisoryTickleEnable( true );
2676 tellClients( kIOMessageSystemWillPowerOn
);
2679 tracePoint( kIOPMTracePointWakeApplications
);
2681 if (pmStatsAppResponses
)
2683 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
2684 pmStatsAppResponses
->release();
2685 pmStatsAppResponses
= OSArray::withCapacity(5);
2688 tellClients( kIOMessageSystemHasPoweredOn
);
2692 //******************************************************************************
2693 // sysPowerDownHandler
2695 // Perform a vfs sync before system sleep.
2696 //******************************************************************************
2698 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2699 void * target
, void * refCon
,
2700 UInt32 messageType
, IOService
* service
,
2701 void * messageArgs
, vm_size_t argSize
)
2705 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2708 return kIOReturnUnsupported
;
2710 if (messageType
== kIOMessageSystemCapabilityChange
)
2712 IOPMSystemCapabilityChangeParameters
* params
=
2713 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2715 // Interested applications have been notified of an impending power
2716 // change and have acked (when applicable).
2717 // This is our chance to save whatever state we can before powering
2719 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2722 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2723 params
->fromCapabilities
, params
->toCapabilities
,
2724 params
->changeFlags
);
2726 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2727 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2728 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2730 // We will ack within 20 seconds
2731 params
->maxWaitForReply
= 20 * 1000 * 1000;
2733 gRootDomain
->evaluateSystemSleepPolicyEarly();
2735 // add in time we could spend freeing pages
2736 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2738 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2740 DLOG("sysPowerDownHandler timeout %d s\n", (int) (params
->maxWaitForReply
/ 1000 / 1000));
2743 // Notify platform that sleep has begun, after the early
2744 // sleep policy evaluation.
2745 getPlatform()->callPlatformFunction(
2746 sleepMessagePEFunction
, false,
2747 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2750 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2752 // Purposely delay the ack and hope that shutdown occurs quickly.
2753 // Another option is not to schedule the thread and wait for
2755 AbsoluteTime deadline
;
2756 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2757 thread_call_enter1_delayed(
2758 gRootDomain
->diskSyncCalloutEntry
,
2759 (thread_call_param_t
) params
->notifyRef
,
2764 gRootDomain
->diskSyncCalloutEntry
,
2765 (thread_call_param_t
) params
->notifyRef
);
2769 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2770 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2771 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2773 // We will ack within 110 seconds
2774 params
->maxWaitForReply
= 110 * 1000 * 1000;
2777 gRootDomain
->diskSyncCalloutEntry
,
2778 (thread_call_param_t
) params
->notifyRef
);
2781 ret
= kIOReturnSuccess
;
2787 //******************************************************************************
2788 // handleQueueSleepWakeUUID
2790 // Called from IOPMrootDomain when we're initiating a sleep,
2791 // or indirectly from PM configd when PM decides to clear the UUID.
2792 // PM clears the UUID several minutes after successful wake from sleep,
2793 // so that we might associate App spindumps with the immediately previous
2796 // @param obj has a retain on it. We're responsible for releasing that retain.
2797 //******************************************************************************
2799 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2801 OSString
*str
= NULL
;
2803 if (kOSBooleanFalse
== obj
)
2805 handlePublishSleepWakeUUID(NULL
);
2807 else if ((str
= OSDynamicCast(OSString
, obj
)))
2809 // This branch caches the UUID for an upcoming sleep/wake
2810 if (queuedSleepWakeUUIDString
) {
2811 queuedSleepWakeUUIDString
->release();
2812 queuedSleepWakeUUIDString
= NULL
;
2814 queuedSleepWakeUUIDString
= str
;
2815 queuedSleepWakeUUIDString
->retain();
2817 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2826 //******************************************************************************
2827 // handlePublishSleepWakeUUID
2829 // Called from IOPMrootDomain when we're initiating a sleep,
2830 // or indirectly from PM configd when PM decides to clear the UUID.
2831 // PM clears the UUID several minutes after successful wake from sleep,
2832 // so that we might associate App spindumps with the immediately previous
2834 //******************************************************************************
2836 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2841 * Clear the current UUID
2843 if (gSleepWakeUUIDIsSet
)
2845 DLOG("SleepWake UUID cleared\n");
2847 OSString
*UUIDstring
= NULL
;
2850 (UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))))
2852 PMEventDetails
*details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDClear
,
2853 UUIDstring
->getCStringNoCopy(), NULL
, 0);
2855 timeline
->recordSystemPowerEvent( details
);
2858 timeline
->setNumEventsLoggedThisPeriod(0);
2861 gSleepWakeUUIDIsSet
= false;
2863 removeProperty(kIOPMSleepWakeUUIDKey
);
2864 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2868 * Optionally, publish a new UUID
2870 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2872 OSString
*publishThisUUID
= NULL
;
2874 publishThisUUID
= queuedSleepWakeUUIDString
;
2875 publishThisUUID
->retain();
2878 PMEventDetails
*details
;
2879 details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDSet
,
2880 publishThisUUID
->getCStringNoCopy(), NULL
, 0);
2882 timeline
->recordSystemPowerEvent( details
);
2887 if (publishThisUUID
)
2889 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
2890 publishThisUUID
->release();
2893 gSleepWakeUUIDIsSet
= true;
2894 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
2896 queuedSleepWakeUUIDString
->release();
2897 queuedSleepWakeUUIDString
= NULL
;
2901 //******************************************************************************
2902 // changePowerStateTo & changePowerStateToPriv
2904 // Override of these methods for logging purposes.
2905 //******************************************************************************
2907 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
2909 DLOG("changePowerStateTo(%lu)\n", ordinal
);
2911 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2912 return kIOReturnUnsupported
;
2914 return super::changePowerStateTo(ordinal
);
2917 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
2919 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
2921 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2922 return kIOReturnUnsupported
;
2924 return super::changePowerStateToPriv(ordinal
);
2927 //******************************************************************************
2930 //******************************************************************************
2932 bool IOPMrootDomain::activitySinceSleep(void)
2934 return (userActivityCount
!= userActivityAtSleep
);
2937 bool IOPMrootDomain::abortHibernation(void)
2939 bool ret
= activitySinceSleep();
2941 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
2943 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
2944 hibernateAborted
= true;
2950 hibernate_should_abort(void)
2953 return (gRootDomain
->abortHibernation());
2958 //******************************************************************************
2959 // sleepOnClamshellClosed
2961 // contains the logic to determine if the system should sleep when the clamshell
2963 //******************************************************************************
2965 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2967 if (!clamshellExists
)
2970 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
2971 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
2973 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
2976 void IOPMrootDomain::sendClientClamshellNotification( void )
2978 /* Only broadcast clamshell alert if clamshell exists. */
2979 if (!clamshellExists
)
2982 setProperty(kAppleClamshellStateKey
,
2983 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
2985 setProperty(kAppleClamshellCausesSleepKey
,
2986 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
2988 /* Argument to message is a bitfiel of
2989 * ( kClamshellStateBit | kClamshellSleepBit )
2991 messageClients(kIOPMMessageClamshellStateChange
,
2992 (void *) ( (clamshellClosed
? kClamshellStateBit
: 0)
2993 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
2996 //******************************************************************************
2997 // getSleepSupported
3000 //******************************************************************************
3002 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3004 return( platformSleepSupport
);
3007 //******************************************************************************
3008 // setSleepSupported
3011 //******************************************************************************
3013 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3015 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3016 OSBitOrAtomic(flags
, &platformSleepSupport
);
3019 //******************************************************************************
3020 // setDisableClamShellSleep
3022 //******************************************************************************
3024 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3026 if (gIOPMWorkLoop
->inGate() == false) {
3028 gIOPMWorkLoop
->runAction(
3029 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3036 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3037 if ( clamshellSleepDisabled
!= val
)
3039 clamshellSleepDisabled
= val
;
3040 // If clamshellSleepDisabled is reset to 0, reevaluate if
3041 // system need to go to sleep due to clamshell state
3042 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3043 handlePowerNotification(kLocalEvalClamshellCommand
);
3048 //******************************************************************************
3052 //******************************************************************************
3054 void IOPMrootDomain::wakeFromDoze( void )
3056 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3062 //******************************************************************************
3065 // Adds a new feature to the supported features dictionary
3066 //******************************************************************************
3068 void IOPMrootDomain::publishFeature( const char * feature
)
3070 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3073 //******************************************************************************
3074 // publishFeature (with supported power source specified)
3076 // Adds a new feature to the supported features dictionary
3077 //******************************************************************************
3079 void IOPMrootDomain::publishFeature(
3080 const char *feature
,
3081 uint32_t supportedWhere
,
3082 uint32_t *uniqueFeatureID
)
3084 static uint16_t next_feature_id
= 500;
3086 OSNumber
*new_feature_data
= NULL
;
3087 OSNumber
*existing_feature
= NULL
;
3088 OSArray
*existing_feature_arr
= NULL
;
3089 OSObject
*osObj
= NULL
;
3090 uint32_t feature_value
= 0;
3092 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3094 if(!supportedWhere
) {
3095 // Feature isn't supported anywhere!
3099 if(next_feature_id
> 5000) {
3100 // Far, far too many features!
3104 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3106 OSDictionary
*features
=
3107 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3109 // Create new features dict if necessary
3110 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3111 features
= OSDictionary::withDictionary(features
);
3113 features
= OSDictionary::withCapacity(1);
3116 // Create OSNumber to track new feature
3118 next_feature_id
+= 1;
3119 if( uniqueFeatureID
) {
3120 // We don't really mind if the calling kext didn't give us a place
3121 // to stash their unique id. Many kexts don't plan to unload, and thus
3122 // have no need to remove themselves later.
3123 *uniqueFeatureID
= next_feature_id
;
3126 feature_value
= (uint32_t)next_feature_id
;
3127 feature_value
<<= 16;
3128 feature_value
+= supportedWhere
;
3130 new_feature_data
= OSNumber::withNumber(
3131 (unsigned long long)feature_value
, 32);
3133 // Does features object already exist?
3134 if( (osObj
= features
->getObject(feature
)) )
3136 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3138 // We need to create an OSArray to hold the now 2 elements.
3139 existing_feature_arr
= OSArray::withObjects(
3140 (const OSObject
**)&existing_feature
, 1, 2);
3141 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3143 // Add object to existing array
3144 existing_feature_arr
= OSArray::withArray(
3145 existing_feature_arr
,
3146 existing_feature_arr
->getCount() + 1);
3149 if (existing_feature_arr
)
3151 existing_feature_arr
->setObject(new_feature_data
);
3152 features
->setObject(feature
, existing_feature_arr
);
3153 existing_feature_arr
->release();
3154 existing_feature_arr
= 0;
3157 // The easy case: no previously existing features listed. We simply
3158 // set the OSNumber at key 'feature' and we're on our way.
3159 features
->setObject(feature
, new_feature_data
);
3162 new_feature_data
->release();
3164 setProperty(kRootDomainSupportedFeatures
, features
);
3166 features
->release();
3168 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3170 // Notify EnergySaver and all those in user space so they might
3171 // re-populate their feature specific UI
3172 if(pmPowerStateQueue
) {
3173 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3177 //******************************************************************************
3178 // removePublishedFeature
3180 // Removes previously published feature
3181 //******************************************************************************
3183 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3185 IOReturn ret
= kIOReturnError
;
3186 uint32_t feature_value
= 0;
3187 uint16_t feature_id
= 0;
3188 bool madeAChange
= false;
3190 OSSymbol
*dictKey
= NULL
;
3191 OSCollectionIterator
*dictIterator
= NULL
;
3192 OSArray
*arrayMember
= NULL
;
3193 OSNumber
*numberMember
= NULL
;
3194 OSObject
*osObj
= NULL
;
3195 OSNumber
*osNum
= NULL
;
3196 OSArray
*arrayMemberCopy
;
3198 if (kBadPMFeatureID
== removeFeatureID
)
3199 return kIOReturnNotFound
;
3201 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3203 OSDictionary
*features
=
3204 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3206 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3208 // Any modifications to the dictionary are made to the copy to prevent
3209 // races & crashes with userland clients. Dictionary updated
3210 // automically later.
3211 features
= OSDictionary::withDictionary(features
);
3214 ret
= kIOReturnNotFound
;
3218 // We iterate 'features' dictionary looking for an entry tagged
3219 // with 'removeFeatureID'. If found, we remove it from our tracking
3220 // structures and notify the OS via a general interest message.
3222 dictIterator
= OSCollectionIterator::withCollection(features
);
3227 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3229 osObj
= features
->getObject(dictKey
);
3231 // Each Feature is either tracked by an OSNumber
3232 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3234 feature_value
= numberMember
->unsigned32BitValue();
3235 feature_id
= (uint16_t)(feature_value
>> 16);
3237 if( feature_id
== (uint16_t)removeFeatureID
)
3240 features
->removeObject(dictKey
);
3245 // Or tracked by an OSArray of OSNumbers
3246 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3248 unsigned int arrayCount
= arrayMember
->getCount();
3250 for(unsigned int i
=0; i
<arrayCount
; i
++)
3252 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3257 feature_value
= osNum
->unsigned32BitValue();
3258 feature_id
= (uint16_t)(feature_value
>> 16);
3260 if( feature_id
== (uint16_t)removeFeatureID
)
3263 if( 1 == arrayCount
) {
3264 // If the array only contains one element, remove
3266 features
->removeObject(dictKey
);
3268 // Otherwise remove the element from a copy of the array.
3269 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3270 if (arrayMemberCopy
)
3272 arrayMemberCopy
->removeObject(i
);
3273 features
->setObject(dictKey
, arrayMemberCopy
);
3274 arrayMemberCopy
->release();
3285 dictIterator
->release();
3289 ret
= kIOReturnSuccess
;
3291 setProperty(kRootDomainSupportedFeatures
, features
);
3293 // Notify EnergySaver and all those in user space so they might
3294 // re-populate their feature specific UI
3295 if(pmPowerStateQueue
) {
3296 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3299 ret
= kIOReturnNotFound
;
3303 if(features
) features
->release();
3304 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3308 //******************************************************************************
3309 // publishPMSetting (private)
3311 // Should only be called by PMSettingObject to publish a PM Setting as a
3312 // supported feature.
3313 //******************************************************************************
3315 void IOPMrootDomain::publishPMSetting(
3316 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3318 if (noPublishPMSettings
&&
3319 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3321 // Setting found in noPublishPMSettings array
3322 *featureID
= kBadPMFeatureID
;
3327 feature
->getCStringNoCopy(), where
, featureID
);
3330 //******************************************************************************
3331 // setPMSetting (private)
3333 // Internal helper to relay PM settings changes from user space to individual
3334 // drivers. Should be called only by IOPMrootDomain::setProperties.
3335 //******************************************************************************
3337 IOReturn
IOPMrootDomain::setPMSetting(
3338 const OSSymbol
*type
,
3341 PMSettingCallEntry
*entries
= 0;
3342 OSArray
*chosen
= 0;
3343 const OSArray
*array
;
3344 PMSettingObject
*pmso
;
3345 thread_t thisThread
;
3346 int i
, j
, count
, capacity
;
3349 return kIOReturnBadArgument
;
3353 // Update settings dict so changes are visible from copyPMSetting().
3354 fPMSettingsDict
->setObject(type
, object
);
3356 // Prep all PMSetting objects with the given 'type' for callout.
3357 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3358 if (!array
|| ((capacity
= array
->getCount()) == 0))
3361 // Array to retain PMSetting objects targeted for callout.
3362 chosen
= OSArray::withCapacity(capacity
);
3364 goto unlock_exit
; // error
3366 entries
= IONew(PMSettingCallEntry
, capacity
);
3368 goto unlock_exit
; // error
3369 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3371 thisThread
= current_thread();
3373 for (i
= 0, j
= 0; i
<capacity
; i
++)
3375 pmso
= (PMSettingObject
*) array
->getObject(i
);
3378 entries
[j
].thread
= thisThread
;
3379 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3380 chosen
->setObject(pmso
);
3389 // Call each pmso in the chosen array.
3390 for (i
=0; i
<count
; i
++)
3392 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3393 pmso
->dispatchPMSetting(type
, object
);
3397 for (i
=0; i
<count
; i
++)
3399 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3400 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3401 if (pmso
->waitThread
)
3403 PMSETTING_WAKEUP(pmso
);
3409 if (chosen
) chosen
->release();
3410 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3412 return kIOReturnSuccess
;
3415 //******************************************************************************
3416 // copyPMSetting (public)
3418 // Allows kexts to safely read setting values, without being subscribed to
3420 //******************************************************************************
3422 OSObject
* IOPMrootDomain::copyPMSetting(
3423 OSSymbol
*whichSetting
)
3425 OSObject
*obj
= NULL
;
3427 if(!whichSetting
) return NULL
;
3430 obj
= fPMSettingsDict
->getObject(whichSetting
);
3439 //******************************************************************************
3440 // registerPMSettingController (public)
3442 // direct wrapper to registerPMSettingController with uint32_t power source arg
3443 //******************************************************************************
3445 IOReturn
IOPMrootDomain::registerPMSettingController(
3446 const OSSymbol
* settings
[],
3447 IOPMSettingControllerCallback func
,
3452 return registerPMSettingController(
3454 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3455 func
, target
, refcon
, handle
);
3458 //******************************************************************************
3459 // registerPMSettingController (public)
3461 // Kexts may register for notifications when a particular setting is changed.
3462 // A list of settings is available in IOPM.h.
3464 // * settings - An OSArray containing OSSymbols. Caller should populate this
3465 // array with a list of settings caller wants notifications from.
3466 // * func - A C function callback of the type IOPMSettingControllerCallback
3467 // * target - caller may provide an OSObject *, which PM will pass as an
3468 // target to calls to "func"
3469 // * refcon - caller may provide an void *, which PM will pass as an
3470 // argument to calls to "func"
3471 // * handle - This is a return argument. We will populate this pointer upon
3472 // call success. Hold onto this and pass this argument to
3473 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3475 // kIOReturnSuccess on success
3476 //******************************************************************************
3478 IOReturn
IOPMrootDomain::registerPMSettingController(
3479 const OSSymbol
* settings
[],
3480 uint32_t supportedPowerSources
,
3481 IOPMSettingControllerCallback func
,
3486 PMSettingObject
*pmso
= NULL
;
3487 OSObject
*pmsh
= NULL
;
3488 OSArray
*list
= NULL
;
3491 if (NULL
== settings
||
3495 return kIOReturnBadArgument
;
3498 pmso
= PMSettingObject::pmSettingObject(
3499 (IOPMrootDomain
*) this, func
, target
,
3500 refcon
, supportedPowerSources
, settings
, &pmsh
);
3504 return kIOReturnInternalError
;
3508 for (i
=0; settings
[i
]; i
++)
3510 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3512 // New array of callbacks for this setting
3513 list
= OSArray::withCapacity(1);
3514 settingsCallbacks
->setObject(settings
[i
], list
);
3518 // Add caller to the callback list
3519 list
->setObject(pmso
);
3523 // Return handle to the caller, the setting object is private.
3526 return kIOReturnSuccess
;
3529 //******************************************************************************
3530 // deregisterPMSettingObject (private)
3532 // Only called from PMSettingObject.
3533 //******************************************************************************
3535 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3537 thread_t thisThread
= current_thread();
3538 PMSettingCallEntry
*callEntry
;
3539 OSCollectionIterator
*iter
;
3547 pmso
->disabled
= true;
3549 // Wait for all callout threads to finish.
3552 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3554 if (callEntry
->thread
!= thisThread
)
3562 assert(0 == pmso
->waitThread
);
3563 pmso
->waitThread
= thisThread
;
3564 PMSETTING_WAIT(pmso
);
3565 pmso
->waitThread
= 0;
3569 // Search each PM settings array in the kernel.
3570 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3573 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3575 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3576 index
= array
->getNextIndexOfObject(pmso
, 0);
3578 array
->removeObject(index
);
3589 //******************************************************************************
3590 // informCPUStateChange
3592 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3593 // running on battery, with the lid closed, etc.
3595 // informCPUStateChange is a no-op on non x86 systems
3596 // only x86 has explicit support in the IntelCPUPowerManagement kext
3597 //******************************************************************************
3599 void IOPMrootDomain::informCPUStateChange(
3603 #if defined(__i386__) || defined(__x86_64__)
3605 pmioctlVariableInfo_t varInfoStruct
;
3607 const char *varNameStr
= NULL
;
3608 int32_t *varIndex
= NULL
;
3610 if (kInformAC
== type
) {
3611 varNameStr
= kIOPMRootDomainBatPowerCString
;
3612 varIndex
= &idxPMCPULimitedPower
;
3613 } else if (kInformLid
== type
) {
3614 varNameStr
= kIOPMRootDomainLidCloseCString
;
3615 varIndex
= &idxPMCPUClamshell
;
3620 // Set the new value!
3621 // pmCPUControl will assign us a new ID if one doesn't exist yet
3622 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3623 varInfoStruct
.varID
= *varIndex
;
3624 varInfoStruct
.varType
= vBool
;
3625 varInfoStruct
.varInitValue
= value
;
3626 varInfoStruct
.varCurValue
= value
;
3627 strncpy( (char *)varInfoStruct
.varName
,
3628 (const char *)varNameStr
,
3629 strlen(varNameStr
) + 1 );
3632 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3634 // pmCPU only assigns numerical id's when a new varName is specified
3636 && (*varIndex
== kCPUUnknownIndex
))
3638 // pmCPUControl has assigned us a new variable ID.
3639 // Let's re-read the structure we just SET to learn that ID.
3640 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3644 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3645 *varIndex
= varInfoStruct
.varID
;
3651 #endif /* __i386__ || __x86_64__ */
3655 // MARK: Deep Sleep Policy
3659 //******************************************************************************
3660 // evaluateSystemSleepPolicy
3661 //******************************************************************************
3663 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3667 kIOPMSleepFlagHibernate
= 0x00000001,
3668 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3671 struct IOPMSystemSleepPolicyEntry
3673 uint32_t factorMask
;
3674 uint32_t factorBits
;
3675 uint32_t sleepFlags
;
3676 uint32_t wakeEvents
;
3677 } __attribute__((packed
));
3679 struct IOPMSystemSleepPolicyTable
3683 uint16_t entryCount
;
3684 IOPMSystemSleepPolicyEntry entries
[];
3685 } __attribute__((packed
));
3688 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
3689 kIOPMSleepAttributeHibernateSleep
= 0x00000002
3693 getSleepTypeAttributes( uint32_t sleepType
)
3695 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
3700 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
3701 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3702 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3703 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3707 if (sleepType
>= kIOPMSleepTypeLast
)
3710 return sleepTypeAttributes
[sleepType
];
3713 bool IOPMrootDomain::evaluateSystemSleepPolicy(
3714 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
3716 const IOPMSystemSleepPolicyTable
* pt
;
3717 OSObject
* prop
= 0;
3718 OSData
* policyData
;
3719 uint64_t currentFactors
= 0;
3720 uint32_t standbyDelay
= 0;
3721 uint32_t powerOffDelay
= 0;
3722 uint32_t powerOffTimer
= 0;
3724 bool standbyEnabled
;
3725 bool powerOffEnabled
;
3728 // Get platform's sleep policy table
3729 if (!gSleepPolicyHandler
)
3731 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3732 if (!prop
) goto done
;
3735 // Fetch additional settings
3736 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
3737 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
3738 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
3739 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
3740 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
3741 powerOffTimer
= powerOffDelay
;
3743 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
3744 sleepPhase
, standbyEnabled
, standbyDelay
,
3745 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
3747 // pmset level overrides
3748 if ((*hibMode
& kIOHibernateModeOn
) == 0)
3750 if (!gSleepPolicyHandler
)
3752 standbyEnabled
= false;
3753 powerOffEnabled
= false;
3756 else if (!(*hibMode
& kIOHibernateModeSleep
))
3758 // Force hibernate (i.e. mode 25)
3759 // If standby is enabled, force standy.
3760 // If poweroff is enabled, force poweroff.
3762 currentFactors
|= kIOPMSleepFactorStandbyForced
;
3763 else if (powerOffEnabled
)
3764 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
3766 currentFactors
|= kIOPMSleepFactorHibernateForced
;
3769 // Current factors based on environment and assertions
3770 if (sleepTimerMaintenance
)
3771 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3772 if (!clamshellClosed
)
3773 currentFactors
|= kIOPMSleepFactorLidOpen
;
3774 if (acAdaptorConnected
)
3775 currentFactors
|= kIOPMSleepFactorACPower
;
3776 if (lowBatteryCondition
)
3777 currentFactors
|= kIOPMSleepFactorBatteryLow
;
3779 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
3780 if (!standbyEnabled
)
3781 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
3782 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3783 kIOPMDriverAssertionLevelOff
)
3784 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3785 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3786 kIOPMDriverAssertionLevelOff
)
3787 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3788 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3789 kIOPMDriverAssertionLevelOff
)
3790 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3791 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
3792 kIOPMDriverAssertionLevelOff
)
3793 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
3794 if (_scheduledAlarms
!= 0)
3795 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
3796 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
3797 kIOPMDriverAssertionLevelOff
)
3798 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
3799 if (!powerOffEnabled
)
3800 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
3802 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
3804 DLOG("sleep factors 0x%llx\n", currentFactors
);
3806 if (gSleepPolicyHandler
)
3808 uint32_t savedHibernateMode
;
3811 if (!gSleepPolicyVars
)
3813 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
3814 if (!gSleepPolicyVars
)
3816 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
3818 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
3819 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
3820 gSleepPolicyVars
->currentCapability
= _currentCapability
;
3821 gSleepPolicyVars
->highestCapability
= _highestCapability
;
3822 gSleepPolicyVars
->sleepFactors
= currentFactors
;
3823 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
3824 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
3825 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
3826 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
3827 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
3828 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
3830 if (kIOPMSleepPhase0
== sleepPhase
)
3832 // preserve hibernateMode
3833 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
3834 gSleepPolicyVars
->hibernateMode
= *hibMode
;
3836 else if (kIOPMSleepPhase1
== sleepPhase
)
3838 // use original hibernateMode for phase2
3839 gSleepPolicyVars
->hibernateMode
= *hibMode
;
3842 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
3844 if (kIOPMSleepPhase0
== sleepPhase
)
3846 // restore hibernateMode
3847 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
3850 if ((result
!= kIOReturnSuccess
) ||
3851 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
3852 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
3853 (kIOPMSystemSleepParametersVersion
!= params
->version
))
3855 MSG("sleep policy handler error\n");
3859 if ((getSleepTypeAttributes(params
->sleepType
) &
3860 kIOPMSleepAttributeHibernateSetup
) &&
3861 ((*hibMode
& kIOHibernateModeOn
) == 0))
3863 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
3866 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
3867 params
->version
, params
->sleepType
, params
->sleepFlags
,
3868 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
3873 // Policy table is meaningless without standby enabled
3874 if (!standbyEnabled
)
3877 // Validate the sleep policy table
3878 policyData
= OSDynamicCast(OSData
, prop
);
3879 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
3882 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
3883 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
3884 (pt
->version
!= 1) || (0 == pt
->entryCount
))
3887 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
3888 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
3891 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
3893 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
3894 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
3896 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
3897 entry
->factorMask
, entry
->factorBits
,
3898 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
3902 DLOG("^ found match\n");
3905 params
->version
= kIOPMSystemSleepParametersVersion
;
3906 params
->reserved1
= 1;
3907 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
3908 params
->sleepType
= kIOPMSleepTypeStandby
;
3910 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
3912 params
->ecWakeEvents
= entry
->wakeEvents
;
3913 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
3915 if (kIOPMSleepPhase2
== sleepPhase
)
3917 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
3919 if (!_standbyTimerResetSeconds
||
3920 (now_secs
<= _standbyTimerResetSeconds
))
3922 // Reset standby timer adjustment
3923 _standbyTimerResetSeconds
= now_secs
;
3924 DLOG("standby delay %u, reset %u\n",
3925 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
3927 else if (standbyDelay
)
3929 // Shorten the standby delay timer
3930 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
3931 if (standbyDelay
> elapsed
)
3932 standbyDelay
-= elapsed
;
3934 standbyDelay
= 1; // must be > 0
3936 DLOG("standby delay %u, elapsed %u\n",
3937 standbyDelay
, (uint32_t) elapsed
);
3940 params
->ecWakeTimer
= standbyDelay
;
3942 else if (kIOPMSleepPhase2
== sleepPhase
)
3944 // A sleep that does not enable the sleep timer will reset
3945 // the standby delay adjustment.
3946 _standbyTimerResetSeconds
= 0;
3958 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
3960 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
3962 // Evaluate early (priority interest phase), before drivers sleep.
3964 DLOG("%s\n", __FUNCTION__
);
3965 removeProperty(kIOPMSystemSleepParametersKey
);
3967 // Full wake resets the standby timer delay adjustment
3968 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
3969 _standbyTimerResetSeconds
= 0;
3971 hibernateDisabled
= false;
3973 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
3975 // Save for late evaluation if sleep is aborted
3976 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
3978 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
3981 if (!hibernateNoDefeat
&&
3982 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
3983 kIOPMSleepAttributeHibernateSetup
) == 0))
3985 // skip hibernate setup
3986 hibernateDisabled
= true;
3990 // Publish IOPMSystemSleepType
3991 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
3992 if (sleepType
== kIOPMSleepTypeInvalid
)
3995 sleepType
= kIOPMSleepTypeNormalSleep
;
3996 if (hibernateMode
& kIOHibernateModeOn
)
3997 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
3998 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4000 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4001 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4003 // report the lowest possible sleep state
4004 sleepType
= kIOPMSleepTypePowerOff
;
4007 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4010 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4012 IOPMSystemSleepParameters params
;
4013 OSData
* paramsData
;
4015 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4017 DLOG("%s\n", __FUNCTION__
);
4019 bzero(¶ms
, sizeof(params
));
4020 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4022 if ((hibernateDisabled
|| hibernateAborted
) &&
4023 (getSleepTypeAttributes(params
.sleepType
) &
4024 kIOPMSleepAttributeHibernateSetup
))
4026 // Final evaluation picked a state requiring hibernation,
4027 // but hibernate setup was skipped. Retry using the early
4028 // sleep parameters.
4030 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4031 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4032 params
.ecWakeTimer
= 1;
4033 hibernateNoDefeat
= true;
4034 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
4035 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
);
4039 hibernateNoDefeat
= false;
4042 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4045 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4046 paramsData
->release();
4049 if (getSleepTypeAttributes(params
.sleepType
) &
4050 kIOPMSleepAttributeHibernateSleep
)
4052 // Disable sleep to force hibernation
4053 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4058 bool IOPMrootDomain::getHibernateSettings(
4059 uint32_t * hibernateModePtr
,
4060 uint32_t * hibernateFreeRatio
,
4061 uint32_t * hibernateFreeTime
)
4063 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4064 // has updated the hibernateDisabled flag.
4066 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4067 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4068 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4069 if (hibernateDisabled
)
4070 *hibernateModePtr
= 0;
4071 else if (gSleepPolicyHandler
)
4072 *hibernateModePtr
= hibernateMode
;
4073 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4077 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4079 OSObject
* optionsProp
;
4080 OSDictionary
* optionsDict
;
4085 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4086 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4090 obj
= optionsDict
->getObject(key
);
4091 if (obj
) obj
->retain();
4095 obj
= copyProperty(key
);
4097 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)))
4099 *option
= num
->unsigned32BitValue();
4106 optionsProp
->release();
4110 #endif /* HIBERNATION */
4112 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
)
4115 IOPMSystemSleepParameters params
;
4116 uint32_t hibMode
= 0;
4119 if (gIOPMWorkLoop
->inGate() == false)
4121 IOReturn ret
= gIOPMWorkLoop
->runAction(
4122 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4123 &IOPMrootDomain::getSystemSleepType
),
4125 (void *) sleepType
);
4129 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4130 bzero(¶ms
, sizeof(params
));
4132 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4135 *sleepType
= params
.sleepType
;
4136 return kIOReturnSuccess
;
4140 return kIOReturnUnsupported
;
4144 // MARK: Shutdown and Restart
4146 //******************************************************************************
4147 // handlePlatformHaltRestart
4149 //******************************************************************************
4151 struct HaltRestartApplierContext
{
4152 IOPMrootDomain
* RootDomain
;
4153 unsigned long PowerState
;
4154 IOPMPowerFlags PowerFlags
;
4160 platformHaltRestartApplier( OSObject
* object
, void * context
)
4162 IOPowerStateChangeNotification notify
;
4163 HaltRestartApplierContext
* ctx
;
4164 AbsoluteTime startTime
;
4167 ctx
= (HaltRestartApplierContext
*) context
;
4169 memset(¬ify
, 0, sizeof(notify
));
4170 notify
.powerRef
= (void *)ctx
->Counter
;
4171 notify
.returnValue
= 0;
4172 notify
.stateNumber
= ctx
->PowerState
;
4173 notify
.stateFlags
= ctx
->PowerFlags
;
4175 clock_get_uptime(&startTime
);
4176 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4177 deltaTime
= computeDeltaTimeMS(&startTime
);
4179 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4180 (gIOKitDebug
& kIOLogPMRootDomain
))
4182 _IOServiceInterestNotifier
* notifier
;
4183 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4185 // IOService children of IOPMrootDomain are not instrumented.
4186 // Only IORootParent currently falls under that group.
4190 LOG("%s handler %p took %u ms\n",
4191 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
4192 (ctx
->MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
4193 notifier
->handler
, (uint32_t) deltaTime
);
4200 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4202 HaltRestartApplierContext ctx
;
4203 AbsoluteTime startTime
;
4206 memset(&ctx
, 0, sizeof(ctx
));
4207 ctx
.RootDomain
= this;
4209 clock_get_uptime(&startTime
);
4213 case kPEUPSDelayHaltCPU
:
4214 ctx
.PowerState
= OFF_STATE
;
4215 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4219 ctx
.PowerState
= RESTART_STATE
;
4220 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4224 ctx
.PowerState
= ON_STATE
;
4225 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4226 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4228 IOHibernateSystemRestart();
4236 // Notify legacy clients
4237 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4239 // For normal shutdown, turn off File Server Mode.
4240 if (kPEHaltCPU
== pe_type
)
4242 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4243 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4246 setPMSetting(setting
, num
);
4252 if (kPEPagingOff
!= pe_type
)
4254 // Notify in power tree order
4255 notifySystemShutdown(this, ctx
.MessageType
);
4258 deltaTime
= computeDeltaTimeMS(&startTime
);
4259 LOG("%s all drivers took %u ms\n",
4260 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
4261 (ctx
.MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
4262 (uint32_t) deltaTime
);
4265 //******************************************************************************
4268 //******************************************************************************
4270 IOReturn
IOPMrootDomain::shutdownSystem( void )
4272 return kIOReturnUnsupported
;
4275 //******************************************************************************
4278 //******************************************************************************
4280 IOReturn
IOPMrootDomain::restartSystem( void )
4282 return kIOReturnUnsupported
;
4286 // MARK: System Capability
4288 //******************************************************************************
4289 // tagPowerPlaneService
4291 // Running on PM work loop thread.
4292 //******************************************************************************
4294 void IOPMrootDomain::tagPowerPlaneService(
4295 IOService
* service
,
4296 IOPMActions
* actions
)
4299 bool isDisplayWrangler
;
4301 memset(actions
, 0, sizeof(*actions
));
4302 actions
->target
= this;
4304 if (service
== this)
4306 actions
->actionPowerChangeStart
=
4307 OSMemberFunctionCast(
4308 IOPMActionPowerChangeStart
, this,
4309 &IOPMrootDomain::handleOurPowerChangeStart
);
4311 actions
->actionPowerChangeDone
=
4312 OSMemberFunctionCast(
4313 IOPMActionPowerChangeDone
, this,
4314 &IOPMrootDomain::handleOurPowerChangeDone
);
4316 actions
->actionPowerChangeOverride
=
4317 OSMemberFunctionCast(
4318 IOPMActionPowerChangeOverride
, this,
4319 &IOPMrootDomain::overrideOurPowerChange
);
4324 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4325 if (isDisplayWrangler
)
4330 isDisplayWrangler
= false;
4333 #if defined(__i386__) || defined(__x86_64__)
4334 if (isDisplayWrangler
)
4335 flags
|= kPMActionsFlagIsDisplayWrangler
;
4336 if (service
->getProperty("IOPMStrictTreeOrder"))
4337 flags
|= kPMActionsFlagIsGraphicsDevice
;
4338 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4339 flags
|= kPMActionsFlagIsAudioDevice
;
4342 // Find the power connection object that is a child of the PCI host
4343 // bridge, and has a graphics/audio device attached below. Mark the
4344 // power branch for delayed child notifications.
4348 IORegistryEntry
* child
= service
;
4349 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4351 while (child
!= this)
4353 if ((parent
== pciHostBridgeDriver
) ||
4356 if (OSDynamicCast(IOPowerConnection
, child
))
4358 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4359 conn
->delayChildNotification
= true;
4364 parent
= child
->getParentEntry(gIOPowerPlane
);
4370 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4371 actions
->parameter
|= flags
;
4372 actions
->actionPowerChangeOverride
=
4373 OSMemberFunctionCast(
4374 IOPMActionPowerChangeOverride
, this,
4375 &IOPMrootDomain::overridePowerChangeForUIService
);
4377 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4379 actions
->actionActivityTickle
=
4380 OSMemberFunctionCast(
4381 IOPMActionActivityTickle
, this,
4382 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4387 // Locate the first PCI host bridge for PMTrace.
4388 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4390 IOService
* provider
= service
->getProvider();
4391 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4392 provider
->inPlane(gIODTPlane
))
4394 pciHostBridgeDevice
= provider
;
4395 pciHostBridgeDriver
= service
;
4396 DLOG("PMTrace found PCI host bridge %s->%s\n",
4397 provider
->getName(), service
->getName());
4401 // Tag top-level PCI devices. The order of PMinit() call does not
4402 // change across boots and is used as the PCI bit number.
4403 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4405 // Would prefer to check built-in property, but tagPowerPlaneService()
4406 // is called before pciDevice->registerService().
4407 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4408 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4410 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4413 // Save the assigned bit for fast lookup.
4414 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4416 actions
->actionPowerChangeStart
=
4417 OSMemberFunctionCast(
4418 IOPMActionPowerChangeStart
, this,
4419 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4421 actions
->actionPowerChangeDone
=
4422 OSMemberFunctionCast(
4423 IOPMActionPowerChangeDone
, this,
4424 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4430 //******************************************************************************
4431 // PM actions for root domain
4432 //******************************************************************************
4434 void IOPMrootDomain::overrideOurPowerChange(
4435 IOService
* service
,
4436 IOPMActions
* actions
,
4437 unsigned long * inOutPowerState
,
4438 uint32_t * inOutChangeFlags
)
4440 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4441 uint32_t changeFlags
= *inOutChangeFlags
;
4442 uint32_t currentPowerState
= (uint32_t) getPowerState();
4444 if (changeFlags
& kIOPMParentInitiated
)
4446 // FIXME: cancel any parent change (unexpected)
4447 // Root parent is permanently pegged at max power,
4448 // kIOPMParentInitiated is unexpected.
4452 if (powerState
< currentPowerState
)
4454 if ((changeFlags
& kIOPMSkipAskPowerDown
) == 0)
4456 /* Convenient place to run any code at idle sleep time
4457 * IOPMrootDomain initiates an idle sleep here
4459 * Set last sleep cause accordingly.
4461 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
4463 lastSleepReason
= kIOPMSleepReasonIdle
;
4464 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
4466 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4468 // Root domain is dropping power state ON->SLEEP.
4469 // If system is in full wake, first drop to dark wake.
4471 darkWakeToSleepASAP
= true;
4473 // Drop graphics capability.
4474 // No transition if system is already in dark wake.
4476 _desiredCapability
&= ~(
4477 kIOPMSystemCapabilityGraphics
|
4478 kIOPMSystemCapabilityAudio
);
4480 *inOutPowerState
= ON_STATE
;
4481 *inOutChangeFlags
|= kIOPMSynchronize
;
4483 // Revert device desire from SLEEP->ON.
4484 changePowerStateToPriv(ON_STATE
);
4488 // Broadcast power down
4489 *inOutChangeFlags
|= kIOPMRootChangeDown
;
4492 else if (powerState
> currentPowerState
)
4494 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
4496 // Broadcast power up when waking from sleep, but not for the
4497 // initial power change at boot by checking for cpu capability.
4498 *inOutChangeFlags
|= kIOPMRootChangeUp
;
4503 void IOPMrootDomain::handleOurPowerChangeStart(
4504 IOService
* service
,
4505 IOPMActions
* actions
,
4506 uint32_t powerState
,
4507 uint32_t * inOutChangeFlags
)
4509 uint32_t changeFlags
= *inOutChangeFlags
;
4510 uint32_t currentPowerState
= (uint32_t) getPowerState();
4512 _systemTransitionType
= kSystemTransitionNone
;
4513 _systemMessageClientMask
= 0;
4514 capabilityLoss
= false;
4516 // 1. Explicit capability change.
4518 if (changeFlags
& kIOPMSynchronize
)
4520 if (powerState
== ON_STATE
)
4522 if (changeFlags
& kIOPMSyncNoChildNotify
)
4523 _systemTransitionType
= kSystemTransitionNewCapClient
;
4525 _systemTransitionType
= kSystemTransitionCapability
;
4529 // 2. Going to sleep (cancellation still possible).
4531 else if (powerState
< currentPowerState
)
4532 _systemTransitionType
= kSystemTransitionSleep
;
4534 // 3. Woke from (idle or demand) sleep.
4536 else if (!systemBooting
&&
4537 (changeFlags
& kIOPMSelfInitiated
) &&
4538 (powerState
> currentPowerState
))
4540 _systemTransitionType
= kSystemTransitionWake
;
4541 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4542 kIOPMSystemCapabilityNetwork
;
4544 // Check for early HID events (e.g. LID open)
4545 if (wranglerTickled
)
4547 _desiredCapability
|= (
4548 kIOPMSystemCapabilityGraphics
|
4549 kIOPMSystemCapabilityAudio
);
4553 // Update pending wake capability at the beginning of every
4554 // state transition (including synchronize). This will become
4555 // the current capability at the end of the transition.
4557 if (kSystemTransitionSleep
== _systemTransitionType
)
4559 _pendingCapability
= 0;
4560 capabilityLoss
= true;
4562 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4564 _pendingCapability
= _desiredCapability
|
4565 kIOPMSystemCapabilityCPU
|
4566 kIOPMSystemCapabilityNetwork
;
4568 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4569 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4571 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4572 (_pendingCapability
== _currentCapability
))
4574 // Cancel the PM state change.
4575 _systemTransitionType
= kSystemTransitionNone
;
4576 *inOutChangeFlags
|= kIOPMNotDone
;
4578 if (__builtin_popcount(_pendingCapability
) <
4579 __builtin_popcount(_currentCapability
))
4580 capabilityLoss
= true;
4581 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4582 rejectWranglerTickle
= true;
4585 // 1. Capability change.
4587 if (kSystemTransitionCapability
== _systemTransitionType
)
4589 // Dark to Full transition.
4590 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4592 tracePoint( kIOPMTracePointDarkWakeExit
);
4593 wranglerSleepIgnored
= false;
4594 sleepTimerMaintenance
= false;
4595 hibernateNoDefeat
= false;
4596 _systemMessageClientMask
= kSystemMessageClientUser
;
4597 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4598 _systemMessageClientMask
|= kSystemMessageClientKernel
;
4600 IOService::setAdvisoryTickleEnable( true );
4601 tellClients(kIOMessageSystemWillPowerOn
);
4604 // Full to Dark transition.
4605 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4607 tracePoint( kIOPMTracePointDarkWakeEntry
);
4608 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4609 _systemMessageClientMask
= kSystemMessageClientUser
;
4610 IOService::setAdvisoryTickleEnable( false );
4616 else if (kSystemTransitionSleep
== _systemTransitionType
)
4618 // Beginning of a system sleep transition.
4619 // Cancellation is still possible.
4620 tracePoint( kIOPMTracePointSleepStarted
, lastSleepReason
);
4622 _systemMessageClientMask
= kSystemMessageClientAll
;
4623 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4624 _systemMessageClientMask
&= ~kSystemMessageClientApp
;
4625 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4626 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4628 // Optimization to ignore wrangler power down thus skipping
4629 // the disk spindown and arming the idle timer for demand sleep.
4631 if (changeFlags
& kIOPMIgnoreChildren
)
4633 wranglerSleepIgnored
= true;
4636 logWranglerTickle
= false;
4641 else if (kSystemTransitionWake
== _systemTransitionType
)
4643 wranglerSleepIgnored
= false;
4645 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4647 _systemMessageClientMask
= kSystemMessageClientAll
;
4648 IOService::setAdvisoryTickleEnable( true );
4652 _systemMessageClientMask
= kSystemMessageClientConfigd
;
4655 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4656 tellClients(kIOMessageSystemWillPowerOn
);
4659 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4660 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4662 _systemStateGeneration
++;
4663 systemDarkWake
= false;
4665 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4667 currentPowerState
, powerState
, *inOutChangeFlags
,
4668 _systemTransitionType
, _systemStateGeneration
,
4669 _systemMessageClientMask
,
4670 _desiredCapability
, _currentCapability
, _pendingCapability
);
4674 void IOPMrootDomain::handleOurPowerChangeDone(
4675 IOService
* service
,
4676 IOPMActions
* actions
,
4677 uint32_t powerState
,
4678 uint32_t changeFlags
)
4680 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4682 _systemTransitionType
= kSystemTransitionNone
;
4686 if (_systemTransitionType
!= kSystemTransitionNone
)
4688 uint32_t currentPowerState
= (uint32_t) getPowerState();
4690 if (changeFlags
& kIOPMNotDone
)
4692 // Power down was cancelled or vetoed.
4693 _pendingCapability
= _currentCapability
;
4694 lastSleepReason
= 0;
4696 if (((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4697 (_currentCapability
& kIOPMSystemCapabilityCPU
))
4699 pmPowerStateQueue
->submitPowerEvent(
4700 kPowerEventPolicyStimulus
,
4701 (void *) kStimulusDarkWakeReentry
,
4702 _systemStateGeneration
);
4705 // Revert device desire to max.
4706 changePowerStateToPriv(ON_STATE
);
4710 // Send message on dark wake to full wake promotion.
4711 // tellChangeUp() handles the normal SLEEP->ON case.
4713 if (kSystemTransitionCapability
== _systemTransitionType
)
4715 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4717 tellClients(kIOMessageSystemHasPoweredOn
);
4718 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4719 // Re-evaluate clamshell state ourselves when graphics
4720 // will not get kIOMessageSystemHasPoweredOn.
4722 if (clamshellClosed
&&
4723 ((_systemMessageClientMask
& kSystemMessageClientKernel
) == 0))
4725 receivePowerNotification( kLocalEvalClamshellCommand
);
4729 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4730 wranglerTickled
= false;
4733 // Reset state after exiting from dark wake.
4735 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
4736 CAP_LOSS(kIOPMSystemCapabilityCPU
))
4738 darkWakeMaintenance
= false;
4739 darkWakeToSleepASAP
= false;
4740 pciCantSleepValid
= false;
4741 rejectWranglerTickle
= false;
4742 darkWakeSleepService
= false;
4745 // Entered dark mode.
4747 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4748 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
4750 if (((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOInDark
) == 0) &&
4751 (kSystemTransitionWake
== _systemTransitionType
) &&
4752 (_lastDebugWakeSeconds
== 0))
4754 OSObject
* prop
= copyProperty(kIOPMRootDomainWakeTypeKey
);
4757 OSString
* wakeType
= OSDynamicCast(OSString
, prop
);
4759 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeNetwork
))
4761 // Woke from network and entered dark wake.
4762 if (darkWakeToSleepASAP
)
4764 DLOG("cleared darkWakeToSleepASAP\n");
4765 darkWakeToSleepASAP
= false;
4772 // Queue an evaluation of whether to remain in dark wake,
4773 // and for how long. This serves the purpose of draining
4774 // any assertions from the queue.
4776 pmPowerStateQueue
->submitPowerEvent(
4777 kPowerEventPolicyStimulus
,
4778 (void *) kStimulusDarkWakeEntry
,
4779 _systemStateGeneration
);
4783 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4784 "dcp %x:%x:%x, dbgtimer %u\n",
4785 currentPowerState
, powerState
, changeFlags
,
4786 _systemTransitionType
, _systemStateGeneration
,
4787 _systemMessageClientMask
,
4788 _desiredCapability
, _currentCapability
, _pendingCapability
,
4789 _lastDebugWakeSeconds
);
4791 // Update current system capability.
4793 if (_currentCapability
!= _pendingCapability
)
4794 _currentCapability
= _pendingCapability
;
4796 // Update highest system capability.
4798 _highestCapability
|= _currentCapability
;
4800 if (darkWakePostTickle
&&
4801 (kSystemTransitionWake
== _systemTransitionType
) &&
4802 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4803 kDarkWakeFlagHIDTickleLate
)
4805 darkWakePostTickle
= false;
4809 // Reset tracepoint at completion of capability change,
4810 // completion of wake transition, and aborted sleep transition.
4812 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
4813 (_systemTransitionType
== kSystemTransitionWake
) ||
4814 ((_systemTransitionType
== kSystemTransitionSleep
) &&
4815 (changeFlags
& kIOPMNotDone
)))
4817 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
4818 tracePoint( kIOPMTracePointSystemUp
, 0 );
4820 // kIOPMDWOverTemp notification handling was postponed
4821 if (darkWakeThermalAlarm
)
4823 if (!wranglerTickled
&& !darkWakeThermalEmergency
&&
4824 CAP_CURRENT(kIOPMSystemCapabilityCPU
) &&
4825 !CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4827 darkWakeThermalEmergency
= true;
4828 privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
4829 MSG("DarkWake thermal limits breached. Going to sleep!\n");
4831 darkWakeThermalAlarm
= false;
4835 _systemTransitionType
= kSystemTransitionNone
;
4836 _systemMessageClientMask
= 0;
4838 logGraphicsClamp
= false;
4842 //******************************************************************************
4843 // PM actions for graphics and audio.
4844 //******************************************************************************
4846 void IOPMrootDomain::overridePowerChangeForUIService(
4847 IOService
* service
,
4848 IOPMActions
* actions
,
4849 unsigned long * inOutPowerState
,
4850 uint32_t * inOutChangeFlags
)
4852 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4853 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
4855 if (kSystemTransitionNone
== _systemTransitionType
)
4857 // Not in midst of a system transition.
4858 // Do not modify power limit enable state.
4860 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4862 // Activate power limiter.
4864 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4865 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4866 (changeFlags
& kIOPMSynchronize
))
4868 actions
->parameter
|= kPMActionsFlagLimitPower
;
4870 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4871 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
4872 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
4873 (changeFlags
& kIOPMSynchronize
))
4875 actions
->parameter
|= kPMActionsFlagLimitPower
;
4877 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
4878 (_systemTransitionType
== kSystemTransitionSleep
))
4880 // For graphics devices, arm the limiter when entering
4881 // system sleep. Not when dropping to dark wake.
4882 actions
->parameter
|= kPMActionsFlagLimitPower
;
4885 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4887 DLOG("+ plimit %s %p\n",
4888 service
->getName(), service
);
4893 // Remove power limit.
4895 if ((actions
->parameter
& (
4896 kPMActionsFlagIsDisplayWrangler
|
4897 kPMActionsFlagIsGraphicsDevice
)) &&
4898 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
4900 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4902 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4903 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
4905 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4908 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4910 DLOG("- plimit %s %p\n",
4911 service
->getName(), service
);
4915 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4917 uint32_t maxPowerState
= (uint32_t)(-1);
4919 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
4921 // Enforce limit for system power/cap transitions.
4924 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4925 (service
->getPowerState() > 0))
4927 // Forces a 3->1 transition sequence
4928 if (changeFlags
& kIOPMDomainWillChange
)
4933 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
4940 // Deny all self-initiated changes when power is limited.
4941 // Wrangler tickle should never defeat the limiter.
4943 maxPowerState
= service
->getPowerState();
4946 if (powerState
> maxPowerState
)
4948 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4949 service
->getName(), service
, powerState
, maxPowerState
,
4951 *inOutPowerState
= maxPowerState
;
4953 if (darkWakePostTickle
&&
4954 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4955 (changeFlags
& kIOPMDomainWillChange
) &&
4956 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4957 kDarkWakeFlagHIDTickleEarly
))
4959 darkWakePostTickle
= false;
4964 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
4966 if (logGraphicsClamp
)
4971 clock_get_uptime(&now
);
4972 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
4973 absolutetime_to_nanoseconds(now
, &nsec
);
4974 MSG("Graphics suppressed %u ms\n",
4975 ((int)((nsec
) / 1000000ULL)));
4977 graphicsSuppressed
= true;
4982 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4983 IOService
* service
,
4984 IOPMActions
* actions
)
4986 // Warning: Not running in PM work loop context - don't modify state !!!
4987 // Trap tickle directed to IODisplayWrangler while running with graphics
4988 // capability suppressed.
4990 assert(service
== wrangler
);
4992 if (service
== wrangler
)
4994 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
4995 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
4997 userActivityCount
++;
4998 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
5002 if (!wranglerTickled
&&
5003 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5005 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
5006 DLOG("display wrangler tickled\n");
5007 if (kIOLogPMRootDomain
& gIOKitDebug
)
5008 OSReportWithBacktrace("Dark wake display tickle");
5009 if (pmPowerStateQueue
)
5011 pmPowerStateQueue
->submitPowerEvent(
5012 kPowerEventPolicyStimulus
,
5013 (void *) kStimulusDarkWakeActivityTickle
);
5018 //******************************************************************************
5019 // Approve usage of delayed child notification by PM.
5020 //******************************************************************************
5022 bool IOPMrootDomain::shouldDelayChildNotification(
5023 IOService
* service
)
5025 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5027 (kSystemTransitionWake
== _systemTransitionType
))
5029 DLOG("%s: delay child notify\n", service
->getName());
5035 //******************************************************************************
5036 // PM actions for PCI device.
5037 //******************************************************************************
5039 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5040 IOService
* service
,
5041 IOPMActions
* actions
,
5042 uint32_t powerState
,
5043 uint32_t * inOutChangeFlags
)
5045 pmTracer
->tracePCIPowerChange(
5046 PMTraceWorker::kPowerChangeStart
,
5047 service
, *inOutChangeFlags
,
5048 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5051 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5052 IOService
* service
,
5053 IOPMActions
* actions
,
5054 uint32_t powerState
,
5055 uint32_t changeFlags
)
5057 pmTracer
->tracePCIPowerChange(
5058 PMTraceWorker::kPowerChangeCompleted
,
5059 service
, changeFlags
,
5060 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5063 //******************************************************************************
5066 // Override IOService::registerInterest() to intercept special clients.
5067 //******************************************************************************
5069 IONotifier
* IOPMrootDomain::registerInterest(
5070 const OSSymbol
* typeOfInterest
,
5071 IOServiceInterestHandler handler
,
5072 void * target
, void * ref
)
5074 IONotifier
* notifier
;
5075 bool isSystemCapabilityClient
;
5076 bool isKernelCapabilityClient
;
5078 isSystemCapabilityClient
=
5080 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5082 isKernelCapabilityClient
=
5084 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5086 if (isSystemCapabilityClient
)
5087 typeOfInterest
= gIOAppPowerStateInterest
;
5089 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
5090 if (notifier
&& pmPowerStateQueue
)
5092 if (isSystemCapabilityClient
)
5095 if (pmPowerStateQueue
->submitPowerEvent(
5096 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5097 notifier
->release();
5100 if (isKernelCapabilityClient
)
5103 if (pmPowerStateQueue
->submitPowerEvent(
5104 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5105 notifier
->release();
5112 //******************************************************************************
5113 // systemMessageFilter
5115 //******************************************************************************
5117 bool IOPMrootDomain::systemMessageFilter(
5118 void * object
, void * arg1
, void * arg2
, void * arg3
)
5120 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5121 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5122 bool isCapClient
= false;
5126 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5127 (!isCapMsg
|| !_joinedCapabilityClients
||
5128 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5131 // Capability change message for app and kernel clients.
5135 if ((context
->notifyType
== kNotifyPriority
) ||
5136 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5139 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5140 (object
== (void *) systemCapabilityNotifier
))
5146 IOPMSystemCapabilityChangeParameters
* capArgs
=
5147 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5149 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5151 capArgs
->fromCapabilities
= 0;
5152 capArgs
->toCapabilities
= _currentCapability
;
5153 capArgs
->changeFlags
= 0;
5157 capArgs
->fromCapabilities
= _currentCapability
;
5158 capArgs
->toCapabilities
= _pendingCapability
;
5160 if (context
->isPreChange
)
5161 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5163 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5166 // Capability change messages only go to the PM configd plugin.
5167 // Wait for response post-change if capabilitiy is increasing.
5168 // Wait for response pre-change if capability is decreasing.
5170 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5171 ( (capabilityLoss
&& context
->isPreChange
) ||
5172 (!capabilityLoss
&& !context
->isPreChange
) ) )
5174 // app has not replied yet, wait for it
5175 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5182 // Capability client will always see kIOMessageCanSystemSleep,
5183 // even for demand sleep.
5185 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5186 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5188 if (object
== (OSObject
*) systemCapabilityNotifier
)
5194 // Not idle sleep, don't ask apps.
5195 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5201 // Reject capability change messages for legacy clients.
5202 // Reject legacy system sleep messages for capability client.
5204 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5209 // Filter system sleep messages.
5211 if ((context
->notifyType
== kNotifyApps
) &&
5212 (_systemMessageClientMask
& kSystemMessageClientApp
))
5216 else if ((context
->notifyType
== kNotifyPriority
) &&
5217 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5224 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5226 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5227 if (_joinedCapabilityClients
->getCount() == 0)
5229 DLOG("destroyed capability client set %p\n",
5230 _joinedCapabilityClients
);
5231 _joinedCapabilityClients
->release();
5232 _joinedCapabilityClients
= 0;
5239 //******************************************************************************
5240 // setMaintenanceWakeCalendar
5242 //******************************************************************************
5244 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5245 const IOPMCalendarStruct
* calendar
)
5251 return kIOReturnBadArgument
;
5253 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5255 return kIOReturnNoMemory
;
5257 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5258 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5259 if (kIOReturnSuccess
== ret
)
5260 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5262 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5264 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5265 if (kIOReturnSuccess
== ret
)
5266 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5268 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5275 // MARK: Display Wrangler
5277 //******************************************************************************
5278 // displayWranglerNotification
5280 // Handle the notification when the IODisplayWrangler changes power state.
5281 //******************************************************************************
5283 IOReturn
IOPMrootDomain::displayWranglerNotification(
5284 void * target
, void * refCon
,
5285 UInt32 messageType
, IOService
* service
,
5286 void * messageArgument
, vm_size_t argSize
)
5289 int displayPowerState
;
5290 IOPowerStateChangeNotification
* params
=
5291 (IOPowerStateChangeNotification
*) messageArgument
;
5293 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5294 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5295 return kIOReturnUnsupported
;
5299 return kIOReturnUnsupported
;
5301 displayPowerState
= params
->stateNumber
;
5302 DLOG("DisplayWrangler message 0x%x, power state %d\n",
5303 (uint32_t) messageType
, displayPowerState
);
5305 switch (messageType
) {
5306 case kIOMessageDeviceWillPowerOff
:
5308 // Display wrangler has dropped power due to display idle
5309 // or force system sleep.
5314 // 1 Not visible to user
5315 // 0 Not visible to user
5317 if (displayPowerState
> 2)
5320 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5323 case kIOMessageDeviceHasPoweredOn
:
5325 // Display wrangler has powered on due to user activity
5326 // or wake from sleep.
5328 if ( 4 != displayPowerState
)
5331 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5335 return kIOReturnUnsupported
;
5338 //******************************************************************************
5339 // displayWranglerMatchPublished
5341 // Receives a notification when the IODisplayWrangler is published.
5342 // When it's published we install a power state change handler.
5343 //******************************************************************************
5345 bool IOPMrootDomain::displayWranglerMatchPublished(
5348 IOService
* newService
,
5349 IONotifier
* notifier __unused
)
5352 // found the display wrangler, now install a handler
5353 if( !newService
->registerInterest( gIOGeneralInterest
,
5354 &displayWranglerNotification
, target
, 0) )
5362 //******************************************************************************
5365 //******************************************************************************
5367 void IOPMrootDomain::reportUserInput( void )
5374 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
5377 wrangler
= (IOService
*) iter
->getNextObject();
5383 wrangler
->activityTickle(0,0);
5387 //******************************************************************************
5388 // blockDisplayWranglerTickle
5389 //******************************************************************************
5391 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
5396 // Not too late to prevent the display from lighting up
5397 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
5398 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5399 !checkSystemCanSustainFullWake())
5401 wranglerTickleLatched
= true;
5405 wranglerTickleLatched
= false;
5408 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
5410 wranglerTickleLatched
= false;
5412 pmPowerStateQueue
->submitPowerEvent(
5413 kPowerEventPolicyStimulus
,
5414 (void *) kStimulusDarkWakeActivityTickle
);
5417 return wranglerTickleLatched
;
5426 //******************************************************************************
5429 // Notification on battery class IOPowerSource appearance
5430 //******************************************************************************
5432 bool IOPMrootDomain::batteryPublished(
5435 IOService
* resourceService
,
5436 IONotifier
* notifier __unused
)
5438 // rdar://2936060&4435589
5439 // All laptops have dimmable LCD displays
5440 // All laptops have batteries
5441 // So if this machine has a battery, publish the fact that the backlight
5442 // supports dimming.
5443 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
5449 // MARK: System PM Policy
5451 //******************************************************************************
5452 // checkSystemCanSleep
5454 //******************************************************************************
5456 bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options
)
5460 // Conditions that prevent idle and demand system sleep.
5463 if (userDisabledAllSleep
)
5465 err
= 1; // 1. user-space sleep kill switch
5469 if (systemBooting
|| systemShutdown
)
5471 err
= 2; // 2. restart or shutdown in progress
5478 // Conditions above pegs the system at full wake.
5479 // Conditions below prevent system sleep but does not prevent
5480 // dark wake, and must be called from gated context.
5483 err
= 3; // 3. config does not support sleep
5487 if (lowBatteryCondition
)
5489 break; // always sleep on low battery
5492 if(darkWakeThermalEmergency
)
5494 break; // always sleep on dark wake thermal emergencies
5497 if (preventSystemSleepList
->getCount() != 0)
5499 err
= 4; // 4. child prevent system sleep clamp
5503 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
5504 kIOPMDriverAssertionLevelOn
)
5506 err
= 5; // 5. CPU assertion
5510 if (pciCantSleepValid
)
5512 if (pciCantSleepFlag
)
5513 err
= 6; // 6. PCI card does not support PM (cached)
5516 else if (sleepSupportedPEFunction
&&
5517 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5520 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
5521 ret
= getPlatform()->callPlatformFunction(
5522 sleepSupportedPEFunction
, false,
5523 NULL
, NULL
, NULL
, NULL
);
5524 pciCantSleepValid
= true;
5525 pciCantSleepFlag
= false;
5526 if ((platformSleepSupport
& kPCICantSleep
) ||
5527 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
5529 err
= 6; // 6. PCI card does not support PM
5530 pciCantSleepFlag
= true;
5539 DLOG("System sleep prevented by %d\n", err
);
5545 //******************************************************************************
5546 // checkSystemCanSustainFullWake
5547 //******************************************************************************
5549 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
5552 if (lowBatteryCondition
)
5554 // Low battery wake, or received a low battery notification
5555 // while system is awake.
5559 if (clamshellExists
&& clamshellClosed
&& !acAdaptorConnected
&&
5560 !clamshellSleepDisabled
)
5562 // Lid closed on battery power
5569 //******************************************************************************
5572 // Conditions that affect our wake/sleep decision has changed.
5573 // If conditions dictate that the system must remain awake, clamp power
5574 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
5575 // is TRUE, then remove the power clamp and allow the power state to drop
5577 //******************************************************************************
5579 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
5581 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
5582 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
5586 if ((sleepSlider
== 0) || !checkSystemCanSleep())
5588 changePowerStateToPriv(ON_STATE
);
5590 else if ( sleepASAP
)
5592 changePowerStateToPriv(SLEEP_STATE
);
5596 //******************************************************************************
5597 // dispatchPowerEvent
5599 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
5600 //******************************************************************************
5602 void IOPMrootDomain::dispatchPowerEvent(
5603 uint32_t event
, void * arg0
, uint64_t arg1
)
5605 DLOG("power event %u args %p 0x%llx\n", event
, arg0
, arg1
);
5610 case kPowerEventFeatureChanged
:
5611 messageClients(kIOPMMessageFeatureChange
, this);
5614 case kPowerEventReceivedPowerNotification
:
5615 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
5618 case kPowerEventSystemBootCompleted
:
5621 systemBooting
= false;
5623 if (lowBatteryCondition
)
5625 privateSleepSystem (kIOPMSleepReasonLowPower
);
5627 // The rest is unnecessary since the system is expected
5628 // to sleep immediately. The following wake will update
5633 // If lid is closed, re-send lid closed notification
5634 // now that booting is complete.
5635 if ( clamshellClosed
)
5637 handlePowerNotification(kLocalEvalClamshellCommand
);
5639 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
5643 case kPowerEventSystemShutdown
:
5644 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
5646 /* We set systemShutdown = true during shutdown
5647 to prevent sleep at unexpected times while loginwindow is trying
5648 to shutdown apps and while the OS is trying to transition to
5651 Set to true during shutdown, as soon as loginwindow shows
5652 the "shutdown countdown dialog", through individual app
5653 termination, and through black screen kernel shutdown.
5655 systemShutdown
= true;
5658 A shutdown was initiated, but then the shutdown
5659 was cancelled, clearing systemShutdown to false here.
5661 systemShutdown
= false;
5665 case kPowerEventUserDisabledSleep
:
5666 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
5669 case kPowerEventRegisterSystemCapabilityClient
:
5670 if (systemCapabilityNotifier
)
5672 systemCapabilityNotifier
->release();
5673 systemCapabilityNotifier
= 0;
5677 systemCapabilityNotifier
= (IONotifier
*) arg0
;
5678 systemCapabilityNotifier
->retain();
5680 /* intentional fall-through */
5682 case kPowerEventRegisterKernelCapabilityClient
:
5683 if (!_joinedCapabilityClients
)
5684 _joinedCapabilityClients
= OSSet::withCapacity(8);
5687 IONotifier
* notify
= (IONotifier
*) arg0
;
5688 if (_joinedCapabilityClients
)
5690 _joinedCapabilityClients
->setObject(notify
);
5691 synchronizePowerTree( kIOPMSyncNoChildNotify
);
5697 case kPowerEventPolicyStimulus
:
5700 int stimulus
= (uintptr_t) arg0
;
5701 evaluatePolicy( stimulus
, (uint32_t) arg1
);
5705 case kPowerEventAssertionCreate
:
5707 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
5712 case kPowerEventAssertionRelease
:
5714 pmAssertions
->handleReleaseAssertion(arg1
);
5718 case kPowerEventAssertionSetLevel
:
5720 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
5724 case kPowerEventQueueSleepWakeUUID
:
5725 handleQueueSleepWakeUUID((OSObject
*)arg0
);
5727 case kPowerEventPublishSleepWakeUUID
:
5728 handlePublishSleepWakeUUID((bool)arg0
);
5730 case kPowerEventSuspendClient
:
5731 handleSuspendPMNotificationClient((uintptr_t)arg0
, (bool)arg1
);
5736 //******************************************************************************
5737 // systemPowerEventOccurred
5739 // The power controller is notifying us of a hardware-related power management
5740 // event that we must handle.
5742 // systemPowerEventOccurred covers the same functionality that
5743 // receivePowerNotification does; it simply provides a richer API for conveying
5744 // more information.
5745 //******************************************************************************
5747 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5748 const OSSymbol
*event
,
5751 IOReturn attempt
= kIOReturnSuccess
;
5752 OSNumber
*newNumber
= NULL
;
5755 return kIOReturnBadArgument
;
5757 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
5759 return kIOReturnInternalError
;
5761 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
5763 newNumber
->release();
5768 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5769 const OSSymbol
*event
,
5772 OSDictionary
*thermalsDict
= NULL
;
5773 bool shouldUpdate
= true;
5775 if (!event
|| !value
)
5776 return kIOReturnBadArgument
;
5779 // We reuse featuresDict Lock because it already exists and guards
5780 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5781 // of stepping on that lock.
5782 if (featuresDictLock
) IOLockLock(featuresDictLock
);
5784 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
5786 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
5787 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
5789 thermalsDict
= OSDictionary::withCapacity(1);
5792 if (!thermalsDict
) {
5793 shouldUpdate
= false;
5797 thermalsDict
->setObject (event
, value
);
5799 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
5801 thermalsDict
->release();
5805 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
5808 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
5810 return kIOReturnSuccess
;
5813 //******************************************************************************
5814 // receivePowerNotification
5816 // The power controller is notifying us of a hardware-related power management
5817 // event that we must handle. This may be a result of an 'environment' interrupt
5818 // from the power mgt micro.
5819 //******************************************************************************
5821 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
5823 pmPowerStateQueue
->submitPowerEvent(
5824 kPowerEventReceivedPowerNotification
, (void *) msg
);
5825 return kIOReturnSuccess
;
5828 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
5830 bool eval_clamshell
= false;
5835 * Local (IOPMrootDomain only) eval clamshell command
5837 if (msg
& kLocalEvalClamshellCommand
)
5839 eval_clamshell
= true;
5845 if (msg
& kIOPMOverTemp
)
5847 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
5848 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
5851 if (msg
& kIOPMDWOverTemp
)
5853 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU
) ||
5854 (_systemTransitionType
== kSystemTransitionSleep
) ||
5855 (_systemTransitionType
== kSystemTransitionWake
) ||
5856 (_systemTransitionType
== kSystemTransitionCapability
))
5858 // During early wake or when system capability is changing,
5859 // set flag and take action at end of transition.
5860 darkWakeThermalAlarm
= true;
5862 else if (!wranglerTickled
&& !darkWakeThermalEmergency
&&
5863 !CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
5865 // System in steady state and in dark wake
5866 darkWakeThermalEmergency
= true;
5867 privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
5868 MSG("DarkWake thermal limits breached. Going to sleep!\n");
5875 if (msg
& kIOPMSleepNow
)
5877 privateSleepSystem (kIOPMSleepReasonSoftware
);
5883 if (msg
& kIOPMPowerEmergency
)
5885 lowBatteryCondition
= true;
5886 privateSleepSystem (kIOPMSleepReasonLowPower
);
5892 if (msg
& kIOPMClamshellOpened
)
5894 // Received clamshel open message from clamshell controlling driver
5895 // Update our internal state and tell general interest clients
5896 clamshellClosed
= false;
5897 clamshellExists
= true;
5899 // Don't issue a hid tickle when lid is open and polled on wake
5900 if (msg
& kIOPMSetValue
)
5902 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
5907 informCPUStateChange(kInformLid
, 0);
5909 // Tell general interest clients
5910 sendClientClamshellNotification();
5912 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
5913 || (lastSleepReason
== kIOPMSleepReasonIdle
)
5914 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
5915 if (aborting
) userActivityCount
++;
5916 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
5921 * Send the clamshell interest notification since the lid is closing.
5923 if (msg
& kIOPMClamshellClosed
)
5925 // Received clamshel open message from clamshell controlling driver
5926 // Update our internal state and tell general interest clients
5927 clamshellClosed
= true;
5928 clamshellExists
= true;
5931 informCPUStateChange(kInformLid
, 1);
5933 // Tell general interest clients
5934 sendClientClamshellNotification();
5936 // And set eval_clamshell = so we can attempt
5937 eval_clamshell
= true;
5941 * Set Desktop mode (sent from graphics)
5943 * -> reevaluate lid state
5945 if (msg
& kIOPMSetDesktopMode
)
5947 desktopMode
= (0 != (msg
& kIOPMSetValue
));
5948 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
5950 sendClientClamshellNotification();
5952 // Re-evaluate the lid state
5953 if( clamshellClosed
)
5955 eval_clamshell
= true;
5960 * AC Adaptor connected
5962 * -> reevaluate lid state
5964 if (msg
& kIOPMSetACAdaptorConnected
)
5966 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
5967 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
5970 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
5972 // Tell BSD if AC is connected
5973 // 0 == external power source; 1 == on battery
5974 post_sys_powersource(acAdaptorConnected
? 0:1);
5976 sendClientClamshellNotification();
5978 // Re-evaluate the lid state
5979 if( clamshellClosed
)
5981 eval_clamshell
= true;
5984 // Lack of AC may have latched a display wrangler tickle.
5985 // This mirrors the hardware's USB wake event latch, where a latched
5986 // USB wake event followed by an AC attach will trigger a full wake.
5987 latchDisplayWranglerTickle( false );
5990 // AC presence will reset the standy timer delay adjustment.
5991 _standbyTimerResetSeconds
= 0;
5996 * Enable Clamshell (external display disappear)
5998 * -> reevaluate lid state
6000 if (msg
& kIOPMEnableClamshell
)
6002 // Re-evaluate the lid state
6003 // System should sleep on external display disappearance
6004 // in lid closed operation.
6005 if( clamshellClosed
&& (true == clamshellDisabled
) )
6007 eval_clamshell
= true;
6010 clamshellDisabled
= false;
6012 sendClientClamshellNotification();
6016 * Disable Clamshell (external display appeared)
6017 * We don't bother re-evaluating clamshell state. If the system is awake,
6018 * the lid is probably open.
6020 if (msg
& kIOPMDisableClamshell
)
6022 clamshellDisabled
= true;
6024 sendClientClamshellNotification();
6028 * Evaluate clamshell and SLEEP if appropiate
6030 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
6034 privateSleepSystem (kIOPMSleepReasonClamshell
);
6036 else if ( eval_clamshell
)
6038 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6044 if (msg
& kIOPMPowerButton
)
6046 if (!wranglerAsleep
)
6048 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6049 // Check that power button sleep is enabled
6051 if( kOSBooleanTrue
!= getProperty(pbs
))
6052 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6060 //******************************************************************************
6063 // Evaluate root-domain policy in response to external changes.
6064 //******************************************************************************
6066 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6070 int idleSleepEnabled
: 1;
6071 int idleSleepDisabled
: 1;
6072 int displaySleep
: 1;
6073 int sleepDelayChanged
: 1;
6074 int evaluateDarkWake
: 1;
6075 int adjustPowerState
: 1;
6080 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6087 case kStimulusDisplayWranglerSleep
:
6088 if (!wranglerAsleep
)
6090 wranglerAsleep
= true;
6091 clock_get_uptime(&wranglerSleepTime
);
6092 flags
.bit
.displaySleep
= true;
6096 case kStimulusDisplayWranglerWake
:
6097 wranglerAsleep
= false;
6098 flags
.bit
.idleSleepDisabled
= true;
6101 case kStimulusAggressivenessChanged
:
6103 unsigned long minutesToIdleSleep
= 0;
6104 unsigned long minutesToDisplayDim
= 0;
6105 unsigned long minutesDelta
= 0;
6107 // Fetch latest display and system sleep slider values.
6108 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
6109 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
6110 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6111 (uint32_t) sleepSlider
,
6112 (uint32_t) minutesToIdleSleep
,
6113 (uint32_t) minutesToDisplayDim
);
6115 DLOG("idle time -> %ld secs (ena %d)\n",
6116 idleSeconds
, (minutesToIdleSleep
!= 0));
6118 if (0x7fffffff == minutesToIdleSleep
)
6119 minutesToIdleSleep
= idleSeconds
;
6121 // How long to wait before sleeping the system once
6122 // the displays turns off is indicated by 'extraSleepDelay'.
6124 if ( minutesToIdleSleep
> minutesToDisplayDim
)
6125 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
6126 else if( minutesToIdleSleep
<= minutesToDisplayDim
)
6129 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
6130 flags
.bit
.idleSleepEnabled
= true;
6132 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
6133 flags
.bit
.idleSleepDisabled
= true;
6135 if ((minutesDelta
!= extraSleepDelay
) &&
6136 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
6137 flags
.bit
.sleepDelayChanged
= true;
6139 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
6140 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
6142 // Reconsider decision to remain in dark wake
6143 flags
.bit
.evaluateDarkWake
= true;
6146 sleepSlider
= minutesToIdleSleep
;
6147 extraSleepDelay
= minutesDelta
;
6150 case kStimulusDemandSystemSleep
:
6151 changePowerStateWithOverrideTo( SLEEP_STATE
);
6154 case kStimulusAllowSystemSleepChanged
:
6155 flags
.bit
.adjustPowerState
= true;
6158 case kStimulusDarkWakeActivityTickle
:
6159 if (false == wranglerTickled
)
6161 uint32_t options
= 0;
6162 IOService
* pciRoot
= 0;
6164 if (rejectWranglerTickle
)
6166 DLOG("rejected tickle, type %u capability %x:%x\n",
6167 _systemTransitionType
,
6168 _currentCapability
, _pendingCapability
);
6172 if (latchDisplayWranglerTickle(true))
6174 DLOG("latched tickle\n");
6178 _desiredCapability
|=
6179 (kIOPMSystemCapabilityGraphics
|
6180 kIOPMSystemCapabilityAudio
);
6182 if ((kSystemTransitionWake
== _systemTransitionType
) &&
6183 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6184 !graphicsSuppressed
)
6186 DLOG("Promoting to full wake\n");
6188 // Elevate to full wake while waking up to dark wake.
6189 // PM will hold off notifying the graphics subsystem about
6190 // system wake as late as possible, so if a HID event does
6191 // arrive, we can turn on graphics on this wake cycle, and
6192 // not have to wait till the following cycle. That latency
6193 // can be huge on some systems. However, once any graphics
6194 // suppression has taken effect, it is too late. All other
6195 // graphics devices must be similarly suppressed. But the
6196 // delay till the following cycle should be very short.
6198 _pendingCapability
|=
6199 (kIOPMSystemCapabilityGraphics
|
6200 kIOPMSystemCapabilityAudio
);
6202 // Immediately bring up audio and graphics.
6203 pciRoot
= pciHostBridgeDriver
;
6205 // Notify clients about full wake.
6206 _systemMessageClientMask
= kSystemMessageClientAll
;
6207 IOService::setAdvisoryTickleEnable( true );
6208 tellClients(kIOMessageSystemWillPowerOn
);
6211 // Unsafe to cancel once graphics was powered.
6212 // If system woke from dark wake, the return to sleep can
6213 // be cancelled. But "awake -> dark -> sleep" transition
6214 // cannot be cancelled.
6216 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
6217 options
|= kIOPMSyncCancelPowerDown
;
6220 synchronizePowerTree( options
, pciRoot
);
6221 wranglerTickled
= true;
6222 // IOGraphics doesn't lit the display even though graphics
6223 // is enanbled in kIOMessageSystemCapabilityChange message(radar 9502104)
6224 // So, do an explicit activity tickle
6226 wrangler
->activityTickle(0,0);
6228 if (logWranglerTickle
)
6233 clock_get_uptime(&now
);
6234 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
6235 absolutetime_to_nanoseconds(now
, &nsec
);
6236 MSG("HID tickle %u ms\n",
6237 ((int)((nsec
) / 1000000ULL)));
6238 logWranglerTickle
= false;
6243 case kStimulusDarkWakeEntry
:
6244 case kStimulusDarkWakeReentry
:
6245 // Any system transitions since the last dark wake transition
6246 // will invalid the stimulus.
6248 if (arg
== _systemStateGeneration
)
6250 DLOG("dark wake entry\n");
6251 systemDarkWake
= true;
6252 wranglerAsleep
= true;
6253 clock_get_uptime(&wranglerSleepTime
);
6255 // Always accelerate disk spindown while in dark wake,
6256 // even if system does not support/allow sleep.
6258 cancelIdleSleepTimer();
6259 setQuickSpinDownTimeout();
6260 flags
.bit
.evaluateDarkWake
= true;
6264 case kStimulusDarkWakeEvaluate
:
6267 flags
.bit
.evaluateDarkWake
= true;
6269 #if !DARK_TO_FULL_EVALUATE_CLAMSHELL
6272 // Not through kLocalEvalClamshellCommand to avoid loop.
6273 if (clamshellClosed
&& shouldSleepOnClamshellClosed() &&
6274 checkSystemCanSleep(true))
6276 privateSleepSystem( kIOPMSleepReasonClamshell
);
6282 case kStimulusNoIdleSleepPreventers
:
6283 flags
.bit
.adjustPowerState
= true;
6286 } /* switch(stimulus) */
6288 if (flags
.bit
.evaluateDarkWake
&& !wranglerTickled
)
6290 if (darkWakeToSleepASAP
||
6291 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
6293 // System currently in dark wake, and no children and
6294 // assertion prevent system sleep.
6296 if (checkSystemCanSleep(true))
6298 if (lowBatteryCondition
)
6300 lastSleepReason
= kIOPMSleepReasonLowPower
;
6301 setProperty(kRootDomainSleepReasonKey
, kIOPMLowPowerSleepKey
);
6303 else if (darkWakeMaintenance
)
6305 lastSleepReason
= kIOPMSleepReasonMaintenance
;
6306 setProperty(kRootDomainSleepReasonKey
, kIOPMMaintenanceSleepKey
);
6308 else if (darkWakeSleepService
)
6310 lastSleepReason
= kIOPMSleepReasonSleepServiceExit
;
6311 setProperty(kRootDomainSleepReasonKey
, kIOPMSleepServiceExitKey
);
6313 changePowerStateWithOverrideTo( SLEEP_STATE
);
6317 // Parked in dark wake, a tickle will return to full wake
6318 rejectWranglerTickle
= false;
6321 else // non-maintenance (network) dark wake
6323 if (checkSystemCanSleep(true))
6325 // Release power clamp, and wait for children idle.
6326 adjustPowerState(true);
6330 changePowerStateToPriv(ON_STATE
);
6332 rejectWranglerTickle
= false;
6338 // The rest are irrelevant while system is in dark wake.
6342 if (flags
.bit
.displaySleep
|| flags
.bit
.sleepDelayChanged
)
6344 bool cancelQuickSpindown
= false;
6346 if (flags
.bit
.sleepDelayChanged
)
6348 DLOG("extra sleep timer changed\n");
6349 cancelIdleSleepTimer();
6350 cancelQuickSpindown
= true;
6354 DLOG("display sleep\n");
6357 if (wranglerAsleep
&& !wranglerSleepIgnored
)
6359 if ( extraSleepDelay
)
6361 // Start a timer here if the System Sleep timer is greater
6362 // than the Display Sleep timer.
6364 startIdleSleepTimer(gRootDomain
->extraSleepDelay
* 60);
6366 else if ( sleepSlider
)
6368 // Accelerate disk spindown if system sleep and display sleep
6369 // sliders are set to the same value (e.g. both set to 5 min),
6370 // and display is about to go dark. Check the system sleep is
6371 // not set to never sleep. Disk sleep setting is ignored.
6373 setQuickSpinDownTimeout();
6374 cancelQuickSpindown
= false;
6378 if (cancelQuickSpindown
)
6379 restoreUserSpinDownTimeout();
6382 if (flags
.bit
.idleSleepEnabled
)
6384 DLOG("idle sleep timer enabled\n");
6387 changePowerStateToPriv(ON_STATE
);
6390 startIdleSleepTimer( idleSeconds
);
6395 // Start idle sleep timer if wrangler went to sleep
6396 // while system sleep was disabled. Disk spindown is
6397 // accelerated upon timer expiration.
6403 uint32_t minutesSinceDisplaySleep
= 0;
6404 uint32_t sleepDelay
= 0;
6406 clock_get_uptime(&now
);
6407 if (CMP_ABSOLUTETIME(&now
, &wranglerSleepTime
) > 0)
6409 SUB_ABSOLUTETIME(&now
, &wranglerSleepTime
);
6410 absolutetime_to_nanoseconds(now
, &nanos
);
6411 minutesSinceDisplaySleep
= nanos
/ (60000000000ULL);
6414 if (extraSleepDelay
> minutesSinceDisplaySleep
)
6416 sleepDelay
= extraSleepDelay
- minutesSinceDisplaySleep
;
6419 startIdleSleepTimer(sleepDelay
* 60);
6420 DLOG("display slept %u min, set idle timer to %u min\n",
6421 minutesSinceDisplaySleep
, sleepDelay
);
6426 if (flags
.bit
.idleSleepDisabled
)
6428 DLOG("idle sleep timer disabled\n");
6429 cancelIdleSleepTimer();
6430 restoreUserSpinDownTimeout();
6434 if (flags
.bit
.adjustPowerState
)
6436 bool sleepASAP
= false;
6438 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
6442 changePowerStateToPriv(ON_STATE
);
6445 // stay awake for at least idleSeconds
6446 startIdleSleepTimer(idleSeconds
);
6449 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
6456 lastSleepReason
= kIOPMSleepReasonIdle
;
6457 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
6460 adjustPowerState(sleepASAP
);
6464 //******************************************************************************
6465 // evaluateAssertions
6467 //******************************************************************************
6468 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
6470 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
6472 messageClients(kIOPMMessageDriverAssertionsChanged
);
6474 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
6478 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
6479 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
6480 wrangler
->setIgnoreIdleTimer( value
);
6484 if (changedBits
& kIOPMDriverAssertionCPUBit
)
6485 evaluatePolicy(kStimulusDarkWakeEvaluate
);
6487 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
6488 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
6490 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
6491 updatePreventIdleSleepList(this, true);
6494 DLOG("Driver assertion ReservedBit7 dropped\n");
6495 updatePreventIdleSleepList(this, false);
6504 //******************************************************************************
6507 //******************************************************************************
6509 void IOPMrootDomain::pmStatsRecordEvent(
6511 AbsoluteTime timestamp
)
6513 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
6514 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
6517 OSData
*publishPMStats
= NULL
;
6519 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
6521 absolutetime_to_nanoseconds(timestamp
, &nsec
);
6523 switch (eventIndex
) {
6524 case kIOPMStatsHibernateImageWrite
:
6526 gPMStats
.hibWrite
.start
= nsec
;
6528 gPMStats
.hibWrite
.stop
= nsec
;
6531 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
6532 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
6535 case kIOPMStatsHibernateImageRead
:
6537 gPMStats
.hibRead
.start
= nsec
;
6539 gPMStats
.hibRead
.stop
= nsec
;
6542 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
6543 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
6545 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
6546 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
6547 publishPMStats
->release();
6548 bzero(&gPMStats
, sizeof(gPMStats
));
6555 * Appends a record of the application response to
6556 * IOPMrootDomain::pmStatsAppResponses
6558 void IOPMrootDomain::pmStatsRecordApplicationResponse(
6559 const OSSymbol
*response
,
6565 OSDictionary
*responseDescription
= NULL
;
6566 OSNumber
*delayNum
= NULL
;
6567 OSNumber
*pidNum
= NULL
;
6568 OSNumber
*msgNum
= NULL
;
6569 const OSSymbol
*appname
;
6570 const OSSymbol
*entryName
;
6571 OSObject
*entryType
;
6574 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
6578 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
6580 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
6581 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
6582 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
))
6584 OSNumber
* entryValue
;
6585 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
6586 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
6587 entryValue
->setValue(delay_ms
);
6592 responseDescription
= OSDictionary::withCapacity(5);
6593 if (responseDescription
)
6596 responseDescription
->setObject(_statsResponseTypeKey
, response
);
6599 if (messageType
!= 0) {
6600 msgNum
= OSNumber::withNumber(messageType
, 32);
6602 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
6607 if (name
&& (strlen(name
) > 0))
6609 appname
= OSSymbol::withCString(name
);
6611 responseDescription
->setObject(_statsNameKey
, appname
);
6616 if (app_pid
!= -1) {
6617 pidNum
= OSNumber::withNumber(app_pid
, 32);
6619 responseDescription
->setObject(_statsPIDKey
, pidNum
);
6624 delayNum
= OSNumber::withNumber(delay_ms
, 32);
6626 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
6627 delayNum
->release();
6630 if (pmStatsAppResponses
) {
6631 pmStatsAppResponses
->setObject(responseDescription
);
6634 responseDescription
->release();
6640 // MARK: PMTraceWorker
6642 //******************************************************************************
6643 // TracePoint support
6645 //******************************************************************************
6647 #define kIOPMRegisterNVRAMTracePointHandlerKey \
6648 "IOPMRegisterNVRAMTracePointHandler"
6650 IOReturn
IOPMrootDomain::callPlatformFunction(
6651 const OSSymbol
* functionName
,
6652 bool waitForFunction
,
6653 void * param1
, void * param2
,
6654 void * param3
, void * param4
)
6656 if (pmTracer
&& functionName
&&
6657 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
6658 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
6660 uint32_t tracePointPhases
, tracePointPCI
;
6661 uint64_t statusCode
;
6663 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
6664 pmTracer
->tracePointTarget
= (void *) param2
;
6665 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
6666 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
6667 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
6668 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
6670 MSG("Sleep failure code 0x%08x 0x%08x\n",
6671 tracePointPCI
, tracePointPhases
);
6673 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
6674 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
6676 return kIOReturnSuccess
;
6679 else if (functionName
&&
6680 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
6682 if (gSleepPolicyHandler
)
6683 return kIOReturnExclusiveAccess
;
6685 return kIOReturnBadArgument
;
6686 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
6687 gSleepPolicyTarget
= (void *) param2
;
6688 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
6689 return kIOReturnSuccess
;
6693 return super::callPlatformFunction(
6694 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
6697 void IOPMrootDomain::tracePoint( uint8_t point
)
6699 if (systemBooting
) return;
6701 PMDebug(kPMLogSleepWakeTracePoint
, point
, 0);
6702 pmTracer
->tracePoint(point
);
6705 if (kIOPMTracePointSleepPowerPlaneDrivers
== point
) IOHibernateIOKitSleep();
6709 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
6711 if (systemBooting
) return;
6713 PMDebug(kPMLogSleepWakeTracePoint
, point
, data
);
6714 pmTracer
->tracePoint(point
, data
);
6717 void IOPMrootDomain::traceDetail( uint32_t detail
)
6720 pmTracer
->traceDetail( detail
);
6723 //******************************************************************************
6724 // PMTraceWorker Class
6726 //******************************************************************************
6729 #define super OSObject
6730 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
6732 #define kPMBestGuessPCIDevicesCount 25
6733 #define kPMMaxRTCBitfieldSize 32
6735 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
6739 me
= OSTypeAlloc( PMTraceWorker
);
6740 if (!me
|| !me
->init())
6745 DLOG("PMTraceWorker %p\n", me
);
6747 // Note that we cannot instantiate the PCI device -> bit mappings here, since
6748 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
6749 // this dictionary lazily.
6751 me
->pciDeviceBitMappings
= NULL
;
6752 me
->pciMappingLock
= IOLockAlloc();
6753 me
->tracePhase
= kIOPMTracePointSystemUp
;
6754 me
->loginWindowPhase
= 0;
6755 me
->traceData32
= 0;
6759 void PMTraceWorker::RTC_TRACE(void)
6761 if (tracePointHandler
&& tracePointTarget
)
6765 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
6768 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
6769 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
6773 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
6775 const OSSymbol
* deviceName
;
6778 IOLockLock(pciMappingLock
);
6780 if (!pciDeviceBitMappings
)
6782 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
6783 if (!pciDeviceBitMappings
)
6787 // Check for bitmask overflow.
6788 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
6791 if ((deviceName
= pciDevice
->copyName()) &&
6792 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
6793 pciDeviceBitMappings
->setObject(deviceName
))
6795 index
= pciDeviceBitMappings
->getCount() - 1;
6796 _LOG("PMTrace PCI array: set object %s => %d\n",
6797 deviceName
->getCStringNoCopy(), index
);
6800 deviceName
->release();
6801 if (!addedToRegistry
&& (index
>= 0))
6802 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
6805 IOLockUnlock(pciMappingLock
);
6809 bool PMTraceWorker::serialize(OSSerialize
*s
) const
6812 if (pciDeviceBitMappings
)
6814 IOLockLock(pciMappingLock
);
6815 ok
= pciDeviceBitMappings
->serialize(s
);
6816 IOLockUnlock(pciMappingLock
);
6821 void PMTraceWorker::tracePoint(uint8_t phase
)
6823 // clear trace detail when phase begins
6824 if (tracePhase
!= phase
)
6829 DLOG("trace point 0x%02x\n", tracePhase
);
6833 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
6835 // clear trace detail when phase begins
6836 if (tracePhase
!= phase
)
6842 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
6846 void PMTraceWorker::traceDetail(uint32_t detail
)
6848 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
6851 traceData32
= detail
;
6852 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
6857 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
6859 loginWindowPhase
= phase
;
6861 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
6865 void PMTraceWorker::tracePCIPowerChange(
6866 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
6869 uint32_t expectedFlag
;
6871 // Ignore PCI changes outside of system sleep/wake.
6872 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
6873 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
6876 // Only record the WillChange transition when going to sleep,
6877 // and the DidChange on the way up.
6878 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
6879 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
6880 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
6881 if (changeFlags
!= expectedFlag
)
6884 // Mark this device off in our bitfield
6885 if (bitNum
< kPMMaxRTCBitfieldSize
)
6887 bitMask
= (1 << bitNum
);
6889 if (kPowerChangeStart
== type
)
6891 traceData32
|= bitMask
;
6892 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
6893 service
->getName(), bitNum
, bitMask
, traceData32
);
6897 traceData32
&= ~bitMask
;
6898 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
6899 service
->getName(), bitNum
, bitMask
, traceData32
);
6907 // MARK: PMHaltWorker
6909 //******************************************************************************
6910 // PMHaltWorker Class
6912 //******************************************************************************
6914 static unsigned int gPMHaltBusyCount
;
6915 static unsigned int gPMHaltIdleCount
;
6916 static int gPMHaltDepth
;
6917 static unsigned long gPMHaltEvent
;
6918 static IOLock
* gPMHaltLock
= 0;
6919 static OSArray
* gPMHaltArray
= 0;
6920 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
6922 PMHaltWorker
* PMHaltWorker::worker( void )
6928 me
= OSTypeAlloc( PMHaltWorker
);
6929 if (!me
|| !me
->init())
6932 me
->lock
= IOLockAlloc();
6936 DLOG("PMHaltWorker %p\n", me
);
6937 me
->retain(); // thread holds extra retain
6938 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
6943 thread_deallocate(thread
);
6948 if (me
) me
->release();
6952 void PMHaltWorker::free( void )
6954 DLOG("PMHaltWorker free %p\n", this);
6960 return OSObject::free();
6963 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
6965 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
6967 IOLockLock( gPMHaltLock
);
6969 me
->depth
= gPMHaltDepth
;
6970 IOLockUnlock( gPMHaltLock
);
6972 while (me
->depth
>= 0)
6974 PMHaltWorker::work( me
);
6976 IOLockLock( gPMHaltLock
);
6977 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
6979 // This is the last thread to finish work on this level,
6980 // inform everyone to start working on next lower level.
6982 me
->depth
= gPMHaltDepth
;
6983 gPMHaltIdleCount
= 0;
6984 thread_wakeup((event_t
) &gPMHaltIdleCount
);
6988 // One or more threads are still working on this level,
6989 // this thread must wait.
6990 me
->depth
= gPMHaltDepth
- 1;
6992 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
6993 } while (me
->depth
!= gPMHaltDepth
);
6995 IOLockUnlock( gPMHaltLock
);
6998 // No more work to do, terminate thread
6999 DLOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
7000 thread_wakeup( &gPMHaltDepth
);
7004 void PMHaltWorker::work( PMHaltWorker
* me
)
7006 IOService
* service
;
7008 AbsoluteTime startTime
;
7017 // Claim an unit of work from the shared pool
7018 IOLockLock( gPMHaltLock
);
7019 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
7022 service
= (IOService
*)inner
->getAnyObject();
7026 inner
->removeObject(service
);
7029 IOLockUnlock( gPMHaltLock
);
7031 break; // no more work at this depth
7033 clock_get_uptime(&startTime
);
7035 if (!service
->isInactive() &&
7036 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
7038 IOLockLock(me
->lock
);
7039 me
->startTime
= startTime
;
7040 me
->service
= service
;
7041 me
->timeout
= false;
7042 IOLockUnlock(me
->lock
);
7044 service
->systemWillShutdown( gPMHaltEvent
);
7046 // Wait for driver acknowledgement
7047 IOLockLock(me
->lock
);
7048 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
7050 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
7053 timeout
= me
->timeout
;
7054 IOLockUnlock(me
->lock
);
7057 deltaTime
= computeDeltaTimeMS(&startTime
);
7058 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
7059 (gIOKitDebug
& kIOLogPMRootDomain
))
7061 LOG("%s driver %s (%p) took %u ms\n",
7062 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
7063 "PowerOff" : "Restart",
7064 service
->getName(), service
,
7065 (uint32_t) deltaTime
);
7073 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
7076 AbsoluteTime startTime
;
7077 AbsoluteTime endTime
;
7081 IOLockLock(me
->lock
);
7082 if (me
->service
&& !me
->timeout
)
7084 startTime
= me
->startTime
;
7086 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
7088 SUB_ABSOLUTETIME(&endTime
, &startTime
);
7089 absolutetime_to_nanoseconds(endTime
, &nano
);
7091 if (nano
> 3000000000ULL)
7094 MSG("%s still waiting on %s\n",
7095 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
7096 "PowerOff" : "Restart",
7097 me
->service
->getName());
7100 IOLockUnlock(me
->lock
);
7104 //******************************************************************************
7105 // acknowledgeSystemWillShutdown
7107 // Acknowledgement from drivers that they have prepared for shutdown/restart.
7108 //******************************************************************************
7110 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
7112 PMHaltWorker
* worker
;
7118 //DLOG("%s acknowledged\n", from->getName());
7119 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
7122 worker
= (PMHaltWorker
*) prop
;
7123 IOLockLock(worker
->lock
);
7124 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
7125 thread_wakeup((event_t
) worker
);
7126 IOLockUnlock(worker
->lock
);
7131 DLOG("%s acknowledged without worker property\n",
7137 //******************************************************************************
7138 // notifySystemShutdown
7140 // Notify all objects in PM tree that system will shutdown or restart
7141 //******************************************************************************
7144 notifySystemShutdown( IOService
* root
, unsigned long event
)
7146 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
7147 IORegistryIterator
* iter
;
7148 IORegistryEntry
* entry
;
7151 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
7152 AbsoluteTime deadline
;
7153 unsigned int totalNodes
= 0;
7155 unsigned int rootDepth
;
7156 unsigned int numWorkers
;
7162 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
7164 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
7166 // Iterate the entire PM tree starting from root
7168 rootDepth
= root
->getDepth( gIOPowerPlane
);
7169 if (!rootDepth
) goto done
;
7171 // debug - for repeated test runs
7172 while (PMHaltWorker::metaClass
->getInstanceCount())
7177 gPMHaltArray
= OSArray::withCapacity(40);
7178 if (!gPMHaltArray
) goto done
;
7181 gPMHaltArray
->flushCollection();
7185 gPMHaltLock
= IOLockAlloc();
7186 if (!gPMHaltLock
) goto done
;
7189 if (!gPMHaltClientAcknowledgeKey
)
7191 gPMHaltClientAcknowledgeKey
=
7192 OSSymbol::withCStringNoCopy("PMShutdown");
7193 if (!gPMHaltClientAcknowledgeKey
) goto done
;
7196 gPMHaltEvent
= event
;
7198 // Depth-first walk of PM plane
7200 iter
= IORegistryIterator::iterateOver(
7201 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
7205 while ((entry
= iter
->getNextObject()))
7207 node
= OSDynamicCast(IOService
, entry
);
7212 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
7215 depth
= node
->getDepth( gIOPowerPlane
);
7216 if (depth
<= rootDepth
)
7221 // adjust to zero based depth
7222 depth
-= (rootDepth
+ 1);
7224 // gPMHaltArray is an array of containers, each container
7225 // refers to nodes with the same depth.
7227 count
= gPMHaltArray
->getCount();
7228 while (depth
>= count
)
7230 // expand array and insert placeholders
7231 gPMHaltArray
->setObject(PLACEHOLDER
);
7234 count
= gPMHaltArray
->getCount();
7237 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
7238 if (inner
== PLACEHOLDER
)
7240 inner
= OSSet::withCapacity(40);
7243 gPMHaltArray
->replaceObject(depth
, inner
);
7248 // PM nodes that appear more than once in the tree will have
7249 // the same depth, OSSet will refuse to add the node twice.
7251 ok
= inner
->setObject(node
);
7254 DLOG("Skipped PM node %s\n", node
->getName());
7260 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
7263 if (inner
!= PLACEHOLDER
)
7264 count
= inner
->getCount();
7265 DLOG("Nodes at depth %u = %u\n", i
, count
);
7268 // strip placeholders (not all depths are populated)
7270 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
7272 if (inner
== PLACEHOLDER
)
7274 gPMHaltArray
->removeObject(i
);
7277 count
= inner
->getCount();
7278 if (count
> numWorkers
)
7280 totalNodes
+= count
;
7284 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
7287 gPMHaltBusyCount
= 0;
7288 gPMHaltIdleCount
= 0;
7289 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
7291 // Create multiple workers (and threads)
7293 if (numWorkers
> kPMHaltMaxWorkers
)
7294 numWorkers
= kPMHaltMaxWorkers
;
7296 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
7297 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
7299 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7300 workers
[i
] = PMHaltWorker::worker();
7302 // Wait for workers to exhaust all available work
7304 IOLockLock(gPMHaltLock
);
7305 while (gPMHaltDepth
>= 0)
7307 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
7309 waitResult
= IOLockSleepDeadline(
7310 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
7311 if (THREAD_TIMED_OUT
== waitResult
)
7314 clock_get_uptime(&now
);
7316 IOLockUnlock(gPMHaltLock
);
7317 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
7320 PMHaltWorker::checkTimeout(workers
[i
], &now
);
7322 IOLockLock(gPMHaltLock
);
7325 IOLockUnlock(gPMHaltLock
);
7327 // Release all workers
7329 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7332 workers
[i
]->release();
7333 // worker also retained by it's own thread
7337 DLOG("%s done\n", __FUNCTION__
);
7341 //*********************************************************************************
7342 // Sleep/Wake logging
7344 //*********************************************************************************
7346 IOMemoryDescriptor
*IOPMrootDomain::getPMTraceMemoryDescriptor(void)
7349 return timeline
->getPMTraceMemoryDescriptor();
7354 // Forwards external reports of detailed events to IOPMTimeline
7355 IOReturn
IOPMrootDomain::recordPMEvent(PMEventDetails
*details
)
7357 if (timeline
&& details
) {
7361 // Record a detailed driver power change event, or...
7362 if(details
->eventClassifier
== kIOPMEventClassDriverEvent
) {
7363 rc
= timeline
->recordDetailedPowerEvent( details
);
7366 // Record a system power management event
7367 else if(details
->eventClassifier
== kIOPMEventClassSystemEvent
) {
7368 rc
= timeline
->recordSystemPowerEvent( details
);
7371 return kIOReturnBadArgument
;
7374 // If we get to record this message, then we've reached the
7375 // end of another successful Sleep --> Wake cycle
7376 // At this point, we pat ourselves in the back and allow
7377 // our Sleep --> Wake UUID to be published
7378 if(details
->eventType
== kIOPMEventTypeWakeDone
) {
7379 timeline
->setSleepCycleInProgressFlag(false);
7383 // Check if its time to clear the timeline buffer
7384 if(getProperty(kIOPMSleepWakeUUIDKey)
7385 && timeline->isSleepCycleInProgress() == false
7386 && timeline->getNumEventsLoggedThisPeriod() > 500) {
7388 // Clear the old UUID
7389 if(pmPowerStateQueue) {
7390 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
7397 return kIOReturnNotReady
;
7400 IOReturn
IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails
*details
)
7402 IOReturn ret
= kIOReturnBadArgument
;
7406 ret
= recordPMEvent(details
);
7413 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7415 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
7416 IOPMDriverAssertionType whichAssertionBits
,
7417 IOPMDriverAssertionLevel assertionLevel
,
7418 IOService
*ownerService
,
7419 const char *ownerDescription
)
7422 IOPMDriverAssertionID newAssertion
;
7427 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
7429 if (kIOReturnSuccess
== ret
)
7430 return newAssertion
;
7435 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
7438 return kIOReturnInternalError
;
7440 return pmAssertions
->releaseAssertion(releaseAssertion
);
7443 IOReturn
IOPMrootDomain::setPMAssertionLevel(
7444 IOPMDriverAssertionID assertionID
,
7445 IOPMDriverAssertionLevel assertionLevel
)
7447 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
7450 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
7452 IOPMDriverAssertionType sysLevels
;
7454 if (!pmAssertions
|| whichAssertion
== 0)
7455 return kIOPMDriverAssertionLevelOff
;
7457 sysLevels
= pmAssertions
->getActivatedAssertions();
7459 // Check that every bit set in argument 'whichAssertion' is asserted
7460 // in the aggregate bits.
7461 if ((sysLevels
& whichAssertion
) == whichAssertion
)
7462 return kIOPMDriverAssertionLevelOn
;
7464 return kIOPMDriverAssertionLevelOff
;
7467 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
7470 return kIOReturnNotFound
;
7472 return pmAssertions
->setUserAssertionLevels(inLevels
);
7475 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
7479 pmAssertions
->publishProperties();
7481 return( IOService::serializeProperties(s
) );
7484 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7487 // MARK: PMSettingHandle
7489 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
7491 void PMSettingHandle::free( void )
7495 pmso
->clientHandleFreed();
7504 // MARK: PMSettingObject
7507 #define super OSObject
7508 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
7511 * Static constructor/initializer for PMSettingObject
7513 PMSettingObject
*PMSettingObject::pmSettingObject(
7514 IOPMrootDomain
*parent_arg
,
7515 IOPMSettingControllerCallback handler_arg
,
7516 OSObject
*target_arg
,
7517 uintptr_t refcon_arg
,
7518 uint32_t supportedPowerSources
,
7519 const OSSymbol
* settings
[],
7520 OSObject
**handle_obj
)
7522 uint32_t settingCount
= 0;
7523 PMSettingObject
*pmso
= 0;
7524 PMSettingHandle
*pmsh
= 0;
7526 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
7529 // count OSSymbol entries in NULL terminated settings array
7530 while (settings
[settingCount
]) {
7533 if (0 == settingCount
)
7536 pmso
= new PMSettingObject
;
7537 if (!pmso
|| !pmso
->init())
7540 pmsh
= new PMSettingHandle
;
7541 if (!pmsh
|| !pmsh
->init())
7544 queue_init(&pmso
->calloutQueue
);
7545 pmso
->parent
= parent_arg
;
7546 pmso
->func
= handler_arg
;
7547 pmso
->target
= target_arg
;
7548 pmso
->refcon
= refcon_arg
;
7549 pmso
->settingCount
= settingCount
;
7551 pmso
->retain(); // handle holds a retain on pmso
7555 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
7556 if (pmso
->publishedFeatureID
) {
7557 for (unsigned int i
=0; i
<settingCount
; i
++) {
7558 // Since there is now at least one listener to this setting, publish
7559 // PM root domain support for it.
7560 parent_arg
->publishPMSetting( settings
[i
],
7561 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
7569 if (pmso
) pmso
->release();
7570 if (pmsh
) pmsh
->release();
7574 void PMSettingObject::free( void )
7576 if (publishedFeatureID
) {
7577 for (uint32_t i
=0; i
<settingCount
; i
++) {
7578 if (publishedFeatureID
[i
]) {
7579 parent
->removePublishedFeature( publishedFeatureID
[i
] );
7583 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
7589 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
7591 (*func
)(target
, type
, object
, refcon
);
7594 void PMSettingObject::clientHandleFreed( void )
7596 parent
->deregisterPMSettingObject(this);
7600 // MARK: IOPMTimeline
7603 #define super OSObject
7605 //*********************************************************************************
7606 //*********************************************************************************
7607 //*********************************************************************************
7609 IOPMTimeline
*IOPMTimeline::timeline(IOPMrootDomain
*root_domain
)
7611 IOPMTimeline
*myself
;
7616 myself
= new IOPMTimeline
;
7619 myself
->owner
= root_domain
;
7626 bool IOPMTimeline::init(void)
7628 if (!super::init()) {
7632 logLock
= IOLockAlloc();
7634 // Fresh timeline, no events logged yet
7635 this->numEventsLoggedThisPeriod
= 0;
7636 this->sleepCycleInProgress
= false;
7638 //this->setEventsRecordingLevel(1); // TODO
7639 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked
);
7644 void IOPMTimeline::free(void)
7646 if (pmTraceMemoryDescriptor
) {
7647 pmTraceMemoryDescriptor
->release();
7648 pmTraceMemoryDescriptor
= NULL
;
7651 IOLockFree(logLock
);
7656 IOMemoryDescriptor
*IOPMTimeline::getPMTraceMemoryDescriptor()
7658 return pmTraceMemoryDescriptor
;
7661 //*********************************************************************************
7662 //*********************************************************************************
7663 //*********************************************************************************
7665 bool IOPMTimeline::setProperties(OSDictionary
*d
)
7668 OSBoolean
*b
= NULL
;
7669 bool changed
= false;
7671 /* Changes size of detailed events buffer */
7672 n
= (OSNumber
*)d
->getObject(kIOPMTimelineSystemNumberTrackedKey
);
7673 if (OSDynamicCast(OSNumber
, n
))
7676 this->setEventsTrackedCount(n
->unsigned32BitValue());
7680 /* enables or disables system events */
7681 b
= (OSBoolean
*)d
->getObject(kIOPMTimelineEnabledKey
);
7685 this->setEventsRecordingLevel((int)(kOSBooleanTrue
== b
));
7691 //*********************************************************************************
7692 //*********************************************************************************
7693 //*********************************************************************************
7695 OSDictionary
*IOPMTimeline::copyInfoDictionary(void)
7697 OSDictionary
*out
= OSDictionary::withCapacity(3);
7703 n
= OSNumber::withNumber(hdr
->sizeEntries
, 32);
7704 out
->setObject(kIOPMTimelineSystemNumberTrackedKey
, n
);
7707 n
= OSNumber::withNumber(hdr
->sizeBytes
, 32);
7708 out
->setObject(kIOPMTimelineSystemBufferSizeKey
, n
);
7712 out
->setObject(kIOPMTimelineEnabledKey
, eventsRecordingLevel
? kOSBooleanTrue
: kOSBooleanFalse
);
7717 //*********************************************************************************
7718 //*********************************************************************************
7719 //*********************************************************************************
7721 /* IOPMTimeline::recordSystemPowerEvent()
7723 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
7724 * Type arguments include "system events", and "Intermediate events"
7726 * - System Events have paired "start" and "stop" events.
7727 * - A start event shall be followed by a stop event.
7728 * - Any number of Intermediate Events may fall between the
7729 * start and stop events.
7730 * - Intermediate events are meaningless outside the bounds of a system event's
7731 * start & stoup routines.
7732 * - It's invalid to record a Start event without a following Stop event; e.g. two
7733 * Start events without an intervenining Stop event is invalid.
7736 * - The first recorded system event shall be preceded by an entry with type == 0
7737 * - IOPMTimeline may choose not to record intermediate events while there's not
7738 * a system event in process.
7740 IOReturn
IOPMTimeline::recordSystemPowerEvent( PMEventDetails
*details
)
7742 static bool wakeDonePending
= true;
7743 IOPMSystemEventRecord
*record_to
= NULL
;
7744 OSString
*swUUIDKey
= NULL
;
7745 uint32_t useIndex
= 0;
7748 return kIOReturnBadArgument
;
7751 return kIOReturnNotReady
;
7753 if (details
->eventType
== kIOPMEventTypeWakeDone
)
7755 if(!wakeDonePending
)
7756 return kIOReturnBadArgument
;
7759 IOLockLock(logLock
);
7761 if (details
->eventType
== kIOPMEventTypeWake
) {
7762 wakeDonePending
= true;
7763 } else if (details
->eventType
== kIOPMEventTypeWakeDone
) {
7764 wakeDonePending
= false;
7767 systemState
= details
->eventType
;
7769 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7771 // The entry immediately after the latest entry (and thus
7772 // immediately before the first entry) shall have a type 0.
7773 if (useIndex
+ 1 >= hdr
->sizeEntries
) {
7774 traceBuffer
[useIndex
+ 1].eventType
= 0;
7776 traceBuffer
[0].eventType
= 0;
7779 record_to
= &traceBuffer
[useIndex
];
7780 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7783 record_to
->eventType
= details
->eventType
;
7784 record_to
->eventReason
= details
->reason
;
7785 record_to
->eventResult
= details
->result
;
7786 pmEventTimeStamp(&record_to
->timestamp
);
7788 // If caller doesn't provide a UUID, we'll use the UUID that's posted
7789 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
7790 if (!details
->uuid
) {
7791 swUUIDKey
= OSDynamicCast(OSString
, owner
->copyProperty(kIOPMSleepWakeUUIDKey
));
7794 details
->uuid
= swUUIDKey
->getCStringNoCopy();
7798 strncpy(record_to
->uuid
, details
->uuid
, kMaxPMStringLength
);
7801 swUUIDKey
->release();
7803 numEventsLoggedThisPeriod
++;
7806 IOLockUnlock(logLock
);
7808 return kIOReturnSuccess
;
7812 //*********************************************************************************
7813 //*********************************************************************************
7814 //*********************************************************************************
7816 IOReturn
IOPMTimeline::recordDetailedPowerEvent( PMEventDetails
*details
)
7818 IOPMSystemEventRecord
*record_to
= NULL
;
7821 if (!details
->eventType
|| !details
->ownerName
)
7822 return kIOReturnBadArgument
;
7824 IOLockLock(logLock
);
7826 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7828 record_to
= (IOPMSystemEventRecord
*)&traceBuffer
[useIndex
];
7829 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7832 record_to
->eventType
= details
->eventType
;
7833 if (details
->ownerName
&& (strlen(details
->ownerName
) > 1)) {
7834 strlcpy( record_to
->ownerName
,
7836 sizeof(record_to
->ownerName
));
7839 record_to
->ownerDisambiguateID
= details
->ownerUnique
;
7841 if (details
->interestName
&& (strlen(details
->interestName
) > 1)) {
7842 strlcpy(record_to
->interestName
,
7843 details
->interestName
,
7844 sizeof(record_to
->interestName
));
7847 record_to
->oldState
= details
->oldState
;
7848 record_to
->newState
= details
->newState
;
7849 record_to
->eventResult
= details
->result
;
7850 record_to
->elapsedTimeUS
= details
->elapsedTimeUS
;
7851 pmEventTimeStamp(&record_to
->timestamp
);
7853 numEventsLoggedThisPeriod
++;
7856 IOLockUnlock(logLock
);
7857 return kIOReturnSuccess
;
7860 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
7861 return this->numEventsLoggedThisPeriod
;
7864 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount
) {
7865 this->numEventsLoggedThisPeriod
= newCount
;
7868 bool IOPMTimeline::isSleepCycleInProgress() {
7869 return this->sleepCycleInProgress
;
7872 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag
) {
7873 this->sleepCycleInProgress
= flag
;
7875 //*********************************************************************************
7876 //*********************************************************************************
7877 //*********************************************************************************
7879 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked
)
7881 size_t make_buf_size
= 0;
7883 make_buf_size
= sizeof(IOPMTraceBufferHeader
) + (newTracked
* sizeof(IOPMSystemEventRecord
));
7885 IOLockLock(logLock
);
7887 if (pmTraceMemoryDescriptor
) {
7888 pmTraceMemoryDescriptor
->release();
7889 pmTraceMemoryDescriptor
= NULL
;
7895 if (0 == newTracked
)
7897 IOLog("IOPMrootDomain -> erased buffer.\n");
7901 pmTraceMemoryDescriptor
= IOBufferMemoryDescriptor::withOptions(
7902 kIOMemoryKernelUserShared
| kIODirectionIn
| kIOMemoryMapperNone
,
7905 if (!pmTraceMemoryDescriptor
)
7907 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size
);
7911 pmTraceMemoryDescriptor
->prepare(kIODirectionIn
);
7913 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
7914 hdr
= (IOPMTraceBufferHeader
*)pmTraceMemoryDescriptor
->getBytesNoCopy();
7916 // Recorded events occupy the remaining bulk of the buffer
7917 traceBuffer
= (IOPMSystemEventRecord
*)((uint8_t *)hdr
+ sizeof(IOPMTraceBufferHeader
));
7919 bzero(hdr
, make_buf_size
);
7921 hdr
->sizeBytes
= make_buf_size
;
7922 hdr
->sizeEntries
= newTracked
;
7924 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size
, (unsigned int)(uintptr_t)traceBuffer
);
7927 IOLockUnlock(logLock
);
7930 //*********************************************************************************
7931 //*********************************************************************************
7932 //*********************************************************************************
7934 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits
)
7943 /* static helper to IOPMTimeline
7945 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index
, uint32_t limit
)
7955 inc_index
= (was_index
+1)%limit
;
7956 } while (!OSCompareAndSwap(was_index
, inc_index
, index
));
7962 // MARK: PMAssertionsTracker
7964 //*********************************************************************************
7965 //*********************************************************************************
7966 //*********************************************************************************
7967 // class PMAssertionsTracker Implementation
7969 #define kAssertUniqueIDStart 500
7971 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
7973 PMAssertionsTracker
*myself
;
7975 myself
= new PMAssertionsTracker
;
7979 myself
->owner
= rootDomain
;
7980 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
7981 myself
->assertionsArray
= OSArray::withCapacity(5);
7982 myself
->assertionsKernel
= 0;
7983 myself
->assertionsUser
= 0;
7984 myself
->assertionsCombined
= 0;
7985 myself
->assertionsArrayLock
= IOLockAlloc();
7986 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
7988 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
7996 * - Update assertionsKernel to reflect the state of all
7997 * assertions in the kernel.
7998 * - Update assertionsCombined to reflect both kernel & user space.
8000 void PMAssertionsTracker::tabulate(void)
8004 PMAssertStruct
*_a
= NULL
;
8007 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
8008 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
8012 assertionsKernel
= 0;
8013 assertionsCombined
= 0;
8015 if (!assertionsArray
)
8018 if ((count
= assertionsArray
->getCount()))
8020 for (i
=0; i
<count
; i
++)
8022 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8025 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8026 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
8027 assertionsKernel
|= _a
->assertionBits
;
8032 tabulateProducerCount
++;
8033 assertionsCombined
= assertionsKernel
| assertionsUser
;
8035 if ((assertionsKernel
!= oldKernel
) ||
8036 (assertionsCombined
!= oldCombined
))
8038 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
8042 void PMAssertionsTracker::publishProperties( void )
8044 OSArray
*assertionsSummary
= NULL
;
8046 if (tabulateConsumerCount
!= tabulateProducerCount
)
8048 IOLockLock(assertionsArrayLock
);
8050 tabulateConsumerCount
= tabulateProducerCount
;
8052 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8054 assertionsSummary
= copyAssertionsArray();
8055 if (assertionsSummary
)
8057 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
8058 assertionsSummary
->release();
8062 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
8065 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8067 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
8069 IOLockUnlock(assertionsArrayLock
);
8073 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
8075 PMAssertStruct
*_a
= NULL
;
8082 && (count
= assertionsArray
->getCount()))
8084 for (i
=0; i
<count
; i
++)
8086 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8089 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8090 if (_a
&& (_id
== _a
->id
)) {
8107 /* PMAssertionsTracker::handleCreateAssertion
8108 * Perform assertion work on the PM workloop. Do not call directly.
8110 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
8116 IOLockLock(assertionsArrayLock
);
8117 assertionsArray
->setObject(newAssertion
);
8118 IOLockUnlock(assertionsArrayLock
);
8119 newAssertion
->release();
8123 return kIOReturnSuccess
;
8126 /* PMAssertionsTracker::createAssertion
8127 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8130 IOReturn
PMAssertionsTracker::createAssertion(
8131 IOPMDriverAssertionType which
,
8132 IOPMDriverAssertionLevel level
,
8133 IOService
*serviceID
,
8134 const char *whoItIs
,
8135 IOPMDriverAssertionID
*outID
)
8137 OSData
*dataStore
= NULL
;
8138 PMAssertStruct track
;
8140 // Warning: trillions and trillions of created assertions may overflow the unique ID.
8141 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
8142 track
.level
= level
;
8143 track
.assertionBits
= which
;
8144 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
) : 0;
8145 track
.ownerService
= serviceID
;
8146 track
.modifiedTime
= 0;
8147 pmEventTimeStamp(&track
.createdTime
);
8149 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
8152 if (track
.ownerString
)
8153 track
.ownerString
->release();
8154 return kIOReturnNoMemory
;
8159 if (owner
&& owner
->pmPowerStateQueue
) {
8160 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
8163 return kIOReturnSuccess
;
8166 /* PMAssertionsTracker::handleReleaseAssertion
8167 * Runs in PM workloop. Do not call directly.
8169 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
8170 IOPMDriverAssertionID _id
)
8175 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
8178 return kIOReturnNotFound
;
8180 IOLockLock(assertionsArrayLock
);
8181 if (assertStruct
->ownerString
)
8182 assertStruct
->ownerString
->release();
8184 assertionsArray
->removeObject(index
);
8185 IOLockUnlock(assertionsArrayLock
);
8188 return kIOReturnSuccess
;
8191 /* PMAssertionsTracker::releaseAssertion
8192 * Releases an assertion and affects system behavior if appropiate.
8193 * Actual work happens on PM workloop.
8195 IOReturn
PMAssertionsTracker::releaseAssertion(
8196 IOPMDriverAssertionID _id
)
8198 if (owner
&& owner
->pmPowerStateQueue
) {
8199 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
8201 return kIOReturnSuccess
;
8204 /* PMAssertionsTracker::handleSetAssertionLevel
8205 * Runs in PM workloop. Do not call directly.
8207 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
8208 IOPMDriverAssertionID _id
,
8209 IOPMDriverAssertionLevel _level
)
8211 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
8215 if (!assertStruct
) {
8216 return kIOReturnNotFound
;
8219 IOLockLock(assertionsArrayLock
);
8220 pmEventTimeStamp(&assertStruct
->modifiedTime
);
8221 assertStruct
->level
= _level
;
8222 IOLockUnlock(assertionsArrayLock
);
8225 return kIOReturnSuccess
;
8228 /* PMAssertionsTracker::setAssertionLevel
8230 IOReturn
PMAssertionsTracker::setAssertionLevel(
8231 IOPMDriverAssertionID _id
,
8232 IOPMDriverAssertionLevel _level
)
8234 if (owner
&& owner
->pmPowerStateQueue
) {
8235 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
8236 (void *)_level
, _id
);
8239 return kIOReturnSuccess
;
8242 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
8244 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
8248 if (new_user_levels
!= assertionsUser
)
8250 assertionsUser
= new_user_levels
;
8251 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
8255 return kIOReturnSuccess
;
8258 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
8259 IOPMDriverAssertionType new_user_levels
)
8261 if (gIOPMWorkLoop
) {
8262 gIOPMWorkLoop
->runAction(
8263 OSMemberFunctionCast(
8266 &PMAssertionsTracker::handleSetUserAssertionLevels
),
8268 (void *) &new_user_levels
, 0, 0, 0);
8271 return kIOReturnSuccess
;
8275 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
8279 OSArray
*outArray
= NULL
;
8281 if (!assertionsArray
||
8282 (0 == (count
= assertionsArray
->getCount())) ||
8283 (NULL
== (outArray
= OSArray::withCapacity(count
))))
8288 for (i
=0; i
<count
; i
++)
8290 PMAssertStruct
*_a
= NULL
;
8292 OSDictionary
*details
= NULL
;
8294 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8295 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
8297 OSNumber
*_n
= NULL
;
8299 details
= OSDictionary::withCapacity(7);
8303 outArray
->setObject(details
);
8306 _n
= OSNumber::withNumber(_a
->id
, 64);
8308 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
8311 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
8313 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
8316 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
8318 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
8321 _n
= OSNumber::withNumber((uintptr_t)_a
->ownerService
, 64);
8323 details
->setObject(kIOPMDriverAssertionOwnerServiceKey
, _n
);
8326 _n
= OSNumber::withNumber(_a
->level
, 64);
8328 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
8331 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
8333 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
8337 if (_a
->ownerString
) {
8338 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
8347 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
8349 return assertionsCombined
;
8352 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
8353 IOPMDriverAssertionType type
)
8355 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
8357 return kIOPMDriverAssertionLevelOn
;
8359 return kIOPMDriverAssertionLevelOff
;
8363 //*********************************************************************************
8364 //*********************************************************************************
8365 //*********************************************************************************
8368 static void pmEventTimeStamp(uint64_t *recordTS
)
8376 // We assume tsec fits into 32 bits; 32 bits holds enough
8377 // seconds for 136 years since the epoch in 1970.
8378 clock_get_calendar_microtime(&tsec
, &tusec
);
8381 // Pack the sec & microsec calendar time into a uint64_t, for fun.
8383 *recordTS
|= (uint32_t)tusec
;
8384 *recordTS
|= ((uint64_t)tsec
<< 32);
8390 // MARK: IORootParent
8392 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8394 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
8396 // The reason that root domain needs a root parent is to facilitate demand
8397 // sleep, since a power change from the root parent cannot be vetoed.
8399 // The above statement is no longer true since root domain now performs
8400 // demand sleep using overrides. But root parent remains to avoid changing
8401 // the power tree stacking. Root parent is parked at the max power state.
8404 static IOPMPowerState patriarchPowerStates
[2] =
8406 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
8407 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
8410 void IORootParent::initialize( void )
8414 bool IORootParent::start( IOService
* nub
)
8416 IOService::start(nub
);
8417 attachToParent( getRegistryRoot(), gIOPowerPlane
);
8419 registerPowerDriver(this, patriarchPowerStates
, 2);
8424 void IORootParent::shutDownSystem( void )
8428 void IORootParent::restartSystem( void )
8432 void IORootParent::sleepSystem( void )
8436 void IORootParent::dozeSystem( void )
8440 void IORootParent::sleepToDoze( void )
8444 void IORootParent::wakeSystem( void )
8448 OSObject
* IORootParent::copyProperty( const char * aKey
) const
8450 return (IOService::copyProperty(aKey
));