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 getPlatform()->PMLog(kIOPMrootDomainClass
, 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 // Notify platform that sleep has begun
2539 getPlatform()->callPlatformFunction(
2540 sleepMessagePEFunction
, false,
2541 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2544 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2545 // But tellClientsWithResponse() must be called for both.
2546 ignoreTellChangeDown
= true;
2549 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2552 //******************************************************************************
2555 // Override the superclass implementation to send a different message type.
2556 // This must be idle sleep since we don't ask during any other power change.
2557 //******************************************************************************
2559 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2561 DLOG("askChangeDown %u->%u\n",
2562 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2564 // Don't log for dark wake entry
2565 if (kSystemTransitionSleep
== _systemTransitionType
)
2566 tracePoint( kIOPMTracePointSleepApplications
);
2568 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2571 //******************************************************************************
2572 // askChangeDownDone
2574 // Called by PM after all apps have responded to kIOMessageCanSystemSleep.
2575 // pmconfigd may create a deny sleep assertion before ack'ing.
2576 //******************************************************************************
2578 void IOPMrootDomain::askChangeDownDone(
2579 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2581 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2582 *inOutChangeFlags
, *cancel
,
2583 _systemTransitionType
,
2584 _currentCapability
, _pendingCapability
);
2586 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2588 // Dark->Sleep transition.
2589 // Check if there are any deny sleep assertions.
2590 // Full->Dark transition is never cancelled.
2592 if (!checkSystemCanSleep(true))
2594 // Cancel dark wake to sleep transition.
2595 // Must re-scan assertions upon entering dark wake.
2598 DLOG("cancel dark->sleep\n");
2603 //******************************************************************************
2606 // Notify registered applications and kernel clients that we are not dropping
2609 // We override the superclass implementation so we can send a different message
2610 // type to the client or application being notified.
2612 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2613 //******************************************************************************
2615 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2617 DLOG("tellNoChangeDown %u->%u\n",
2618 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2620 // Sleep canceled, clear the sleep trace point.
2621 tracePoint(kIOPMTracePointSystemUp
);
2627 // stay awake for at least idleSeconds
2628 startIdleSleepTimer(idleSeconds
);
2631 else if (sleepSlider
&& wranglerAsleep
)
2633 // Display wrangler is already asleep, it won't trigger the next
2634 // idle sleep attempt. Schedule a future idle sleep attempt, and
2635 // also push out the next idle sleep attempt.
2637 startIdleSleepTimer( kIdleSleepRetryInterval
);
2640 IOService::setAdvisoryTickleEnable( true );
2641 return tellClients( kIOMessageSystemWillNotSleep
);
2644 //******************************************************************************
2647 // Notify registered applications and kernel clients that we are raising power.
2649 // We override the superclass implementation so we can send a different message
2650 // type to the client or application being notified.
2651 //******************************************************************************
2653 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2656 DLOG("tellChangeUp %u->%u\n",
2657 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2659 ignoreTellChangeDown
= false;
2661 if ( stateNum
== ON_STATE
)
2663 // Direct callout into OSKext so it can disable kext unloads
2664 // during sleep/wake to prevent deadlocks.
2665 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2667 // Notify platform that sleep was cancelled or resumed.
2668 getPlatform()->callPlatformFunction(
2669 sleepMessagePEFunction
, false,
2670 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2673 if (getPowerState() == ON_STATE
)
2675 // this is a quick wake from aborted sleep
2676 if (idleSeconds
&& !wrangler
)
2678 // stay awake for at least idleSeconds
2679 startIdleSleepTimer(idleSeconds
);
2681 IOService::setAdvisoryTickleEnable( true );
2682 tellClients( kIOMessageSystemWillPowerOn
);
2685 tracePoint( kIOPMTracePointWakeApplications
);
2687 if (pmStatsAppResponses
)
2689 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
2690 pmStatsAppResponses
->release();
2691 pmStatsAppResponses
= OSArray::withCapacity(5);
2694 tellClients( kIOMessageSystemHasPoweredOn
);
2698 //******************************************************************************
2699 // sysPowerDownHandler
2701 // Perform a vfs sync before system sleep.
2702 //******************************************************************************
2704 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2705 void * target
, void * refCon
,
2706 UInt32 messageType
, IOService
* service
,
2707 void * messageArgs
, vm_size_t argSize
)
2711 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2714 return kIOReturnUnsupported
;
2716 if (messageType
== kIOMessageSystemCapabilityChange
)
2718 IOPMSystemCapabilityChangeParameters
* params
=
2719 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2721 // Interested applications have been notified of an impending power
2722 // change and have acked (when applicable).
2723 // This is our chance to save whatever state we can before powering
2725 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2728 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2729 params
->fromCapabilities
, params
->toCapabilities
,
2730 params
->changeFlags
);
2732 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2733 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2734 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2736 // We will ack within 20 seconds
2737 params
->maxWaitForReply
= 20 * 1000 * 1000;
2739 gRootDomain
->evaluateSystemSleepPolicyEarly();
2741 // add in time we could spend freeing pages
2742 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2744 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2746 DLOG("sysPowerDownHandler timeout %d s\n", (int) (params
->maxWaitForReply
/ 1000 / 1000));
2749 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2751 // Purposely delay the ack and hope that shutdown occurs quickly.
2752 // Another option is not to schedule the thread and wait for
2754 AbsoluteTime deadline
;
2755 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2756 thread_call_enter1_delayed(
2757 gRootDomain
->diskSyncCalloutEntry
,
2758 (thread_call_param_t
) params
->notifyRef
,
2763 gRootDomain
->diskSyncCalloutEntry
,
2764 (thread_call_param_t
) params
->notifyRef
);
2768 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2769 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2770 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2772 // We will ack within 110 seconds
2773 params
->maxWaitForReply
= 110 * 1000 * 1000;
2776 gRootDomain
->diskSyncCalloutEntry
,
2777 (thread_call_param_t
) params
->notifyRef
);
2780 ret
= kIOReturnSuccess
;
2786 //******************************************************************************
2787 // handleQueueSleepWakeUUID
2789 // Called from IOPMrootDomain when we're initiating a sleep,
2790 // or indirectly from PM configd when PM decides to clear the UUID.
2791 // PM clears the UUID several minutes after successful wake from sleep,
2792 // so that we might associate App spindumps with the immediately previous
2795 // @param obj has a retain on it. We're responsible for releasing that retain.
2796 //******************************************************************************
2798 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2800 OSString
*str
= NULL
;
2802 if (kOSBooleanFalse
== obj
)
2804 handlePublishSleepWakeUUID(NULL
);
2806 else if ((str
= OSDynamicCast(OSString
, obj
)))
2808 // This branch caches the UUID for an upcoming sleep/wake
2809 if (queuedSleepWakeUUIDString
) {
2810 queuedSleepWakeUUIDString
->release();
2811 queuedSleepWakeUUIDString
= NULL
;
2813 queuedSleepWakeUUIDString
= str
;
2814 queuedSleepWakeUUIDString
->retain();
2816 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2825 //******************************************************************************
2826 // handlePublishSleepWakeUUID
2828 // Called from IOPMrootDomain when we're initiating a sleep,
2829 // or indirectly from PM configd when PM decides to clear the UUID.
2830 // PM clears the UUID several minutes after successful wake from sleep,
2831 // so that we might associate App spindumps with the immediately previous
2833 //******************************************************************************
2835 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2840 * Clear the current UUID
2842 if (gSleepWakeUUIDIsSet
)
2844 DLOG("SleepWake UUID cleared\n");
2846 OSString
*UUIDstring
= NULL
;
2849 (UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))))
2851 PMEventDetails
*details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDClear
,
2852 UUIDstring
->getCStringNoCopy(), NULL
, 0);
2854 timeline
->recordSystemPowerEvent( details
);
2857 timeline
->setNumEventsLoggedThisPeriod(0);
2860 gSleepWakeUUIDIsSet
= false;
2862 removeProperty(kIOPMSleepWakeUUIDKey
);
2863 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2867 * Optionally, publish a new UUID
2869 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2871 OSString
*publishThisUUID
= NULL
;
2873 publishThisUUID
= queuedSleepWakeUUIDString
;
2874 publishThisUUID
->retain();
2877 PMEventDetails
*details
;
2878 details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDSet
,
2879 publishThisUUID
->getCStringNoCopy(), NULL
, 0);
2881 timeline
->recordSystemPowerEvent( details
);
2886 if (publishThisUUID
)
2888 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
2889 publishThisUUID
->release();
2892 gSleepWakeUUIDIsSet
= true;
2893 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
2895 queuedSleepWakeUUIDString
->release();
2896 queuedSleepWakeUUIDString
= NULL
;
2900 //******************************************************************************
2901 // changePowerStateTo & changePowerStateToPriv
2903 // Override of these methods for logging purposes.
2904 //******************************************************************************
2906 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
2908 DLOG("changePowerStateTo(%lu)\n", ordinal
);
2910 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2911 return kIOReturnUnsupported
;
2913 return super::changePowerStateTo(ordinal
);
2916 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
2918 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
2920 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2921 return kIOReturnUnsupported
;
2923 return super::changePowerStateToPriv(ordinal
);
2926 //******************************************************************************
2929 //******************************************************************************
2931 bool IOPMrootDomain::activitySinceSleep(void)
2933 return (userActivityCount
!= userActivityAtSleep
);
2936 bool IOPMrootDomain::abortHibernation(void)
2938 bool ret
= activitySinceSleep();
2940 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
2942 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
2943 hibernateAborted
= true;
2949 hibernate_should_abort(void)
2952 return (gRootDomain
->abortHibernation());
2957 //******************************************************************************
2958 // sleepOnClamshellClosed
2960 // contains the logic to determine if the system should sleep when the clamshell
2962 //******************************************************************************
2964 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2966 if (!clamshellExists
)
2969 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
2970 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
2972 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
2975 void IOPMrootDomain::sendClientClamshellNotification( void )
2977 /* Only broadcast clamshell alert if clamshell exists. */
2978 if (!clamshellExists
)
2981 setProperty(kAppleClamshellStateKey
,
2982 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
2984 setProperty(kAppleClamshellCausesSleepKey
,
2985 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
2987 /* Argument to message is a bitfiel of
2988 * ( kClamshellStateBit | kClamshellSleepBit )
2990 messageClients(kIOPMMessageClamshellStateChange
,
2991 (void *) ( (clamshellClosed
? kClamshellStateBit
: 0)
2992 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
2995 //******************************************************************************
2996 // getSleepSupported
2999 //******************************************************************************
3001 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3003 return( platformSleepSupport
);
3006 //******************************************************************************
3007 // setSleepSupported
3010 //******************************************************************************
3012 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3014 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3015 OSBitOrAtomic(flags
, &platformSleepSupport
);
3018 //******************************************************************************
3019 // setDisableClamShellSleep
3021 //******************************************************************************
3023 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3025 if (gIOPMWorkLoop
->inGate() == false) {
3027 gIOPMWorkLoop
->runAction(
3028 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3035 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3036 if ( clamshellSleepDisabled
!= val
)
3038 clamshellSleepDisabled
= val
;
3039 // If clamshellSleepDisabled is reset to 0, reevaluate if
3040 // system need to go to sleep due to clamshell state
3041 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3042 handlePowerNotification(kLocalEvalClamshellCommand
);
3047 //******************************************************************************
3051 //******************************************************************************
3053 void IOPMrootDomain::wakeFromDoze( void )
3055 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3061 //******************************************************************************
3064 // Adds a new feature to the supported features dictionary
3065 //******************************************************************************
3067 void IOPMrootDomain::publishFeature( const char * feature
)
3069 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3072 //******************************************************************************
3073 // publishFeature (with supported power source specified)
3075 // Adds a new feature to the supported features dictionary
3076 //******************************************************************************
3078 void IOPMrootDomain::publishFeature(
3079 const char *feature
,
3080 uint32_t supportedWhere
,
3081 uint32_t *uniqueFeatureID
)
3083 static uint16_t next_feature_id
= 500;
3085 OSNumber
*new_feature_data
= NULL
;
3086 OSNumber
*existing_feature
= NULL
;
3087 OSArray
*existing_feature_arr
= NULL
;
3088 OSObject
*osObj
= NULL
;
3089 uint32_t feature_value
= 0;
3091 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3093 if(!supportedWhere
) {
3094 // Feature isn't supported anywhere!
3098 if(next_feature_id
> 5000) {
3099 // Far, far too many features!
3103 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3105 OSDictionary
*features
=
3106 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3108 // Create new features dict if necessary
3109 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3110 features
= OSDictionary::withDictionary(features
);
3112 features
= OSDictionary::withCapacity(1);
3115 // Create OSNumber to track new feature
3117 next_feature_id
+= 1;
3118 if( uniqueFeatureID
) {
3119 // We don't really mind if the calling kext didn't give us a place
3120 // to stash their unique id. Many kexts don't plan to unload, and thus
3121 // have no need to remove themselves later.
3122 *uniqueFeatureID
= next_feature_id
;
3125 feature_value
= (uint32_t)next_feature_id
;
3126 feature_value
<<= 16;
3127 feature_value
+= supportedWhere
;
3129 new_feature_data
= OSNumber::withNumber(
3130 (unsigned long long)feature_value
, 32);
3132 // Does features object already exist?
3133 if( (osObj
= features
->getObject(feature
)) )
3135 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3137 // We need to create an OSArray to hold the now 2 elements.
3138 existing_feature_arr
= OSArray::withObjects(
3139 (const OSObject
**)&existing_feature
, 1, 2);
3140 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3142 // Add object to existing array
3143 existing_feature_arr
= OSArray::withArray(
3144 existing_feature_arr
,
3145 existing_feature_arr
->getCount() + 1);
3148 if (existing_feature_arr
)
3150 existing_feature_arr
->setObject(new_feature_data
);
3151 features
->setObject(feature
, existing_feature_arr
);
3152 existing_feature_arr
->release();
3153 existing_feature_arr
= 0;
3156 // The easy case: no previously existing features listed. We simply
3157 // set the OSNumber at key 'feature' and we're on our way.
3158 features
->setObject(feature
, new_feature_data
);
3161 new_feature_data
->release();
3163 setProperty(kRootDomainSupportedFeatures
, features
);
3165 features
->release();
3167 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3169 // Notify EnergySaver and all those in user space so they might
3170 // re-populate their feature specific UI
3171 if(pmPowerStateQueue
) {
3172 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3176 //******************************************************************************
3177 // removePublishedFeature
3179 // Removes previously published feature
3180 //******************************************************************************
3182 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3184 IOReturn ret
= kIOReturnError
;
3185 uint32_t feature_value
= 0;
3186 uint16_t feature_id
= 0;
3187 bool madeAChange
= false;
3189 OSSymbol
*dictKey
= NULL
;
3190 OSCollectionIterator
*dictIterator
= NULL
;
3191 OSArray
*arrayMember
= NULL
;
3192 OSNumber
*numberMember
= NULL
;
3193 OSObject
*osObj
= NULL
;
3194 OSNumber
*osNum
= NULL
;
3195 OSArray
*arrayMemberCopy
;
3197 if (kBadPMFeatureID
== removeFeatureID
)
3198 return kIOReturnNotFound
;
3200 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3202 OSDictionary
*features
=
3203 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3205 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3207 // Any modifications to the dictionary are made to the copy to prevent
3208 // races & crashes with userland clients. Dictionary updated
3209 // automically later.
3210 features
= OSDictionary::withDictionary(features
);
3213 ret
= kIOReturnNotFound
;
3217 // We iterate 'features' dictionary looking for an entry tagged
3218 // with 'removeFeatureID'. If found, we remove it from our tracking
3219 // structures and notify the OS via a general interest message.
3221 dictIterator
= OSCollectionIterator::withCollection(features
);
3226 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3228 osObj
= features
->getObject(dictKey
);
3230 // Each Feature is either tracked by an OSNumber
3231 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3233 feature_value
= numberMember
->unsigned32BitValue();
3234 feature_id
= (uint16_t)(feature_value
>> 16);
3236 if( feature_id
== (uint16_t)removeFeatureID
)
3239 features
->removeObject(dictKey
);
3244 // Or tracked by an OSArray of OSNumbers
3245 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3247 unsigned int arrayCount
= arrayMember
->getCount();
3249 for(unsigned int i
=0; i
<arrayCount
; i
++)
3251 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3256 feature_value
= osNum
->unsigned32BitValue();
3257 feature_id
= (uint16_t)(feature_value
>> 16);
3259 if( feature_id
== (uint16_t)removeFeatureID
)
3262 if( 1 == arrayCount
) {
3263 // If the array only contains one element, remove
3265 features
->removeObject(dictKey
);
3267 // Otherwise remove the element from a copy of the array.
3268 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3269 if (arrayMemberCopy
)
3271 arrayMemberCopy
->removeObject(i
);
3272 features
->setObject(dictKey
, arrayMemberCopy
);
3273 arrayMemberCopy
->release();
3284 dictIterator
->release();
3288 ret
= kIOReturnSuccess
;
3290 setProperty(kRootDomainSupportedFeatures
, features
);
3292 // Notify EnergySaver and all those in user space so they might
3293 // re-populate their feature specific UI
3294 if(pmPowerStateQueue
) {
3295 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3298 ret
= kIOReturnNotFound
;
3302 if(features
) features
->release();
3303 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3307 //******************************************************************************
3308 // publishPMSetting (private)
3310 // Should only be called by PMSettingObject to publish a PM Setting as a
3311 // supported feature.
3312 //******************************************************************************
3314 void IOPMrootDomain::publishPMSetting(
3315 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3317 if (noPublishPMSettings
&&
3318 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3320 // Setting found in noPublishPMSettings array
3321 *featureID
= kBadPMFeatureID
;
3326 feature
->getCStringNoCopy(), where
, featureID
);
3329 //******************************************************************************
3330 // setPMSetting (private)
3332 // Internal helper to relay PM settings changes from user space to individual
3333 // drivers. Should be called only by IOPMrootDomain::setProperties.
3334 //******************************************************************************
3336 IOReturn
IOPMrootDomain::setPMSetting(
3337 const OSSymbol
*type
,
3340 PMSettingCallEntry
*entries
= 0;
3341 OSArray
*chosen
= 0;
3342 const OSArray
*array
;
3343 PMSettingObject
*pmso
;
3344 thread_t thisThread
;
3345 int i
, j
, count
, capacity
;
3348 return kIOReturnBadArgument
;
3352 // Update settings dict so changes are visible from copyPMSetting().
3353 fPMSettingsDict
->setObject(type
, object
);
3355 // Prep all PMSetting objects with the given 'type' for callout.
3356 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3357 if (!array
|| ((capacity
= array
->getCount()) == 0))
3360 // Array to retain PMSetting objects targeted for callout.
3361 chosen
= OSArray::withCapacity(capacity
);
3363 goto unlock_exit
; // error
3365 entries
= IONew(PMSettingCallEntry
, capacity
);
3367 goto unlock_exit
; // error
3368 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3370 thisThread
= current_thread();
3372 for (i
= 0, j
= 0; i
<capacity
; i
++)
3374 pmso
= (PMSettingObject
*) array
->getObject(i
);
3377 entries
[j
].thread
= thisThread
;
3378 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3379 chosen
->setObject(pmso
);
3388 // Call each pmso in the chosen array.
3389 for (i
=0; i
<count
; i
++)
3391 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3392 pmso
->dispatchPMSetting(type
, object
);
3396 for (i
=0; i
<count
; i
++)
3398 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3399 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3400 if (pmso
->waitThread
)
3402 PMSETTING_WAKEUP(pmso
);
3408 if (chosen
) chosen
->release();
3409 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3411 return kIOReturnSuccess
;
3414 //******************************************************************************
3415 // copyPMSetting (public)
3417 // Allows kexts to safely read setting values, without being subscribed to
3419 //******************************************************************************
3421 OSObject
* IOPMrootDomain::copyPMSetting(
3422 OSSymbol
*whichSetting
)
3424 OSObject
*obj
= NULL
;
3426 if(!whichSetting
) return NULL
;
3429 obj
= fPMSettingsDict
->getObject(whichSetting
);
3438 //******************************************************************************
3439 // registerPMSettingController (public)
3441 // direct wrapper to registerPMSettingController with uint32_t power source arg
3442 //******************************************************************************
3444 IOReturn
IOPMrootDomain::registerPMSettingController(
3445 const OSSymbol
* settings
[],
3446 IOPMSettingControllerCallback func
,
3451 return registerPMSettingController(
3453 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3454 func
, target
, refcon
, handle
);
3457 //******************************************************************************
3458 // registerPMSettingController (public)
3460 // Kexts may register for notifications when a particular setting is changed.
3461 // A list of settings is available in IOPM.h.
3463 // * settings - An OSArray containing OSSymbols. Caller should populate this
3464 // array with a list of settings caller wants notifications from.
3465 // * func - A C function callback of the type IOPMSettingControllerCallback
3466 // * target - caller may provide an OSObject *, which PM will pass as an
3467 // target to calls to "func"
3468 // * refcon - caller may provide an void *, which PM will pass as an
3469 // argument to calls to "func"
3470 // * handle - This is a return argument. We will populate this pointer upon
3471 // call success. Hold onto this and pass this argument to
3472 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3474 // kIOReturnSuccess on success
3475 //******************************************************************************
3477 IOReturn
IOPMrootDomain::registerPMSettingController(
3478 const OSSymbol
* settings
[],
3479 uint32_t supportedPowerSources
,
3480 IOPMSettingControllerCallback func
,
3485 PMSettingObject
*pmso
= NULL
;
3486 OSObject
*pmsh
= NULL
;
3487 OSArray
*list
= NULL
;
3490 if (NULL
== settings
||
3494 return kIOReturnBadArgument
;
3497 pmso
= PMSettingObject::pmSettingObject(
3498 (IOPMrootDomain
*) this, func
, target
,
3499 refcon
, supportedPowerSources
, settings
, &pmsh
);
3503 return kIOReturnInternalError
;
3507 for (i
=0; settings
[i
]; i
++)
3509 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3511 // New array of callbacks for this setting
3512 list
= OSArray::withCapacity(1);
3513 settingsCallbacks
->setObject(settings
[i
], list
);
3517 // Add caller to the callback list
3518 list
->setObject(pmso
);
3522 // Return handle to the caller, the setting object is private.
3525 return kIOReturnSuccess
;
3528 //******************************************************************************
3529 // deregisterPMSettingObject (private)
3531 // Only called from PMSettingObject.
3532 //******************************************************************************
3534 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3536 thread_t thisThread
= current_thread();
3537 PMSettingCallEntry
*callEntry
;
3538 OSCollectionIterator
*iter
;
3546 pmso
->disabled
= true;
3548 // Wait for all callout threads to finish.
3551 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3553 if (callEntry
->thread
!= thisThread
)
3561 assert(0 == pmso
->waitThread
);
3562 pmso
->waitThread
= thisThread
;
3563 PMSETTING_WAIT(pmso
);
3564 pmso
->waitThread
= 0;
3568 // Search each PM settings array in the kernel.
3569 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3572 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3574 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3575 index
= array
->getNextIndexOfObject(pmso
, 0);
3577 array
->removeObject(index
);
3588 //******************************************************************************
3589 // informCPUStateChange
3591 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3592 // running on battery, with the lid closed, etc.
3594 // informCPUStateChange is a no-op on non x86 systems
3595 // only x86 has explicit support in the IntelCPUPowerManagement kext
3596 //******************************************************************************
3598 void IOPMrootDomain::informCPUStateChange(
3602 #if defined(__i386__) || defined(__x86_64__)
3604 pmioctlVariableInfo_t varInfoStruct
;
3606 const char *varNameStr
= NULL
;
3607 int32_t *varIndex
= NULL
;
3609 if (kInformAC
== type
) {
3610 varNameStr
= kIOPMRootDomainBatPowerCString
;
3611 varIndex
= &idxPMCPULimitedPower
;
3612 } else if (kInformLid
== type
) {
3613 varNameStr
= kIOPMRootDomainLidCloseCString
;
3614 varIndex
= &idxPMCPUClamshell
;
3619 // Set the new value!
3620 // pmCPUControl will assign us a new ID if one doesn't exist yet
3621 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3622 varInfoStruct
.varID
= *varIndex
;
3623 varInfoStruct
.varType
= vBool
;
3624 varInfoStruct
.varInitValue
= value
;
3625 varInfoStruct
.varCurValue
= value
;
3626 strncpy( (char *)varInfoStruct
.varName
,
3627 (const char *)varNameStr
,
3628 strlen(varNameStr
) + 1 );
3631 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3633 // pmCPU only assigns numerical id's when a new varName is specified
3635 && (*varIndex
== kCPUUnknownIndex
))
3637 // pmCPUControl has assigned us a new variable ID.
3638 // Let's re-read the structure we just SET to learn that ID.
3639 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3643 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3644 *varIndex
= varInfoStruct
.varID
;
3650 #endif /* __i386__ || __x86_64__ */
3654 // MARK: Deep Sleep Policy
3658 //******************************************************************************
3659 // evaluateSystemSleepPolicy
3660 //******************************************************************************
3662 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3666 kIOPMSleepFlagHibernate
= 0x00000001,
3667 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3670 struct IOPMSystemSleepPolicyEntry
3672 uint32_t factorMask
;
3673 uint32_t factorBits
;
3674 uint32_t sleepFlags
;
3675 uint32_t wakeEvents
;
3676 } __attribute__((packed
));
3678 struct IOPMSystemSleepPolicyTable
3682 uint16_t entryCount
;
3683 IOPMSystemSleepPolicyEntry entries
[];
3684 } __attribute__((packed
));
3686 bool IOPMrootDomain::evaluateSystemSleepPolicy(
3687 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
3689 const IOPMSystemSleepPolicyTable
* pt
;
3690 OSObject
* prop
= 0;
3691 OSData
* policyData
;
3692 uint64_t currentFactors
= 0;
3693 uint32_t standbyDelay
= 0;
3694 uint32_t powerOffDelay
= 0;
3695 uint32_t powerOffTimer
= 0;
3697 bool standbyEnabled
;
3698 bool powerOffEnabled
;
3701 // Get platform's sleep policy table
3702 if (!gSleepPolicyHandler
)
3704 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3705 if (!prop
) goto done
;
3708 // Fetch additional settings
3709 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
3710 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
3711 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
3712 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
3713 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
3714 powerOffTimer
= powerOffDelay
;
3716 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
3717 sleepPhase
, standbyEnabled
, standbyDelay
,
3718 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
3720 // pmset level overrides
3721 if ((*hibMode
& kIOHibernateModeOn
) == 0)
3723 if (!gSleepPolicyHandler
)
3725 standbyEnabled
= false;
3726 powerOffEnabled
= false;
3729 else if (!(*hibMode
& kIOHibernateModeSleep
))
3731 // Force hibernate (i.e. mode 25)
3732 // If standby is enabled, force standy.
3733 // If poweroff is enabled, force poweroff.
3735 currentFactors
|= kIOPMSleepFactorStandbyForced
;
3736 else if (powerOffEnabled
)
3737 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
3739 currentFactors
|= kIOPMSleepFactorHibernateForced
;
3742 // Current factors based on environment and assertions
3743 if (sleepTimerMaintenance
)
3744 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3745 if (!clamshellClosed
)
3746 currentFactors
|= kIOPMSleepFactorLidOpen
;
3747 if (acAdaptorConnected
)
3748 currentFactors
|= kIOPMSleepFactorACPower
;
3749 if (lowBatteryCondition
)
3750 currentFactors
|= kIOPMSleepFactorBatteryLow
;
3752 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
3753 if (!standbyEnabled
)
3754 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
3755 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3756 kIOPMDriverAssertionLevelOff
)
3757 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3758 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3759 kIOPMDriverAssertionLevelOff
)
3760 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3761 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3762 kIOPMDriverAssertionLevelOff
)
3763 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3764 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
3765 kIOPMDriverAssertionLevelOff
)
3766 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
3767 if (_scheduledAlarms
!= 0)
3768 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
3769 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
3770 kIOPMDriverAssertionLevelOff
)
3771 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
3772 if (!powerOffEnabled
)
3773 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
3775 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
3777 DLOG("sleep factors 0x%llx\n", currentFactors
);
3779 if (gSleepPolicyHandler
)
3781 uint32_t savedHibernateMode
;
3784 if (!gSleepPolicyVars
)
3786 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
3787 if (!gSleepPolicyVars
)
3789 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
3791 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
3792 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
3793 gSleepPolicyVars
->currentCapability
= _currentCapability
;
3794 gSleepPolicyVars
->highestCapability
= _highestCapability
;
3795 gSleepPolicyVars
->sleepFactors
= currentFactors
;
3796 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
3797 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
3798 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
3799 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
3800 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
3801 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
3803 if (kIOPMSleepPhase0
== sleepPhase
)
3805 // preserve hibernateMode
3806 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
3807 gSleepPolicyVars
->hibernateMode
= *hibMode
;
3809 else if (kIOPMSleepPhase1
== sleepPhase
)
3811 // use original hibernateMode for phase2
3812 gSleepPolicyVars
->hibernateMode
= *hibMode
;
3815 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
3817 if (kIOPMSleepPhase0
== sleepPhase
)
3819 // restore hibernateMode
3820 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
3823 if ((result
!= kIOReturnSuccess
) ||
3824 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
3825 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
3826 (kIOPMSystemSleepParametersVersion
!= params
->version
))
3828 MSG("sleep policy handler error\n");
3832 if ((params
->sleepType
>= kIOPMSleepTypeSafeSleep
) &&
3833 ((*hibMode
& kIOHibernateModeOn
) == 0))
3835 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
3838 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
3839 params
->version
, params
->sleepType
, params
->sleepFlags
,
3840 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
3845 // Policy table is meaningless without standby enabled
3846 if (!standbyEnabled
)
3849 // Validate the sleep policy table
3850 policyData
= OSDynamicCast(OSData
, prop
);
3851 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
3854 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
3855 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
3856 (pt
->version
!= 1) || (0 == pt
->entryCount
))
3859 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
3860 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
3863 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
3865 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
3866 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
3868 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
3869 entry
->factorMask
, entry
->factorBits
,
3870 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
3874 DLOG("^ found match\n");
3877 params
->version
= kIOPMSystemSleepParametersVersion
;
3878 params
->reserved1
= 1;
3879 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
3880 params
->sleepType
= kIOPMSleepTypeStandby
;
3882 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
3884 params
->ecWakeEvents
= entry
->wakeEvents
;
3885 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
3887 if (kIOPMSleepPhase2
== sleepPhase
)
3889 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
3891 if (!_standbyTimerResetSeconds
||
3892 (now_secs
<= _standbyTimerResetSeconds
))
3894 // Reset standby timer adjustment
3895 _standbyTimerResetSeconds
= now_secs
;
3896 DLOG("standby delay %u, reset %u\n",
3897 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
3899 else if (standbyDelay
)
3901 // Shorten the standby delay timer
3902 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
3903 if (standbyDelay
> elapsed
)
3904 standbyDelay
-= elapsed
;
3906 standbyDelay
= 1; // must be > 0
3908 DLOG("standby delay %u, elapsed %u\n",
3909 standbyDelay
, (uint32_t) elapsed
);
3912 params
->ecWakeTimer
= standbyDelay
;
3914 else if (kIOPMSleepPhase2
== sleepPhase
)
3916 // A sleep that does not enable the sleep timer will reset
3917 // the standby delay adjustment.
3918 _standbyTimerResetSeconds
= 0;
3930 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
3932 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
3934 // Evaluate early (priority interest phase), before drivers sleep.
3936 DLOG("%s\n", __FUNCTION__
);
3937 removeProperty(kIOPMSystemSleepParametersKey
);
3939 // Full wake resets the standby timer delay adjustment
3940 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
3941 _standbyTimerResetSeconds
= 0;
3943 hibernateDisabled
= false;
3945 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
3947 // Save for late evaluation if sleep is aborted
3948 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
3950 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
3953 if (!hibernateNoDefeat
&&
3954 (gEarlySystemSleepParams
.sleepType
== kIOPMSleepTypeNormalSleep
))
3956 // Disable hibernate setup for normal sleep
3957 hibernateDisabled
= true;
3961 // Publish IOPMSystemSleepType
3962 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
3963 if (sleepType
== kIOPMSleepTypeInvalid
)
3966 sleepType
= kIOPMSleepTypeNormalSleep
;
3967 if (hibernateMode
& kIOHibernateModeOn
)
3968 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
3969 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
3971 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
3972 (gEarlySystemSleepParams
.ecPoweroffTimer
))
3974 // report the lowest possible sleep state
3975 sleepType
= kIOPMSleepTypePowerOff
;
3978 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
3981 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
3983 IOPMSystemSleepParameters params
;
3984 OSData
* paramsData
;
3986 // Evaluate sleep policy after sleeping drivers but before platform sleep.
3988 DLOG("%s\n", __FUNCTION__
);
3990 bzero(¶ms
, sizeof(params
));
3991 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
3993 if ((hibernateDisabled
|| hibernateAborted
) &&
3994 (params
.sleepType
!= kIOPMSleepTypeNormalSleep
))
3996 // Final evaluation picked a state requiring hibernation,
3997 // but hibernate setup was skipped. Retry using the early
3998 // sleep parameters.
4000 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4001 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4002 params
.ecWakeTimer
= 1;
4003 hibernateNoDefeat
= true;
4004 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
4005 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
);
4009 hibernateNoDefeat
= false;
4012 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4015 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4016 paramsData
->release();
4019 if (params
.sleepType
>= kIOPMSleepTypeHibernate
)
4021 // Disable safe sleep to force the hibernate path
4022 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4027 bool IOPMrootDomain::getHibernateSettings(
4028 uint32_t * hibernateModePtr
,
4029 uint32_t * hibernateFreeRatio
,
4030 uint32_t * hibernateFreeTime
)
4032 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4033 // has updated the hibernateDisabled flag.
4035 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4036 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4037 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4038 if (hibernateDisabled
)
4039 *hibernateModePtr
= 0;
4040 else if (gSleepPolicyHandler
)
4041 *hibernateModePtr
= hibernateMode
;
4042 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4046 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4048 OSObject
* optionsProp
;
4049 OSDictionary
* optionsDict
;
4054 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4055 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4059 obj
= optionsDict
->getObject(key
);
4060 if (obj
) obj
->retain();
4064 obj
= copyProperty(key
);
4066 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)))
4068 *option
= num
->unsigned32BitValue();
4075 optionsProp
->release();
4079 #endif /* HIBERNATION */
4081 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
)
4084 IOPMSystemSleepParameters params
;
4085 uint32_t hibMode
= 0;
4088 if (gIOPMWorkLoop
->inGate() == false)
4090 IOReturn ret
= gIOPMWorkLoop
->runAction(
4091 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4092 &IOPMrootDomain::getSystemSleepType
),
4094 (void *) sleepType
);
4098 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4099 bzero(¶ms
, sizeof(params
));
4101 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4104 *sleepType
= params
.sleepType
;
4105 return kIOReturnSuccess
;
4109 return kIOReturnUnsupported
;
4113 // MARK: Shutdown and Restart
4115 //******************************************************************************
4116 // handlePlatformHaltRestart
4118 //******************************************************************************
4120 struct HaltRestartApplierContext
{
4121 IOPMrootDomain
* RootDomain
;
4122 unsigned long PowerState
;
4123 IOPMPowerFlags PowerFlags
;
4129 platformHaltRestartApplier( OSObject
* object
, void * context
)
4131 IOPowerStateChangeNotification notify
;
4132 HaltRestartApplierContext
* ctx
;
4133 AbsoluteTime startTime
;
4136 ctx
= (HaltRestartApplierContext
*) context
;
4138 memset(¬ify
, 0, sizeof(notify
));
4139 notify
.powerRef
= (void *)ctx
->Counter
;
4140 notify
.returnValue
= 0;
4141 notify
.stateNumber
= ctx
->PowerState
;
4142 notify
.stateFlags
= ctx
->PowerFlags
;
4144 clock_get_uptime(&startTime
);
4145 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4146 deltaTime
= computeDeltaTimeMS(&startTime
);
4148 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4149 (gIOKitDebug
& kIOLogPMRootDomain
))
4151 _IOServiceInterestNotifier
* notifier
;
4152 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4154 // IOService children of IOPMrootDomain are not instrumented.
4155 // Only IORootParent currently falls under that group.
4159 LOG("%s handler %p took %u ms\n",
4160 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
4161 (ctx
->MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
4162 notifier
->handler
, (uint32_t) deltaTime
);
4169 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4171 HaltRestartApplierContext ctx
;
4172 AbsoluteTime startTime
;
4175 memset(&ctx
, 0, sizeof(ctx
));
4176 ctx
.RootDomain
= this;
4178 clock_get_uptime(&startTime
);
4182 case kPEUPSDelayHaltCPU
:
4183 ctx
.PowerState
= OFF_STATE
;
4184 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4188 ctx
.PowerState
= RESTART_STATE
;
4189 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4193 ctx
.PowerState
= ON_STATE
;
4194 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4195 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4197 IOHibernateSystemRestart();
4205 // Notify legacy clients
4206 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4208 // For normal shutdown, turn off File Server Mode.
4209 if (kPEHaltCPU
== pe_type
)
4211 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4212 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4215 setPMSetting(setting
, num
);
4221 if (kPEPagingOff
!= pe_type
)
4223 // Notify in power tree order
4224 notifySystemShutdown(this, ctx
.MessageType
);
4227 deltaTime
= computeDeltaTimeMS(&startTime
);
4228 LOG("%s all drivers took %u ms\n",
4229 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
4230 (ctx
.MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
4231 (uint32_t) deltaTime
);
4234 //******************************************************************************
4237 //******************************************************************************
4239 IOReturn
IOPMrootDomain::shutdownSystem( void )
4241 return kIOReturnUnsupported
;
4244 //******************************************************************************
4247 //******************************************************************************
4249 IOReturn
IOPMrootDomain::restartSystem( void )
4251 return kIOReturnUnsupported
;
4255 // MARK: System Capability
4257 //******************************************************************************
4258 // tagPowerPlaneService
4260 // Running on PM work loop thread.
4261 //******************************************************************************
4263 void IOPMrootDomain::tagPowerPlaneService(
4264 IOService
* service
,
4265 IOPMActions
* actions
)
4268 bool isDisplayWrangler
;
4270 memset(actions
, 0, sizeof(*actions
));
4271 actions
->target
= this;
4273 if (service
== this)
4275 actions
->actionPowerChangeStart
=
4276 OSMemberFunctionCast(
4277 IOPMActionPowerChangeStart
, this,
4278 &IOPMrootDomain::handleOurPowerChangeStart
);
4280 actions
->actionPowerChangeDone
=
4281 OSMemberFunctionCast(
4282 IOPMActionPowerChangeDone
, this,
4283 &IOPMrootDomain::handleOurPowerChangeDone
);
4285 actions
->actionPowerChangeOverride
=
4286 OSMemberFunctionCast(
4287 IOPMActionPowerChangeOverride
, this,
4288 &IOPMrootDomain::overrideOurPowerChange
);
4293 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4294 if (isDisplayWrangler
)
4299 isDisplayWrangler
= false;
4302 #if defined(__i386__) || defined(__x86_64__)
4303 if (isDisplayWrangler
)
4304 flags
|= kPMActionsFlagIsDisplayWrangler
;
4305 if (service
->getProperty("IOPMStrictTreeOrder"))
4306 flags
|= kPMActionsFlagIsGraphicsDevice
;
4307 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4308 flags
|= kPMActionsFlagIsAudioDevice
;
4311 // Find the power connection object that is a child of the PCI host
4312 // bridge, and has a graphics/audio device attached below. Mark the
4313 // power branch for delayed child notifications.
4317 IORegistryEntry
* child
= service
;
4318 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4320 while (child
!= this)
4322 if ((parent
== pciHostBridgeDriver
) ||
4325 if (OSDynamicCast(IOPowerConnection
, child
))
4327 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4328 conn
->delayChildNotification
= true;
4333 parent
= child
->getParentEntry(gIOPowerPlane
);
4339 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4340 actions
->parameter
|= flags
;
4341 actions
->actionPowerChangeOverride
=
4342 OSMemberFunctionCast(
4343 IOPMActionPowerChangeOverride
, this,
4344 &IOPMrootDomain::overridePowerChangeForUIService
);
4346 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4348 actions
->actionActivityTickle
=
4349 OSMemberFunctionCast(
4350 IOPMActionActivityTickle
, this,
4351 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4356 // Locate the first PCI host bridge for PMTrace.
4357 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4359 IOService
* provider
= service
->getProvider();
4360 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4361 provider
->inPlane(gIODTPlane
))
4363 pciHostBridgeDevice
= provider
;
4364 pciHostBridgeDriver
= service
;
4365 DLOG("PMTrace found PCI host bridge %s->%s\n",
4366 provider
->getName(), service
->getName());
4370 // Tag top-level PCI devices. The order of PMinit() call does not
4371 // change across boots and is used as the PCI bit number.
4372 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4374 // Would prefer to check built-in property, but tagPowerPlaneService()
4375 // is called before pciDevice->registerService().
4376 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4377 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4379 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4382 // Save the assigned bit for fast lookup.
4383 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4385 actions
->actionPowerChangeStart
=
4386 OSMemberFunctionCast(
4387 IOPMActionPowerChangeStart
, this,
4388 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4390 actions
->actionPowerChangeDone
=
4391 OSMemberFunctionCast(
4392 IOPMActionPowerChangeDone
, this,
4393 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4399 //******************************************************************************
4400 // PM actions for root domain
4401 //******************************************************************************
4403 void IOPMrootDomain::overrideOurPowerChange(
4404 IOService
* service
,
4405 IOPMActions
* actions
,
4406 unsigned long * inOutPowerState
,
4407 uint32_t * inOutChangeFlags
)
4409 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4410 uint32_t changeFlags
= *inOutChangeFlags
;
4411 uint32_t currentPowerState
= (uint32_t) getPowerState();
4413 if ((currentPowerState
== powerState
) ||
4414 (changeFlags
& kIOPMParentInitiated
))
4416 // FIXME: cancel any parent change (unexpected)
4417 // Root parent is permanently pegged at max power,
4418 // kIOPMParentInitiated is unexpected.
4422 if (powerState
< currentPowerState
)
4424 if ((changeFlags
& kIOPMSkipAskPowerDown
) == 0)
4426 /* Convenient place to run any code at idle sleep time
4427 * IOPMrootDomain initiates an idle sleep here
4429 * Set last sleep cause accordingly.
4431 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
4433 lastSleepReason
= kIOPMSleepReasonIdle
;
4434 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
4436 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4438 // Root domain is dropping power state ON->SLEEP.
4439 // If system is in full wake, first drop to dark wake.
4441 darkWakeToSleepASAP
= true;
4443 // Drop graphics capability.
4444 // No transition if system is already in dark wake.
4446 _desiredCapability
&= ~(
4447 kIOPMSystemCapabilityGraphics
|
4448 kIOPMSystemCapabilityAudio
);
4450 *inOutPowerState
= ON_STATE
;
4451 *inOutChangeFlags
|= kIOPMSynchronize
;
4453 // Revert device desire from SLEEP->ON.
4454 changePowerStateToPriv(ON_STATE
);
4459 void IOPMrootDomain::handleOurPowerChangeStart(
4460 IOService
* service
,
4461 IOPMActions
* actions
,
4462 uint32_t powerState
,
4463 uint32_t * inOutChangeFlags
)
4465 uint32_t changeFlags
= *inOutChangeFlags
;
4466 uint32_t currentPowerState
= (uint32_t) getPowerState();
4468 _systemTransitionType
= kSystemTransitionNone
;
4469 _systemMessageClientMask
= 0;
4470 capabilityLoss
= false;
4472 // 1. Explicit capability change.
4474 if (changeFlags
& kIOPMSynchronize
)
4476 if (powerState
== ON_STATE
)
4478 if (changeFlags
& kIOPMSyncNoChildNotify
)
4479 _systemTransitionType
= kSystemTransitionNewCapClient
;
4481 _systemTransitionType
= kSystemTransitionCapability
;
4485 // 2. Going to sleep (cancellation still possible).
4487 else if (powerState
< currentPowerState
)
4488 _systemTransitionType
= kSystemTransitionSleep
;
4490 // 3. Woke from (idle or demand) sleep.
4492 else if (!systemBooting
&&
4493 (changeFlags
& kIOPMSelfInitiated
) &&
4494 (powerState
> currentPowerState
))
4496 _systemTransitionType
= kSystemTransitionWake
;
4497 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4498 kIOPMSystemCapabilityNetwork
;
4500 // Check for early HID events (e.g. LID open)
4501 if (wranglerTickled
)
4503 _desiredCapability
|= (
4504 kIOPMSystemCapabilityGraphics
|
4505 kIOPMSystemCapabilityAudio
);
4509 // Update pending wake capability at the beginning of every
4510 // state transition (including synchronize). This will become
4511 // the current capability at the end of the transition.
4513 if (kSystemTransitionSleep
== _systemTransitionType
)
4515 _pendingCapability
= 0;
4516 capabilityLoss
= true;
4518 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4520 _pendingCapability
= _desiredCapability
|
4521 kIOPMSystemCapabilityCPU
|
4522 kIOPMSystemCapabilityNetwork
;
4524 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4525 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4527 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4528 (_pendingCapability
== _currentCapability
))
4530 // Cancel the PM state change.
4531 _systemTransitionType
= kSystemTransitionNone
;
4532 *inOutChangeFlags
|= kIOPMNotDone
;
4534 if (__builtin_popcount(_pendingCapability
) <
4535 __builtin_popcount(_currentCapability
))
4536 capabilityLoss
= true;
4537 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4538 rejectWranglerTickle
= true;
4541 // 1. Capability change.
4543 if (kSystemTransitionCapability
== _systemTransitionType
)
4545 // Dark to Full transition.
4546 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4548 tracePoint( kIOPMTracePointDarkWakeExit
);
4549 wranglerSleepIgnored
= false;
4550 sleepTimerMaintenance
= false;
4551 hibernateNoDefeat
= false;
4552 _systemMessageClientMask
= kSystemMessageClientUser
;
4553 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4554 _systemMessageClientMask
|= kSystemMessageClientKernel
;
4556 IOService::setAdvisoryTickleEnable( true );
4557 tellClients(kIOMessageSystemWillPowerOn
);
4560 // Full to Dark transition.
4561 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4563 tracePoint( kIOPMTracePointDarkWakeEntry
);
4564 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4565 _systemMessageClientMask
= kSystemMessageClientUser
;
4566 IOService::setAdvisoryTickleEnable( false );
4572 else if (kSystemTransitionSleep
== _systemTransitionType
)
4574 // Beginning of a system sleep transition.
4575 // Cancellation is still possible.
4576 tracePoint( kIOPMTracePointSleepStarted
, lastSleepReason
);
4578 _systemMessageClientMask
= kSystemMessageClientAll
;
4579 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4580 _systemMessageClientMask
&= ~kSystemMessageClientApp
;
4581 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4582 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4584 // Optimization to ignore wrangler power down thus skipping
4585 // the disk spindown and arming the idle timer for demand sleep.
4587 if (changeFlags
& kIOPMIgnoreChildren
)
4589 wranglerSleepIgnored
= true;
4592 logWranglerTickle
= false;
4597 else if (kSystemTransitionWake
== _systemTransitionType
)
4599 wranglerSleepIgnored
= false;
4601 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4603 _systemMessageClientMask
= kSystemMessageClientAll
;
4604 IOService::setAdvisoryTickleEnable( true );
4608 _systemMessageClientMask
= kSystemMessageClientConfigd
;
4611 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4612 tellClients(kIOMessageSystemWillPowerOn
);
4615 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4616 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4618 _systemStateGeneration
++;
4619 systemDarkWake
= false;
4621 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4623 currentPowerState
, powerState
, *inOutChangeFlags
,
4624 _systemTransitionType
, _systemStateGeneration
,
4625 _systemMessageClientMask
,
4626 _desiredCapability
, _currentCapability
, _pendingCapability
);
4630 void IOPMrootDomain::handleOurPowerChangeDone(
4631 IOService
* service
,
4632 IOPMActions
* actions
,
4633 uint32_t powerState
,
4634 uint32_t changeFlags
)
4636 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4638 _systemTransitionType
= kSystemTransitionNone
;
4642 if (_systemTransitionType
!= kSystemTransitionNone
)
4644 uint32_t currentPowerState
= (uint32_t) getPowerState();
4646 if (changeFlags
& kIOPMNotDone
)
4648 // Power down was cancelled or vetoed.
4649 _pendingCapability
= _currentCapability
;
4650 lastSleepReason
= 0;
4652 if (((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4653 (_currentCapability
& kIOPMSystemCapabilityCPU
))
4655 pmPowerStateQueue
->submitPowerEvent(
4656 kPowerEventPolicyStimulus
,
4657 (void *) kStimulusDarkWakeReentry
,
4658 _systemStateGeneration
);
4661 // Revert device desire to max.
4662 changePowerStateToPriv(ON_STATE
);
4666 // Send message on dark wake to full wake promotion.
4667 // tellChangeUp() handles the normal SLEEP->ON case.
4669 if (kSystemTransitionCapability
== _systemTransitionType
)
4671 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4673 tellClients(kIOMessageSystemHasPoweredOn
);
4674 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4675 // Re-evaluate clamshell state ourselves when graphics
4676 // will not get kIOMessageSystemHasPoweredOn.
4678 if (clamshellClosed
&&
4679 ((_systemMessageClientMask
& kSystemMessageClientKernel
) == 0))
4681 receivePowerNotification( kLocalEvalClamshellCommand
);
4685 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4686 wranglerTickled
= false;
4689 // Reset state after exiting from dark wake.
4691 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
4692 CAP_LOSS(kIOPMSystemCapabilityCPU
))
4694 darkWakeMaintenance
= false;
4695 darkWakeToSleepASAP
= false;
4696 pciCantSleepValid
= false;
4697 rejectWranglerTickle
= false;
4698 darkWakeSleepService
= false;
4701 // Entered dark mode.
4703 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4704 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
4706 if (((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOInDark
) == 0) &&
4707 (kSystemTransitionWake
== _systemTransitionType
) &&
4708 (_lastDebugWakeSeconds
== 0))
4710 OSObject
* prop
= copyProperty(kIOPMRootDomainWakeTypeKey
);
4713 OSString
* wakeType
= OSDynamicCast(OSString
, prop
);
4715 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeNetwork
))
4717 // Woke from network and entered dark wake.
4718 if (darkWakeToSleepASAP
)
4720 DLOG("cleared darkWakeToSleepASAP\n");
4721 darkWakeToSleepASAP
= false;
4728 // Queue an evaluation of whether to remain in dark wake,
4729 // and for how long. This serves the purpose of draining
4730 // any assertions from the queue.
4732 pmPowerStateQueue
->submitPowerEvent(
4733 kPowerEventPolicyStimulus
,
4734 (void *) kStimulusDarkWakeEntry
,
4735 _systemStateGeneration
);
4739 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4740 "dcp %x:%x:%x, dbgtimer %u\n",
4741 currentPowerState
, powerState
, changeFlags
,
4742 _systemTransitionType
, _systemStateGeneration
,
4743 _systemMessageClientMask
,
4744 _desiredCapability
, _currentCapability
, _pendingCapability
,
4745 _lastDebugWakeSeconds
);
4747 // Update current system capability.
4749 if (_currentCapability
!= _pendingCapability
)
4750 _currentCapability
= _pendingCapability
;
4752 // Update highest system capability.
4754 _highestCapability
|= _currentCapability
;
4756 if (darkWakePostTickle
&&
4757 (kSystemTransitionWake
== _systemTransitionType
) &&
4758 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4759 kDarkWakeFlagHIDTickleLate
)
4761 darkWakePostTickle
= false;
4765 // Reset tracepoint at completion of capability change,
4766 // completion of wake transition, and aborted sleep transition.
4768 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
4769 (_systemTransitionType
== kSystemTransitionWake
) ||
4770 ((_systemTransitionType
== kSystemTransitionSleep
) &&
4771 (changeFlags
& kIOPMNotDone
)))
4773 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
4774 tracePoint( kIOPMTracePointSystemUp
, 0 );
4776 // kIOPMDWOverTemp notification handling was postponed
4777 if (darkWakeThermalAlarm
)
4779 if (!wranglerTickled
&& !darkWakeThermalEmergency
&&
4780 CAP_CURRENT(kIOPMSystemCapabilityCPU
) &&
4781 !CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4783 darkWakeThermalEmergency
= true;
4784 privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
4785 MSG("DarkWake thermal limits breached. Going to sleep!\n");
4787 darkWakeThermalAlarm
= false;
4791 _systemTransitionType
= kSystemTransitionNone
;
4792 _systemMessageClientMask
= 0;
4794 logGraphicsClamp
= false;
4798 //******************************************************************************
4799 // PM actions for graphics and audio.
4800 //******************************************************************************
4802 void IOPMrootDomain::overridePowerChangeForUIService(
4803 IOService
* service
,
4804 IOPMActions
* actions
,
4805 unsigned long * inOutPowerState
,
4806 uint32_t * inOutChangeFlags
)
4808 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4809 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
4811 if (kSystemTransitionNone
== _systemTransitionType
)
4813 // Not in midst of a system transition.
4814 // Do not modify power limit enable state.
4816 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4818 // Activate power limiter.
4820 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4821 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4822 (changeFlags
& kIOPMSynchronize
))
4824 actions
->parameter
|= kPMActionsFlagLimitPower
;
4826 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4827 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
4828 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
4829 (changeFlags
& kIOPMSynchronize
))
4831 actions
->parameter
|= kPMActionsFlagLimitPower
;
4833 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
4834 (_systemTransitionType
== kSystemTransitionSleep
))
4836 // For graphics devices, arm the limiter when entering
4837 // system sleep. Not when dropping to dark wake.
4838 actions
->parameter
|= kPMActionsFlagLimitPower
;
4841 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4843 DLOG("+ plimit %s %p\n",
4844 service
->getName(), service
);
4849 // Remove power limit.
4851 if ((actions
->parameter
& (
4852 kPMActionsFlagIsDisplayWrangler
|
4853 kPMActionsFlagIsGraphicsDevice
)) &&
4854 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
4856 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4858 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4859 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
4861 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4864 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4866 DLOG("- plimit %s %p\n",
4867 service
->getName(), service
);
4871 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4873 uint32_t maxPowerState
= (uint32_t)(-1);
4875 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
4877 // Enforce limit for system power/cap transitions.
4880 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4881 (service
->getPowerState() > 0))
4883 // Forces a 3->1 transition sequence
4884 if (changeFlags
& kIOPMDomainWillChange
)
4889 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
4896 // Deny all self-initiated changes when power is limited.
4897 // Wrangler tickle should never defeat the limiter.
4899 maxPowerState
= service
->getPowerState();
4902 if (powerState
> maxPowerState
)
4904 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4905 service
->getName(), service
, powerState
, maxPowerState
,
4907 *inOutPowerState
= maxPowerState
;
4909 if (darkWakePostTickle
&&
4910 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4911 (changeFlags
& kIOPMDomainWillChange
) &&
4912 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4913 kDarkWakeFlagHIDTickleEarly
))
4915 darkWakePostTickle
= false;
4920 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
4922 if (logGraphicsClamp
)
4927 clock_get_uptime(&now
);
4928 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
4929 absolutetime_to_nanoseconds(now
, &nsec
);
4930 MSG("Graphics suppressed %u ms\n",
4931 ((int)((nsec
) / 1000000ULL)));
4933 graphicsSuppressed
= true;
4938 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4939 IOService
* service
,
4940 IOPMActions
* actions
)
4942 // Warning: Not running in PM work loop context - don't modify state !!!
4943 // Trap tickle directed to IODisplayWrangler while running with graphics
4944 // capability suppressed.
4946 assert(service
== wrangler
);
4948 if (service
== wrangler
)
4950 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
4951 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
4953 userActivityCount
++;
4954 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
4958 if (!wranglerTickled
&&
4959 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4961 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
4962 DLOG("display wrangler tickled\n");
4963 if (kIOLogPMRootDomain
& gIOKitDebug
)
4964 OSReportWithBacktrace("Dark wake display tickle");
4965 if (pmPowerStateQueue
)
4967 pmPowerStateQueue
->submitPowerEvent(
4968 kPowerEventPolicyStimulus
,
4969 (void *) kStimulusDarkWakeActivityTickle
);
4974 //******************************************************************************
4975 // Approve usage of delayed child notification by PM.
4976 //******************************************************************************
4978 bool IOPMrootDomain::shouldDelayChildNotification(
4979 IOService
* service
)
4981 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
4983 (kSystemTransitionWake
== _systemTransitionType
))
4985 DLOG("%s: delay child notify\n", service
->getName());
4991 //******************************************************************************
4992 // PM actions for PCI device.
4993 //******************************************************************************
4995 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
4996 IOService
* service
,
4997 IOPMActions
* actions
,
4998 uint32_t powerState
,
4999 uint32_t * inOutChangeFlags
)
5001 pmTracer
->tracePCIPowerChange(
5002 PMTraceWorker::kPowerChangeStart
,
5003 service
, *inOutChangeFlags
,
5004 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5007 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5008 IOService
* service
,
5009 IOPMActions
* actions
,
5010 uint32_t powerState
,
5011 uint32_t changeFlags
)
5013 pmTracer
->tracePCIPowerChange(
5014 PMTraceWorker::kPowerChangeCompleted
,
5015 service
, changeFlags
,
5016 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5019 //******************************************************************************
5022 // Override IOService::registerInterest() to intercept special clients.
5023 //******************************************************************************
5025 IONotifier
* IOPMrootDomain::registerInterest(
5026 const OSSymbol
* typeOfInterest
,
5027 IOServiceInterestHandler handler
,
5028 void * target
, void * ref
)
5030 IONotifier
* notifier
;
5031 bool isSystemCapabilityClient
;
5032 bool isKernelCapabilityClient
;
5034 isSystemCapabilityClient
=
5036 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5038 isKernelCapabilityClient
=
5040 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5042 if (isSystemCapabilityClient
)
5043 typeOfInterest
= gIOAppPowerStateInterest
;
5045 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
5046 if (notifier
&& pmPowerStateQueue
)
5048 if (isSystemCapabilityClient
)
5051 if (pmPowerStateQueue
->submitPowerEvent(
5052 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5053 notifier
->release();
5056 if (isKernelCapabilityClient
)
5059 if (pmPowerStateQueue
->submitPowerEvent(
5060 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5061 notifier
->release();
5068 //******************************************************************************
5069 // systemMessageFilter
5071 //******************************************************************************
5073 bool IOPMrootDomain::systemMessageFilter(
5074 void * object
, void * arg1
, void * arg2
, void * arg3
)
5076 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5077 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5078 bool isCapClient
= false;
5082 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5083 (!isCapMsg
|| !_joinedCapabilityClients
||
5084 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5087 // Capability change message for app and kernel clients.
5091 if ((context
->notifyType
== kNotifyPriority
) ||
5092 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5095 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5096 (object
== (void *) systemCapabilityNotifier
))
5102 IOPMSystemCapabilityChangeParameters
* capArgs
=
5103 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5105 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5107 capArgs
->fromCapabilities
= 0;
5108 capArgs
->toCapabilities
= _currentCapability
;
5109 capArgs
->changeFlags
= 0;
5113 capArgs
->fromCapabilities
= _currentCapability
;
5114 capArgs
->toCapabilities
= _pendingCapability
;
5116 if (context
->isPreChange
)
5117 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5119 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5122 // Capability change messages only go to the PM configd plugin.
5123 // Wait for response post-change if capabilitiy is increasing.
5124 // Wait for response pre-change if capability is decreasing.
5126 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5127 ( (capabilityLoss
&& context
->isPreChange
) ||
5128 (!capabilityLoss
&& !context
->isPreChange
) ) )
5130 // app has not replied yet, wait for it
5131 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5138 // Capability client will always see kIOMessageCanSystemSleep,
5139 // even for demand sleep.
5141 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5142 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5144 if (object
== (OSObject
*) systemCapabilityNotifier
)
5150 // Not idle sleep, don't ask apps.
5151 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5157 // Reject capability change messages for legacy clients.
5158 // Reject legacy system sleep messages for capability client.
5160 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5165 // Filter system sleep messages.
5167 if ((context
->notifyType
== kNotifyApps
) &&
5168 (_systemMessageClientMask
& kSystemMessageClientApp
))
5172 else if ((context
->notifyType
== kNotifyPriority
) &&
5173 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5180 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5182 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5183 if (_joinedCapabilityClients
->getCount() == 0)
5185 DLOG("destroyed capability client set %p\n",
5186 _joinedCapabilityClients
);
5187 _joinedCapabilityClients
->release();
5188 _joinedCapabilityClients
= 0;
5195 //******************************************************************************
5196 // setMaintenanceWakeCalendar
5198 //******************************************************************************
5200 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5201 const IOPMCalendarStruct
* calendar
)
5207 return kIOReturnBadArgument
;
5209 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5211 return kIOReturnNoMemory
;
5213 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5214 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5215 if (kIOReturnSuccess
== ret
)
5216 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5218 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5220 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5221 if (kIOReturnSuccess
== ret
)
5222 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5224 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5231 // MARK: Display Wrangler
5233 //******************************************************************************
5234 // displayWranglerNotification
5236 // Handle the notification when the IODisplayWrangler changes power state.
5237 //******************************************************************************
5239 IOReturn
IOPMrootDomain::displayWranglerNotification(
5240 void * target
, void * refCon
,
5241 UInt32 messageType
, IOService
* service
,
5242 void * messageArgument
, vm_size_t argSize
)
5245 int displayPowerState
;
5246 IOPowerStateChangeNotification
* params
=
5247 (IOPowerStateChangeNotification
*) messageArgument
;
5249 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5250 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5251 return kIOReturnUnsupported
;
5255 return kIOReturnUnsupported
;
5257 displayPowerState
= params
->stateNumber
;
5258 DLOG("DisplayWrangler message 0x%x, power state %d\n",
5259 (uint32_t) messageType
, displayPowerState
);
5261 switch (messageType
) {
5262 case kIOMessageDeviceWillPowerOff
:
5264 // Display wrangler has dropped power due to display idle
5265 // or force system sleep.
5270 // 1 Not visible to user
5271 // 0 Not visible to user
5273 if (displayPowerState
> 2)
5276 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5279 case kIOMessageDeviceHasPoweredOn
:
5281 // Display wrangler has powered on due to user activity
5282 // or wake from sleep.
5284 if ( 4 != displayPowerState
)
5287 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5291 return kIOReturnUnsupported
;
5294 //******************************************************************************
5295 // displayWranglerMatchPublished
5297 // Receives a notification when the IODisplayWrangler is published.
5298 // When it's published we install a power state change handler.
5299 //******************************************************************************
5301 bool IOPMrootDomain::displayWranglerMatchPublished(
5304 IOService
* newService
,
5305 IONotifier
* notifier __unused
)
5308 // found the display wrangler, now install a handler
5309 if( !newService
->registerInterest( gIOGeneralInterest
,
5310 &displayWranglerNotification
, target
, 0) )
5318 //******************************************************************************
5321 //******************************************************************************
5323 void IOPMrootDomain::reportUserInput( void )
5330 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
5333 wrangler
= (IOService
*) iter
->getNextObject();
5339 wrangler
->activityTickle(0,0);
5343 //******************************************************************************
5344 // blockDisplayWranglerTickle
5345 //******************************************************************************
5347 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
5352 // Not too late to prevent the display from lighting up
5353 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
5354 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5355 !checkSystemCanSustainFullWake())
5357 wranglerTickleLatched
= true;
5361 wranglerTickleLatched
= false;
5364 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
5366 wranglerTickleLatched
= false;
5368 pmPowerStateQueue
->submitPowerEvent(
5369 kPowerEventPolicyStimulus
,
5370 (void *) kStimulusDarkWakeActivityTickle
);
5373 return wranglerTickleLatched
;
5382 //******************************************************************************
5385 // Notification on battery class IOPowerSource appearance
5386 //******************************************************************************
5388 bool IOPMrootDomain::batteryPublished(
5391 IOService
* resourceService
,
5392 IONotifier
* notifier __unused
)
5394 // rdar://2936060&4435589
5395 // All laptops have dimmable LCD displays
5396 // All laptops have batteries
5397 // So if this machine has a battery, publish the fact that the backlight
5398 // supports dimming.
5399 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
5405 // MARK: System PM Policy
5407 //******************************************************************************
5408 // checkSystemCanSleep
5410 //******************************************************************************
5412 bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options
)
5416 // Conditions that prevent idle and demand system sleep.
5419 if (userDisabledAllSleep
)
5421 err
= 1; // 1. user-space sleep kill switch
5425 if (systemBooting
|| systemShutdown
)
5427 err
= 2; // 2. restart or shutdown in progress
5434 // Conditions above pegs the system at full wake.
5435 // Conditions below prevent system sleep but does not prevent
5436 // dark wake, and must be called from gated context.
5439 err
= 3; // 3. config does not support sleep
5443 if (lowBatteryCondition
)
5445 break; // always sleep on low battery
5448 if(darkWakeThermalEmergency
)
5450 break; // always sleep on dark wake thermal emergencies
5453 if (preventSystemSleepList
->getCount() != 0)
5455 err
= 4; // 4. child prevent system sleep clamp
5459 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
5460 kIOPMDriverAssertionLevelOn
)
5462 err
= 5; // 5. CPU assertion
5466 if (pciCantSleepValid
)
5468 if (pciCantSleepFlag
)
5469 err
= 6; // 6. PCI card does not support PM (cached)
5472 else if (sleepSupportedPEFunction
&&
5473 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5476 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
5477 ret
= getPlatform()->callPlatformFunction(
5478 sleepSupportedPEFunction
, false,
5479 NULL
, NULL
, NULL
, NULL
);
5480 pciCantSleepValid
= true;
5481 pciCantSleepFlag
= false;
5482 if ((platformSleepSupport
& kPCICantSleep
) ||
5483 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
5485 err
= 6; // 6. PCI card does not support PM
5486 pciCantSleepFlag
= true;
5495 DLOG("System sleep prevented by %d\n", err
);
5501 //******************************************************************************
5502 // checkSystemCanSustainFullWake
5503 //******************************************************************************
5505 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
5508 if (lowBatteryCondition
)
5510 // Low battery wake, or received a low battery notification
5511 // while system is awake.
5515 if (clamshellExists
&& clamshellClosed
&& !acAdaptorConnected
&&
5516 !clamshellSleepDisabled
)
5518 // Lid closed on battery power
5525 //******************************************************************************
5528 // Conditions that affect our wake/sleep decision has changed.
5529 // If conditions dictate that the system must remain awake, clamp power
5530 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
5531 // is TRUE, then remove the power clamp and allow the power state to drop
5533 //******************************************************************************
5535 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
5537 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
5538 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
5542 if ((sleepSlider
== 0) || !checkSystemCanSleep())
5544 changePowerStateToPriv(ON_STATE
);
5546 else if ( sleepASAP
)
5548 changePowerStateToPriv(SLEEP_STATE
);
5552 //******************************************************************************
5553 // dispatchPowerEvent
5555 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
5556 //******************************************************************************
5558 void IOPMrootDomain::dispatchPowerEvent(
5559 uint32_t event
, void * arg0
, uint64_t arg1
)
5561 DLOG("power event %u args %p 0x%llx\n", event
, arg0
, arg1
);
5566 case kPowerEventFeatureChanged
:
5567 messageClients(kIOPMMessageFeatureChange
, this);
5570 case kPowerEventReceivedPowerNotification
:
5571 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
5574 case kPowerEventSystemBootCompleted
:
5577 systemBooting
= false;
5579 if (lowBatteryCondition
)
5581 privateSleepSystem (kIOPMSleepReasonLowPower
);
5583 // The rest is unnecessary since the system is expected
5584 // to sleep immediately. The following wake will update
5589 // If lid is closed, re-send lid closed notification
5590 // now that booting is complete.
5591 if ( clamshellClosed
)
5593 handlePowerNotification(kLocalEvalClamshellCommand
);
5595 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
5599 case kPowerEventSystemShutdown
:
5600 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
5602 /* We set systemShutdown = true during shutdown
5603 to prevent sleep at unexpected times while loginwindow is trying
5604 to shutdown apps and while the OS is trying to transition to
5607 Set to true during shutdown, as soon as loginwindow shows
5608 the "shutdown countdown dialog", through individual app
5609 termination, and through black screen kernel shutdown.
5611 systemShutdown
= true;
5614 A shutdown was initiated, but then the shutdown
5615 was cancelled, clearing systemShutdown to false here.
5617 systemShutdown
= false;
5621 case kPowerEventUserDisabledSleep
:
5622 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
5625 case kPowerEventRegisterSystemCapabilityClient
:
5626 if (systemCapabilityNotifier
)
5628 systemCapabilityNotifier
->release();
5629 systemCapabilityNotifier
= 0;
5633 systemCapabilityNotifier
= (IONotifier
*) arg0
;
5634 systemCapabilityNotifier
->retain();
5636 /* intentional fall-through */
5638 case kPowerEventRegisterKernelCapabilityClient
:
5639 if (!_joinedCapabilityClients
)
5640 _joinedCapabilityClients
= OSSet::withCapacity(8);
5643 IONotifier
* notify
= (IONotifier
*) arg0
;
5644 if (_joinedCapabilityClients
)
5646 _joinedCapabilityClients
->setObject(notify
);
5647 synchronizePowerTree( kIOPMSyncNoChildNotify
);
5653 case kPowerEventPolicyStimulus
:
5656 int stimulus
= (uintptr_t) arg0
;
5657 evaluatePolicy( stimulus
, (uint32_t) arg1
);
5661 case kPowerEventAssertionCreate
:
5663 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
5668 case kPowerEventAssertionRelease
:
5670 pmAssertions
->handleReleaseAssertion(arg1
);
5674 case kPowerEventAssertionSetLevel
:
5676 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
5680 case kPowerEventQueueSleepWakeUUID
:
5681 handleQueueSleepWakeUUID((OSObject
*)arg0
);
5683 case kPowerEventPublishSleepWakeUUID
:
5684 handlePublishSleepWakeUUID((bool)arg0
);
5686 case kPowerEventSuspendClient
:
5687 handleSuspendPMNotificationClient((uintptr_t)arg0
, (bool)arg1
);
5692 //******************************************************************************
5693 // systemPowerEventOccurred
5695 // The power controller is notifying us of a hardware-related power management
5696 // event that we must handle.
5698 // systemPowerEventOccurred covers the same functionality that
5699 // receivePowerNotification does; it simply provides a richer API for conveying
5700 // more information.
5701 //******************************************************************************
5703 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5704 const OSSymbol
*event
,
5707 IOReturn attempt
= kIOReturnSuccess
;
5708 OSNumber
*newNumber
= NULL
;
5711 return kIOReturnBadArgument
;
5713 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
5715 return kIOReturnInternalError
;
5717 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
5719 newNumber
->release();
5724 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5725 const OSSymbol
*event
,
5728 OSDictionary
*thermalsDict
= NULL
;
5729 bool shouldUpdate
= true;
5731 if (!event
|| !value
)
5732 return kIOReturnBadArgument
;
5735 // We reuse featuresDict Lock because it already exists and guards
5736 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5737 // of stepping on that lock.
5738 if (featuresDictLock
) IOLockLock(featuresDictLock
);
5740 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
5742 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
5743 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
5745 thermalsDict
= OSDictionary::withCapacity(1);
5748 if (!thermalsDict
) {
5749 shouldUpdate
= false;
5753 thermalsDict
->setObject (event
, value
);
5755 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
5757 thermalsDict
->release();
5761 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
5764 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
5766 return kIOReturnSuccess
;
5769 //******************************************************************************
5770 // receivePowerNotification
5772 // The power controller is notifying us of a hardware-related power management
5773 // event that we must handle. This may be a result of an 'environment' interrupt
5774 // from the power mgt micro.
5775 //******************************************************************************
5777 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
5779 pmPowerStateQueue
->submitPowerEvent(
5780 kPowerEventReceivedPowerNotification
, (void *) msg
);
5781 return kIOReturnSuccess
;
5784 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
5786 bool eval_clamshell
= false;
5791 * Local (IOPMrootDomain only) eval clamshell command
5793 if (msg
& kLocalEvalClamshellCommand
)
5795 eval_clamshell
= true;
5801 if (msg
& kIOPMOverTemp
)
5803 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
5804 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
5807 if (msg
& kIOPMDWOverTemp
)
5809 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU
) ||
5810 (_systemTransitionType
== kSystemTransitionSleep
) ||
5811 (_systemTransitionType
== kSystemTransitionWake
) ||
5812 (_systemTransitionType
== kSystemTransitionCapability
))
5814 // During early wake or when system capability is changing,
5815 // set flag and take action at end of transition.
5816 darkWakeThermalAlarm
= true;
5818 else if (!wranglerTickled
&& !darkWakeThermalEmergency
&&
5819 !CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
5821 // System in steady state and in dark wake
5822 darkWakeThermalEmergency
= true;
5823 privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
5824 MSG("DarkWake thermal limits breached. Going to sleep!\n");
5831 if (msg
& kIOPMSleepNow
)
5833 privateSleepSystem (kIOPMSleepReasonSoftware
);
5839 if (msg
& kIOPMPowerEmergency
)
5841 lowBatteryCondition
= true;
5842 privateSleepSystem (kIOPMSleepReasonLowPower
);
5848 if (msg
& kIOPMClamshellOpened
)
5850 // Received clamshel open message from clamshell controlling driver
5851 // Update our internal state and tell general interest clients
5852 clamshellClosed
= false;
5853 clamshellExists
= true;
5855 // Don't issue a hid tickle when lid is open and polled on wake
5856 if (msg
& kIOPMSetValue
)
5858 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
5863 informCPUStateChange(kInformLid
, 0);
5865 // Tell general interest clients
5866 sendClientClamshellNotification();
5868 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
5869 || (lastSleepReason
== kIOPMSleepReasonIdle
)
5870 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
5871 if (aborting
) userActivityCount
++;
5872 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
5877 * Send the clamshell interest notification since the lid is closing.
5879 if (msg
& kIOPMClamshellClosed
)
5881 // Received clamshel open message from clamshell controlling driver
5882 // Update our internal state and tell general interest clients
5883 clamshellClosed
= true;
5884 clamshellExists
= true;
5887 informCPUStateChange(kInformLid
, 1);
5889 // Tell general interest clients
5890 sendClientClamshellNotification();
5892 // And set eval_clamshell = so we can attempt
5893 eval_clamshell
= true;
5897 * Set Desktop mode (sent from graphics)
5899 * -> reevaluate lid state
5901 if (msg
& kIOPMSetDesktopMode
)
5903 desktopMode
= (0 != (msg
& kIOPMSetValue
));
5904 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
5906 sendClientClamshellNotification();
5908 // Re-evaluate the lid state
5909 if( clamshellClosed
)
5911 eval_clamshell
= true;
5916 * AC Adaptor connected
5918 * -> reevaluate lid state
5920 if (msg
& kIOPMSetACAdaptorConnected
)
5922 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
5923 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
5926 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
5928 // Tell BSD if AC is connected
5929 // 0 == external power source; 1 == on battery
5930 post_sys_powersource(acAdaptorConnected
? 0:1);
5932 sendClientClamshellNotification();
5934 // Re-evaluate the lid state
5935 if( clamshellClosed
)
5937 eval_clamshell
= true;
5940 // Lack of AC may have latched a display wrangler tickle.
5941 // This mirrors the hardware's USB wake event latch, where a latched
5942 // USB wake event followed by an AC attach will trigger a full wake.
5943 latchDisplayWranglerTickle( false );
5946 // AC presence will reset the standy timer delay adjustment.
5947 _standbyTimerResetSeconds
= 0;
5952 * Enable Clamshell (external display disappear)
5954 * -> reevaluate lid state
5956 if (msg
& kIOPMEnableClamshell
)
5958 // Re-evaluate the lid state
5959 // System should sleep on external display disappearance
5960 // in lid closed operation.
5961 if( clamshellClosed
&& (true == clamshellDisabled
) )
5963 eval_clamshell
= true;
5966 clamshellDisabled
= false;
5968 sendClientClamshellNotification();
5972 * Disable Clamshell (external display appeared)
5973 * We don't bother re-evaluating clamshell state. If the system is awake,
5974 * the lid is probably open.
5976 if (msg
& kIOPMDisableClamshell
)
5978 clamshellDisabled
= true;
5980 sendClientClamshellNotification();
5984 * Evaluate clamshell and SLEEP if appropiate
5986 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
5990 privateSleepSystem (kIOPMSleepReasonClamshell
);
5992 else if ( eval_clamshell
)
5994 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6000 if (msg
& kIOPMPowerButton
)
6002 if (!wranglerAsleep
)
6004 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6005 // Check that power button sleep is enabled
6007 if( kOSBooleanTrue
!= getProperty(pbs
))
6008 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6016 //******************************************************************************
6019 // Evaluate root-domain policy in response to external changes.
6020 //******************************************************************************
6022 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6026 int idleSleepEnabled
: 1;
6027 int idleSleepDisabled
: 1;
6028 int displaySleep
: 1;
6029 int sleepDelayChanged
: 1;
6030 int evaluateDarkWake
: 1;
6031 int adjustPowerState
: 1;
6036 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6043 case kStimulusDisplayWranglerSleep
:
6044 if (!wranglerAsleep
)
6046 wranglerAsleep
= true;
6047 clock_get_uptime(&wranglerSleepTime
);
6048 flags
.bit
.displaySleep
= true;
6052 case kStimulusDisplayWranglerWake
:
6053 wranglerAsleep
= false;
6054 flags
.bit
.idleSleepDisabled
= true;
6057 case kStimulusAggressivenessChanged
:
6059 unsigned long minutesToIdleSleep
= 0;
6060 unsigned long minutesToDisplayDim
= 0;
6061 unsigned long minutesDelta
= 0;
6063 // Fetch latest display and system sleep slider values.
6064 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
6065 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
6066 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6067 (uint32_t) sleepSlider
,
6068 (uint32_t) minutesToIdleSleep
,
6069 (uint32_t) minutesToDisplayDim
);
6071 DLOG("idle time -> %ld secs (ena %d)\n",
6072 idleSeconds
, (minutesToIdleSleep
!= 0));
6074 if (0x7fffffff == minutesToIdleSleep
)
6075 minutesToIdleSleep
= idleSeconds
;
6077 // How long to wait before sleeping the system once
6078 // the displays turns off is indicated by 'extraSleepDelay'.
6080 if ( minutesToIdleSleep
> minutesToDisplayDim
)
6081 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
6082 else if( minutesToIdleSleep
== minutesToDisplayDim
)
6085 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
6086 flags
.bit
.idleSleepEnabled
= true;
6088 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
6089 flags
.bit
.idleSleepDisabled
= true;
6091 if ((minutesDelta
!= extraSleepDelay
) &&
6092 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
6093 flags
.bit
.sleepDelayChanged
= true;
6095 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
6096 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
6098 // Reconsider decision to remain in dark wake
6099 flags
.bit
.evaluateDarkWake
= true;
6102 sleepSlider
= minutesToIdleSleep
;
6103 extraSleepDelay
= minutesDelta
;
6106 case kStimulusDemandSystemSleep
:
6107 changePowerStateWithOverrideTo( SLEEP_STATE
);
6110 case kStimulusAllowSystemSleepChanged
:
6111 flags
.bit
.adjustPowerState
= true;
6114 case kStimulusDarkWakeActivityTickle
:
6115 if (false == wranglerTickled
)
6117 uint32_t options
= 0;
6118 IOService
* pciRoot
= 0;
6120 if (rejectWranglerTickle
)
6122 DLOG("rejected tickle, type %u capability %x:%x\n",
6123 _systemTransitionType
,
6124 _currentCapability
, _pendingCapability
);
6128 if (latchDisplayWranglerTickle(true))
6130 DLOG("latched tickle\n");
6134 _desiredCapability
|=
6135 (kIOPMSystemCapabilityGraphics
|
6136 kIOPMSystemCapabilityAudio
);
6138 if ((kSystemTransitionWake
== _systemTransitionType
) &&
6139 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6140 !graphicsSuppressed
)
6142 DLOG("Promoting to full wake\n");
6144 // Elevate to full wake while waking up to dark wake.
6145 // PM will hold off notifying the graphics subsystem about
6146 // system wake as late as possible, so if a HID event does
6147 // arrive, we can turn on graphics on this wake cycle, and
6148 // not have to wait till the following cycle. That latency
6149 // can be huge on some systems. However, once any graphics
6150 // suppression has taken effect, it is too late. All other
6151 // graphics devices must be similarly suppressed. But the
6152 // delay till the following cycle should be very short.
6154 _pendingCapability
|=
6155 (kIOPMSystemCapabilityGraphics
|
6156 kIOPMSystemCapabilityAudio
);
6158 // Immediately bring up audio and graphics.
6159 pciRoot
= pciHostBridgeDriver
;
6161 // Notify clients about full wake.
6162 _systemMessageClientMask
= kSystemMessageClientAll
;
6163 IOService::setAdvisoryTickleEnable( true );
6164 tellClients(kIOMessageSystemWillPowerOn
);
6167 // Unsafe to cancel once graphics was powered.
6168 // If system woke from dark wake, the return to sleep can
6169 // be cancelled. But "awake -> dark -> sleep" transition
6170 // cannot be cancelled.
6172 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
6173 options
|= kIOPMSyncCancelPowerDown
;
6176 synchronizePowerTree( options
, pciRoot
);
6177 wranglerTickled
= true;
6178 // IOGraphics doesn't lit the display even though graphics
6179 // is enanbled in kIOMessageSystemCapabilityChange message(radar 9502104)
6180 // So, do an explicit activity tickle
6182 wrangler
->activityTickle(0,0);
6184 if (logWranglerTickle
)
6189 clock_get_uptime(&now
);
6190 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
6191 absolutetime_to_nanoseconds(now
, &nsec
);
6192 MSG("HID tickle %u ms\n",
6193 ((int)((nsec
) / 1000000ULL)));
6194 logWranglerTickle
= false;
6199 case kStimulusDarkWakeEntry
:
6200 case kStimulusDarkWakeReentry
:
6201 // Any system transitions since the last dark wake transition
6202 // will invalid the stimulus.
6204 if (arg
== _systemStateGeneration
)
6206 DLOG("dark wake entry\n");
6207 systemDarkWake
= true;
6208 wranglerAsleep
= true;
6209 clock_get_uptime(&wranglerSleepTime
);
6211 // Always accelerate disk spindown while in dark wake,
6212 // even if system does not support/allow sleep.
6214 cancelIdleSleepTimer();
6215 setQuickSpinDownTimeout();
6216 flags
.bit
.evaluateDarkWake
= true;
6220 case kStimulusDarkWakeEvaluate
:
6223 flags
.bit
.evaluateDarkWake
= true;
6225 #if !DARK_TO_FULL_EVALUATE_CLAMSHELL
6228 // Not through kLocalEvalClamshellCommand to avoid loop.
6229 if (clamshellClosed
&& shouldSleepOnClamshellClosed() &&
6230 checkSystemCanSleep(true))
6232 privateSleepSystem( kIOPMSleepReasonClamshell
);
6238 case kStimulusNoIdleSleepPreventers
:
6239 flags
.bit
.adjustPowerState
= true;
6242 } /* switch(stimulus) */
6244 if (flags
.bit
.evaluateDarkWake
&& !wranglerTickled
)
6246 if (darkWakeToSleepASAP
||
6247 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
6249 // System currently in dark wake, and no children and
6250 // assertion prevent system sleep.
6252 if (checkSystemCanSleep(true))
6254 if (lowBatteryCondition
)
6256 lastSleepReason
= kIOPMSleepReasonLowPower
;
6257 setProperty(kRootDomainSleepReasonKey
, kIOPMLowPowerSleepKey
);
6259 else if (darkWakeMaintenance
)
6261 lastSleepReason
= kIOPMSleepReasonMaintenance
;
6262 setProperty(kRootDomainSleepReasonKey
, kIOPMMaintenanceSleepKey
);
6264 else if (darkWakeSleepService
)
6266 lastSleepReason
= kIOPMSleepReasonSleepServiceExit
;
6267 setProperty(kRootDomainSleepReasonKey
, kIOPMSleepServiceExitKey
);
6269 changePowerStateWithOverrideTo( SLEEP_STATE
);
6273 // Parked in dark wake, a tickle will return to full wake
6274 rejectWranglerTickle
= false;
6277 else // non-maintenance (network) dark wake
6279 if (checkSystemCanSleep(true))
6281 // Release power clamp, and wait for children idle.
6282 adjustPowerState(true);
6286 changePowerStateToPriv(ON_STATE
);
6288 rejectWranglerTickle
= false;
6294 // The rest are irrelevant while system is in dark wake.
6298 if (flags
.bit
.displaySleep
|| flags
.bit
.sleepDelayChanged
)
6300 bool cancelQuickSpindown
= false;
6302 if (flags
.bit
.sleepDelayChanged
)
6304 DLOG("extra sleep timer changed\n");
6305 cancelIdleSleepTimer();
6306 cancelQuickSpindown
= true;
6310 DLOG("display sleep\n");
6313 if (wranglerAsleep
&& !wranglerSleepIgnored
)
6315 if ( extraSleepDelay
)
6317 // Start a timer here if the System Sleep timer is greater
6318 // than the Display Sleep timer.
6320 startIdleSleepTimer(gRootDomain
->extraSleepDelay
* 60);
6322 else if ( sleepSlider
)
6324 // Accelerate disk spindown if system sleep and display sleep
6325 // sliders are set to the same value (e.g. both set to 5 min),
6326 // and display is about to go dark. Check the system sleep is
6327 // not set to never sleep. Disk sleep setting is ignored.
6329 setQuickSpinDownTimeout();
6330 cancelQuickSpindown
= false;
6334 if (cancelQuickSpindown
)
6335 restoreUserSpinDownTimeout();
6338 if (flags
.bit
.idleSleepEnabled
)
6340 DLOG("idle sleep timer enabled\n");
6343 changePowerStateToPriv(ON_STATE
);
6346 startIdleSleepTimer( idleSeconds
);
6351 // Start idle sleep timer if wrangler went to sleep
6352 // while system sleep was disabled. Disk spindown is
6353 // accelerated upon timer expiration.
6359 uint32_t minutesSinceDisplaySleep
= 0;
6360 uint32_t sleepDelay
= 0;
6362 clock_get_uptime(&now
);
6363 if (CMP_ABSOLUTETIME(&now
, &wranglerSleepTime
) > 0)
6365 SUB_ABSOLUTETIME(&now
, &wranglerSleepTime
);
6366 absolutetime_to_nanoseconds(now
, &nanos
);
6367 minutesSinceDisplaySleep
= nanos
/ (60000000000ULL);
6370 if (extraSleepDelay
> minutesSinceDisplaySleep
)
6372 sleepDelay
= extraSleepDelay
- minutesSinceDisplaySleep
;
6375 startIdleSleepTimer(sleepDelay
* 60);
6376 DLOG("display slept %u min, set idle timer to %u min\n",
6377 minutesSinceDisplaySleep
, sleepDelay
);
6382 if (flags
.bit
.idleSleepDisabled
)
6384 DLOG("idle sleep timer disabled\n");
6385 cancelIdleSleepTimer();
6386 restoreUserSpinDownTimeout();
6390 if (flags
.bit
.adjustPowerState
)
6392 bool sleepASAP
= false;
6394 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
6398 changePowerStateToPriv(ON_STATE
);
6401 // stay awake for at least idleSeconds
6402 startIdleSleepTimer(idleSeconds
);
6405 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
6412 lastSleepReason
= kIOPMSleepReasonIdle
;
6413 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
6416 adjustPowerState(sleepASAP
);
6420 //******************************************************************************
6421 // evaluateAssertions
6423 //******************************************************************************
6424 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
6426 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
6428 messageClients(kIOPMMessageDriverAssertionsChanged
);
6430 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
6434 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
6435 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
6436 wrangler
->setIgnoreIdleTimer( value
);
6440 if (changedBits
& kIOPMDriverAssertionCPUBit
)
6441 evaluatePolicy(kStimulusDarkWakeEvaluate
);
6443 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
6444 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
6446 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
6447 updatePreventIdleSleepList(this, true);
6450 DLOG("Driver assertion ReservedBit7 dropped\n");
6451 updatePreventIdleSleepList(this, false);
6460 //******************************************************************************
6463 //******************************************************************************
6465 void IOPMrootDomain::pmStatsRecordEvent(
6467 AbsoluteTime timestamp
)
6469 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
6470 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
6473 OSData
*publishPMStats
= NULL
;
6475 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
6477 absolutetime_to_nanoseconds(timestamp
, &nsec
);
6479 switch (eventIndex
) {
6480 case kIOPMStatsHibernateImageWrite
:
6482 gPMStats
.hibWrite
.start
= nsec
;
6484 gPMStats
.hibWrite
.stop
= nsec
;
6487 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
6488 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
6491 case kIOPMStatsHibernateImageRead
:
6493 gPMStats
.hibRead
.start
= nsec
;
6495 gPMStats
.hibRead
.stop
= nsec
;
6498 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
6499 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
6501 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
6502 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
6503 publishPMStats
->release();
6504 bzero(&gPMStats
, sizeof(gPMStats
));
6511 * Appends a record of the application response to
6512 * IOPMrootDomain::pmStatsAppResponses
6514 void IOPMrootDomain::pmStatsRecordApplicationResponse(
6515 const OSSymbol
*response
,
6521 OSDictionary
*responseDescription
= NULL
;
6522 OSNumber
*delayNum
= NULL
;
6523 OSNumber
*pidNum
= NULL
;
6524 OSNumber
*msgNum
= NULL
;
6525 const OSSymbol
*appname
;
6526 const OSSymbol
*entryName
;
6527 OSObject
*entryType
;
6530 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
6534 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
6536 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
6537 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
6538 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
))
6540 OSNumber
* entryValue
;
6541 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
6542 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
6543 entryValue
->setValue(delay_ms
);
6548 responseDescription
= OSDictionary::withCapacity(5);
6549 if (responseDescription
)
6552 responseDescription
->setObject(_statsResponseTypeKey
, response
);
6555 if (messageType
!= 0) {
6556 msgNum
= OSNumber::withNumber(messageType
, 32);
6558 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
6563 if (name
&& (strlen(name
) > 0))
6565 appname
= OSSymbol::withCString(name
);
6567 responseDescription
->setObject(_statsNameKey
, appname
);
6572 if (app_pid
!= -1) {
6573 pidNum
= OSNumber::withNumber(app_pid
, 32);
6575 responseDescription
->setObject(_statsPIDKey
, pidNum
);
6580 delayNum
= OSNumber::withNumber(delay_ms
, 32);
6582 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
6583 delayNum
->release();
6586 if (pmStatsAppResponses
) {
6587 pmStatsAppResponses
->setObject(responseDescription
);
6590 responseDescription
->release();
6596 // MARK: PMTraceWorker
6598 //******************************************************************************
6599 // TracePoint support
6601 //******************************************************************************
6603 #define kIOPMRegisterNVRAMTracePointHandlerKey \
6604 "IOPMRegisterNVRAMTracePointHandler"
6606 IOReturn
IOPMrootDomain::callPlatformFunction(
6607 const OSSymbol
* functionName
,
6608 bool waitForFunction
,
6609 void * param1
, void * param2
,
6610 void * param3
, void * param4
)
6612 if (pmTracer
&& functionName
&&
6613 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
6614 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
6616 uint32_t tracePointPhases
, tracePointPCI
;
6617 uint64_t statusCode
;
6619 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
6620 pmTracer
->tracePointTarget
= (void *) param2
;
6621 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
6622 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
6623 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
6624 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
6626 MSG("Sleep failure code 0x%08x 0x%08x\n",
6627 tracePointPCI
, tracePointPhases
);
6629 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
6630 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
6632 return kIOReturnSuccess
;
6635 else if (functionName
&&
6636 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
6638 if (gSleepPolicyHandler
)
6639 return kIOReturnExclusiveAccess
;
6641 return kIOReturnBadArgument
;
6642 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
6643 gSleepPolicyTarget
= (void *) param2
;
6644 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
6645 return kIOReturnSuccess
;
6649 return super::callPlatformFunction(
6650 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
6653 void IOPMrootDomain::tracePoint( uint8_t point
)
6655 if (systemBooting
) return;
6657 pmTracer
->tracePoint(point
);
6660 if (kIOPMTracePointSleepPowerPlaneDrivers
== point
) IOHibernateIOKitSleep();
6664 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
6667 pmTracer
->tracePoint(point
, data
);
6670 void IOPMrootDomain::traceDetail( uint32_t detail
)
6673 pmTracer
->traceDetail( detail
);
6676 //******************************************************************************
6677 // PMTraceWorker Class
6679 //******************************************************************************
6682 #define super OSObject
6683 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
6685 #define kPMBestGuessPCIDevicesCount 25
6686 #define kPMMaxRTCBitfieldSize 32
6688 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
6692 me
= OSTypeAlloc( PMTraceWorker
);
6693 if (!me
|| !me
->init())
6698 DLOG("PMTraceWorker %p\n", me
);
6700 // Note that we cannot instantiate the PCI device -> bit mappings here, since
6701 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
6702 // this dictionary lazily.
6704 me
->pciDeviceBitMappings
= NULL
;
6705 me
->pciMappingLock
= IOLockAlloc();
6706 me
->tracePhase
= kIOPMTracePointSystemUp
;
6707 me
->loginWindowPhase
= 0;
6708 me
->traceData32
= 0;
6712 void PMTraceWorker::RTC_TRACE(void)
6714 if (tracePointHandler
&& tracePointTarget
)
6718 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
6721 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
6722 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
6726 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
6728 const OSSymbol
* deviceName
;
6731 IOLockLock(pciMappingLock
);
6733 if (!pciDeviceBitMappings
)
6735 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
6736 if (!pciDeviceBitMappings
)
6740 // Check for bitmask overflow.
6741 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
6744 if ((deviceName
= pciDevice
->copyName()) &&
6745 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
6746 pciDeviceBitMappings
->setObject(deviceName
))
6748 index
= pciDeviceBitMappings
->getCount() - 1;
6749 _LOG("PMTrace PCI array: set object %s => %d\n",
6750 deviceName
->getCStringNoCopy(), index
);
6753 deviceName
->release();
6754 if (!addedToRegistry
&& (index
>= 0))
6755 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
6758 IOLockUnlock(pciMappingLock
);
6762 bool PMTraceWorker::serialize(OSSerialize
*s
) const
6765 if (pciDeviceBitMappings
)
6767 IOLockLock(pciMappingLock
);
6768 ok
= pciDeviceBitMappings
->serialize(s
);
6769 IOLockUnlock(pciMappingLock
);
6774 void PMTraceWorker::tracePoint(uint8_t phase
)
6776 // clear trace detail when phase begins
6777 if (tracePhase
!= phase
)
6782 DLOG("trace point 0x%02x\n", tracePhase
);
6786 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
6788 // clear trace detail when phase begins
6789 if (tracePhase
!= phase
)
6795 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
6799 void PMTraceWorker::traceDetail(uint32_t detail
)
6801 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
6804 traceData32
= detail
;
6805 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
6810 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
6812 loginWindowPhase
= phase
;
6814 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
6818 void PMTraceWorker::tracePCIPowerChange(
6819 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
6822 uint32_t expectedFlag
;
6824 // Ignore PCI changes outside of system sleep/wake.
6825 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
6826 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
6829 // Only record the WillChange transition when going to sleep,
6830 // and the DidChange on the way up.
6831 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
6832 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
6833 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
6834 if (changeFlags
!= expectedFlag
)
6837 // Mark this device off in our bitfield
6838 if (bitNum
< kPMMaxRTCBitfieldSize
)
6840 bitMask
= (1 << bitNum
);
6842 if (kPowerChangeStart
== type
)
6844 traceData32
|= bitMask
;
6845 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
6846 service
->getName(), bitNum
, bitMask
, traceData32
);
6850 traceData32
&= ~bitMask
;
6851 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
6852 service
->getName(), bitNum
, bitMask
, traceData32
);
6860 // MARK: PMHaltWorker
6862 //******************************************************************************
6863 // PMHaltWorker Class
6865 //******************************************************************************
6867 static unsigned int gPMHaltBusyCount
;
6868 static unsigned int gPMHaltIdleCount
;
6869 static int gPMHaltDepth
;
6870 static unsigned long gPMHaltEvent
;
6871 static IOLock
* gPMHaltLock
= 0;
6872 static OSArray
* gPMHaltArray
= 0;
6873 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
6875 PMHaltWorker
* PMHaltWorker::worker( void )
6881 me
= OSTypeAlloc( PMHaltWorker
);
6882 if (!me
|| !me
->init())
6885 me
->lock
= IOLockAlloc();
6889 DLOG("PMHaltWorker %p\n", me
);
6890 me
->retain(); // thread holds extra retain
6891 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
6896 thread_deallocate(thread
);
6901 if (me
) me
->release();
6905 void PMHaltWorker::free( void )
6907 DLOG("PMHaltWorker free %p\n", this);
6913 return OSObject::free();
6916 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
6918 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
6920 IOLockLock( gPMHaltLock
);
6922 me
->depth
= gPMHaltDepth
;
6923 IOLockUnlock( gPMHaltLock
);
6925 while (me
->depth
>= 0)
6927 PMHaltWorker::work( me
);
6929 IOLockLock( gPMHaltLock
);
6930 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
6932 // This is the last thread to finish work on this level,
6933 // inform everyone to start working on next lower level.
6935 me
->depth
= gPMHaltDepth
;
6936 gPMHaltIdleCount
= 0;
6937 thread_wakeup((event_t
) &gPMHaltIdleCount
);
6941 // One or more threads are still working on this level,
6942 // this thread must wait.
6943 me
->depth
= gPMHaltDepth
- 1;
6945 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
6946 } while (me
->depth
!= gPMHaltDepth
);
6948 IOLockUnlock( gPMHaltLock
);
6951 // No more work to do, terminate thread
6952 DLOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
6953 thread_wakeup( &gPMHaltDepth
);
6957 void PMHaltWorker::work( PMHaltWorker
* me
)
6959 IOService
* service
;
6961 AbsoluteTime startTime
;
6970 // Claim an unit of work from the shared pool
6971 IOLockLock( gPMHaltLock
);
6972 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
6975 service
= (IOService
*)inner
->getAnyObject();
6979 inner
->removeObject(service
);
6982 IOLockUnlock( gPMHaltLock
);
6984 break; // no more work at this depth
6986 clock_get_uptime(&startTime
);
6988 if (!service
->isInactive() &&
6989 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
6991 IOLockLock(me
->lock
);
6992 me
->startTime
= startTime
;
6993 me
->service
= service
;
6994 me
->timeout
= false;
6995 IOLockUnlock(me
->lock
);
6997 service
->systemWillShutdown( gPMHaltEvent
);
6999 // Wait for driver acknowledgement
7000 IOLockLock(me
->lock
);
7001 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
7003 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
7006 timeout
= me
->timeout
;
7007 IOLockUnlock(me
->lock
);
7010 deltaTime
= computeDeltaTimeMS(&startTime
);
7011 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
7012 (gIOKitDebug
& kIOLogPMRootDomain
))
7014 LOG("%s driver %s (%p) took %u ms\n",
7015 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
7016 "PowerOff" : "Restart",
7017 service
->getName(), service
,
7018 (uint32_t) deltaTime
);
7026 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
7029 AbsoluteTime startTime
;
7030 AbsoluteTime endTime
;
7034 IOLockLock(me
->lock
);
7035 if (me
->service
&& !me
->timeout
)
7037 startTime
= me
->startTime
;
7039 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
7041 SUB_ABSOLUTETIME(&endTime
, &startTime
);
7042 absolutetime_to_nanoseconds(endTime
, &nano
);
7044 if (nano
> 3000000000ULL)
7047 MSG("%s still waiting on %s\n",
7048 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
7049 "PowerOff" : "Restart",
7050 me
->service
->getName());
7053 IOLockUnlock(me
->lock
);
7057 //******************************************************************************
7058 // acknowledgeSystemWillShutdown
7060 // Acknowledgement from drivers that they have prepared for shutdown/restart.
7061 //******************************************************************************
7063 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
7065 PMHaltWorker
* worker
;
7071 //DLOG("%s acknowledged\n", from->getName());
7072 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
7075 worker
= (PMHaltWorker
*) prop
;
7076 IOLockLock(worker
->lock
);
7077 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
7078 thread_wakeup((event_t
) worker
);
7079 IOLockUnlock(worker
->lock
);
7084 DLOG("%s acknowledged without worker property\n",
7090 //******************************************************************************
7091 // notifySystemShutdown
7093 // Notify all objects in PM tree that system will shutdown or restart
7094 //******************************************************************************
7097 notifySystemShutdown( IOService
* root
, unsigned long event
)
7099 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
7100 IORegistryIterator
* iter
;
7101 IORegistryEntry
* entry
;
7104 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
7105 AbsoluteTime deadline
;
7106 unsigned int totalNodes
= 0;
7108 unsigned int rootDepth
;
7109 unsigned int numWorkers
;
7115 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
7117 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
7119 // Iterate the entire PM tree starting from root
7121 rootDepth
= root
->getDepth( gIOPowerPlane
);
7122 if (!rootDepth
) goto done
;
7124 // debug - for repeated test runs
7125 while (PMHaltWorker::metaClass
->getInstanceCount())
7130 gPMHaltArray
= OSArray::withCapacity(40);
7131 if (!gPMHaltArray
) goto done
;
7134 gPMHaltArray
->flushCollection();
7138 gPMHaltLock
= IOLockAlloc();
7139 if (!gPMHaltLock
) goto done
;
7142 if (!gPMHaltClientAcknowledgeKey
)
7144 gPMHaltClientAcknowledgeKey
=
7145 OSSymbol::withCStringNoCopy("PMShutdown");
7146 if (!gPMHaltClientAcknowledgeKey
) goto done
;
7149 gPMHaltEvent
= event
;
7151 // Depth-first walk of PM plane
7153 iter
= IORegistryIterator::iterateOver(
7154 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
7158 while ((entry
= iter
->getNextObject()))
7160 node
= OSDynamicCast(IOService
, entry
);
7165 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
7168 depth
= node
->getDepth( gIOPowerPlane
);
7169 if (depth
<= rootDepth
)
7174 // adjust to zero based depth
7175 depth
-= (rootDepth
+ 1);
7177 // gPMHaltArray is an array of containers, each container
7178 // refers to nodes with the same depth.
7180 count
= gPMHaltArray
->getCount();
7181 while (depth
>= count
)
7183 // expand array and insert placeholders
7184 gPMHaltArray
->setObject(PLACEHOLDER
);
7187 count
= gPMHaltArray
->getCount();
7190 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
7191 if (inner
== PLACEHOLDER
)
7193 inner
= OSSet::withCapacity(40);
7196 gPMHaltArray
->replaceObject(depth
, inner
);
7201 // PM nodes that appear more than once in the tree will have
7202 // the same depth, OSSet will refuse to add the node twice.
7204 ok
= inner
->setObject(node
);
7207 DLOG("Skipped PM node %s\n", node
->getName());
7213 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
7216 if (inner
!= PLACEHOLDER
)
7217 count
= inner
->getCount();
7218 DLOG("Nodes at depth %u = %u\n", i
, count
);
7221 // strip placeholders (not all depths are populated)
7223 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
7225 if (inner
== PLACEHOLDER
)
7227 gPMHaltArray
->removeObject(i
);
7230 count
= inner
->getCount();
7231 if (count
> numWorkers
)
7233 totalNodes
+= count
;
7237 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
7240 gPMHaltBusyCount
= 0;
7241 gPMHaltIdleCount
= 0;
7242 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
7244 // Create multiple workers (and threads)
7246 if (numWorkers
> kPMHaltMaxWorkers
)
7247 numWorkers
= kPMHaltMaxWorkers
;
7249 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
7250 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
7252 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7253 workers
[i
] = PMHaltWorker::worker();
7255 // Wait for workers to exhaust all available work
7257 IOLockLock(gPMHaltLock
);
7258 while (gPMHaltDepth
>= 0)
7260 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
7262 waitResult
= IOLockSleepDeadline(
7263 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
7264 if (THREAD_TIMED_OUT
== waitResult
)
7267 clock_get_uptime(&now
);
7269 IOLockUnlock(gPMHaltLock
);
7270 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
7273 PMHaltWorker::checkTimeout(workers
[i
], &now
);
7275 IOLockLock(gPMHaltLock
);
7278 IOLockUnlock(gPMHaltLock
);
7280 // Release all workers
7282 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7285 workers
[i
]->release();
7286 // worker also retained by it's own thread
7290 DLOG("%s done\n", __FUNCTION__
);
7294 //*********************************************************************************
7295 // Sleep/Wake logging
7297 //*********************************************************************************
7299 IOMemoryDescriptor
*IOPMrootDomain::getPMTraceMemoryDescriptor(void)
7302 return timeline
->getPMTraceMemoryDescriptor();
7307 // Forwards external reports of detailed events to IOPMTimeline
7308 IOReturn
IOPMrootDomain::recordPMEvent(PMEventDetails
*details
)
7310 if (timeline
&& details
) {
7314 // Record a detailed driver power change event, or...
7315 if(details
->eventClassifier
== kIOPMEventClassDriverEvent
) {
7316 rc
= timeline
->recordDetailedPowerEvent( details
);
7319 // Record a system power management event
7320 else if(details
->eventClassifier
== kIOPMEventClassSystemEvent
) {
7321 rc
= timeline
->recordSystemPowerEvent( details
);
7324 return kIOReturnBadArgument
;
7327 // If we get to record this message, then we've reached the
7328 // end of another successful Sleep --> Wake cycle
7329 // At this point, we pat ourselves in the back and allow
7330 // our Sleep --> Wake UUID to be published
7331 if(details
->eventType
== kIOPMEventTypeWakeDone
) {
7332 timeline
->setSleepCycleInProgressFlag(false);
7336 // Check if its time to clear the timeline buffer
7337 if(getProperty(kIOPMSleepWakeUUIDKey)
7338 && timeline->isSleepCycleInProgress() == false
7339 && timeline->getNumEventsLoggedThisPeriod() > 500) {
7341 // Clear the old UUID
7342 if(pmPowerStateQueue) {
7343 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
7350 return kIOReturnNotReady
;
7353 IOReturn
IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails
*details
)
7355 IOReturn ret
= kIOReturnBadArgument
;
7359 ret
= recordPMEvent(details
);
7366 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7368 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
7369 IOPMDriverAssertionType whichAssertionBits
,
7370 IOPMDriverAssertionLevel assertionLevel
,
7371 IOService
*ownerService
,
7372 const char *ownerDescription
)
7375 IOPMDriverAssertionID newAssertion
;
7380 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
7382 if (kIOReturnSuccess
== ret
)
7383 return newAssertion
;
7388 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
7391 return kIOReturnInternalError
;
7393 return pmAssertions
->releaseAssertion(releaseAssertion
);
7396 IOReturn
IOPMrootDomain::setPMAssertionLevel(
7397 IOPMDriverAssertionID assertionID
,
7398 IOPMDriverAssertionLevel assertionLevel
)
7400 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
7403 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
7405 IOPMDriverAssertionType sysLevels
;
7407 if (!pmAssertions
|| whichAssertion
== 0)
7408 return kIOPMDriverAssertionLevelOff
;
7410 sysLevels
= pmAssertions
->getActivatedAssertions();
7412 // Check that every bit set in argument 'whichAssertion' is asserted
7413 // in the aggregate bits.
7414 if ((sysLevels
& whichAssertion
) == whichAssertion
)
7415 return kIOPMDriverAssertionLevelOn
;
7417 return kIOPMDriverAssertionLevelOff
;
7420 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
7423 return kIOReturnNotFound
;
7425 return pmAssertions
->setUserAssertionLevels(inLevels
);
7428 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
7432 pmAssertions
->publishProperties();
7434 return( IOService::serializeProperties(s
) );
7437 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7440 // MARK: PMSettingHandle
7442 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
7444 void PMSettingHandle::free( void )
7448 pmso
->clientHandleFreed();
7457 // MARK: PMSettingObject
7460 #define super OSObject
7461 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
7464 * Static constructor/initializer for PMSettingObject
7466 PMSettingObject
*PMSettingObject::pmSettingObject(
7467 IOPMrootDomain
*parent_arg
,
7468 IOPMSettingControllerCallback handler_arg
,
7469 OSObject
*target_arg
,
7470 uintptr_t refcon_arg
,
7471 uint32_t supportedPowerSources
,
7472 const OSSymbol
* settings
[],
7473 OSObject
**handle_obj
)
7475 uint32_t settingCount
= 0;
7476 PMSettingObject
*pmso
= 0;
7477 PMSettingHandle
*pmsh
= 0;
7479 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
7482 // count OSSymbol entries in NULL terminated settings array
7483 while (settings
[settingCount
]) {
7486 if (0 == settingCount
)
7489 pmso
= new PMSettingObject
;
7490 if (!pmso
|| !pmso
->init())
7493 pmsh
= new PMSettingHandle
;
7494 if (!pmsh
|| !pmsh
->init())
7497 queue_init(&pmso
->calloutQueue
);
7498 pmso
->parent
= parent_arg
;
7499 pmso
->func
= handler_arg
;
7500 pmso
->target
= target_arg
;
7501 pmso
->refcon
= refcon_arg
;
7502 pmso
->settingCount
= settingCount
;
7504 pmso
->retain(); // handle holds a retain on pmso
7508 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
7509 if (pmso
->publishedFeatureID
) {
7510 for (unsigned int i
=0; i
<settingCount
; i
++) {
7511 // Since there is now at least one listener to this setting, publish
7512 // PM root domain support for it.
7513 parent_arg
->publishPMSetting( settings
[i
],
7514 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
7522 if (pmso
) pmso
->release();
7523 if (pmsh
) pmsh
->release();
7527 void PMSettingObject::free( void )
7529 if (publishedFeatureID
) {
7530 for (uint32_t i
=0; i
<settingCount
; i
++) {
7531 if (publishedFeatureID
[i
]) {
7532 parent
->removePublishedFeature( publishedFeatureID
[i
] );
7536 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
7542 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
7544 (*func
)(target
, type
, object
, refcon
);
7547 void PMSettingObject::clientHandleFreed( void )
7549 parent
->deregisterPMSettingObject(this);
7553 // MARK: IOPMTimeline
7556 #define super OSObject
7558 //*********************************************************************************
7559 //*********************************************************************************
7560 //*********************************************************************************
7562 IOPMTimeline
*IOPMTimeline::timeline(IOPMrootDomain
*root_domain
)
7564 IOPMTimeline
*myself
;
7569 myself
= new IOPMTimeline
;
7572 myself
->owner
= root_domain
;
7579 bool IOPMTimeline::init(void)
7581 if (!super::init()) {
7585 logLock
= IOLockAlloc();
7587 // Fresh timeline, no events logged yet
7588 this->numEventsLoggedThisPeriod
= 0;
7589 this->sleepCycleInProgress
= false;
7591 //this->setEventsRecordingLevel(1); // TODO
7592 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked
);
7597 void IOPMTimeline::free(void)
7599 if (pmTraceMemoryDescriptor
) {
7600 pmTraceMemoryDescriptor
->release();
7601 pmTraceMemoryDescriptor
= NULL
;
7604 IOLockFree(logLock
);
7609 IOMemoryDescriptor
*IOPMTimeline::getPMTraceMemoryDescriptor()
7611 return pmTraceMemoryDescriptor
;
7614 //*********************************************************************************
7615 //*********************************************************************************
7616 //*********************************************************************************
7618 bool IOPMTimeline::setProperties(OSDictionary
*d
)
7621 OSBoolean
*b
= NULL
;
7622 bool changed
= false;
7624 /* Changes size of detailed events buffer */
7625 n
= (OSNumber
*)d
->getObject(kIOPMTimelineSystemNumberTrackedKey
);
7626 if (OSDynamicCast(OSNumber
, n
))
7629 this->setEventsTrackedCount(n
->unsigned32BitValue());
7633 /* enables or disables system events */
7634 b
= (OSBoolean
*)d
->getObject(kIOPMTimelineEnabledKey
);
7638 this->setEventsRecordingLevel((int)(kOSBooleanTrue
== b
));
7644 //*********************************************************************************
7645 //*********************************************************************************
7646 //*********************************************************************************
7648 OSDictionary
*IOPMTimeline::copyInfoDictionary(void)
7650 OSDictionary
*out
= OSDictionary::withCapacity(3);
7656 n
= OSNumber::withNumber(hdr
->sizeEntries
, 32);
7657 out
->setObject(kIOPMTimelineSystemNumberTrackedKey
, n
);
7660 n
= OSNumber::withNumber(hdr
->sizeBytes
, 32);
7661 out
->setObject(kIOPMTimelineSystemBufferSizeKey
, n
);
7665 out
->setObject(kIOPMTimelineEnabledKey
, eventsRecordingLevel
? kOSBooleanTrue
: kOSBooleanFalse
);
7670 //*********************************************************************************
7671 //*********************************************************************************
7672 //*********************************************************************************
7674 /* IOPMTimeline::recordSystemPowerEvent()
7676 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
7677 * Type arguments include "system events", and "Intermediate events"
7679 * - System Events have paired "start" and "stop" events.
7680 * - A start event shall be followed by a stop event.
7681 * - Any number of Intermediate Events may fall between the
7682 * start and stop events.
7683 * - Intermediate events are meaningless outside the bounds of a system event's
7684 * start & stoup routines.
7685 * - It's invalid to record a Start event without a following Stop event; e.g. two
7686 * Start events without an intervenining Stop event is invalid.
7689 * - The first recorded system event shall be preceded by an entry with type == 0
7690 * - IOPMTimeline may choose not to record intermediate events while there's not
7691 * a system event in process.
7693 IOReturn
IOPMTimeline::recordSystemPowerEvent( PMEventDetails
*details
)
7695 static bool wakeDonePending
= true;
7696 IOPMSystemEventRecord
*record_to
= NULL
;
7697 OSString
*swUUIDKey
= NULL
;
7698 uint32_t useIndex
= 0;
7701 return kIOReturnBadArgument
;
7704 return kIOReturnNotReady
;
7706 if (details
->eventType
== kIOPMEventTypeWakeDone
)
7708 if(!wakeDonePending
)
7709 return kIOReturnBadArgument
;
7712 IOLockLock(logLock
);
7714 if (details
->eventType
== kIOPMEventTypeWake
) {
7715 wakeDonePending
= true;
7716 } else if (details
->eventType
== kIOPMEventTypeWakeDone
) {
7717 wakeDonePending
= false;
7720 systemState
= details
->eventType
;
7722 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7724 // The entry immediately after the latest entry (and thus
7725 // immediately before the first entry) shall have a type 0.
7726 if (useIndex
+ 1 >= hdr
->sizeEntries
) {
7727 traceBuffer
[useIndex
+ 1].eventType
= 0;
7729 traceBuffer
[0].eventType
= 0;
7732 record_to
= &traceBuffer
[useIndex
];
7733 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7736 record_to
->eventType
= details
->eventType
;
7737 record_to
->eventReason
= details
->reason
;
7738 record_to
->eventResult
= details
->result
;
7739 pmEventTimeStamp(&record_to
->timestamp
);
7741 // If caller doesn't provide a UUID, we'll use the UUID that's posted
7742 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
7743 if (!details
->uuid
) {
7744 swUUIDKey
= OSDynamicCast(OSString
, owner
->copyProperty(kIOPMSleepWakeUUIDKey
));
7747 details
->uuid
= swUUIDKey
->getCStringNoCopy();
7751 strncpy(record_to
->uuid
, details
->uuid
, kMaxPMStringLength
);
7754 swUUIDKey
->release();
7756 numEventsLoggedThisPeriod
++;
7759 IOLockUnlock(logLock
);
7761 return kIOReturnSuccess
;
7765 //*********************************************************************************
7766 //*********************************************************************************
7767 //*********************************************************************************
7769 IOReturn
IOPMTimeline::recordDetailedPowerEvent( PMEventDetails
*details
)
7771 IOPMSystemEventRecord
*record_to
= NULL
;
7774 if (!details
->eventType
|| !details
->ownerName
)
7775 return kIOReturnBadArgument
;
7777 IOLockLock(logLock
);
7779 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7781 record_to
= (IOPMSystemEventRecord
*)&traceBuffer
[useIndex
];
7782 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7785 record_to
->eventType
= details
->eventType
;
7786 if (details
->ownerName
&& (strlen(details
->ownerName
) > 1)) {
7787 strlcpy( record_to
->ownerName
,
7789 sizeof(record_to
->ownerName
));
7792 record_to
->ownerDisambiguateID
= details
->ownerUnique
;
7794 if (details
->interestName
&& (strlen(details
->interestName
) > 1)) {
7795 strlcpy(record_to
->interestName
,
7796 details
->interestName
,
7797 sizeof(record_to
->interestName
));
7800 record_to
->oldState
= details
->oldState
;
7801 record_to
->newState
= details
->newState
;
7802 record_to
->eventResult
= details
->result
;
7803 record_to
->elapsedTimeUS
= details
->elapsedTimeUS
;
7804 pmEventTimeStamp(&record_to
->timestamp
);
7806 numEventsLoggedThisPeriod
++;
7809 IOLockUnlock(logLock
);
7810 return kIOReturnSuccess
;
7813 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
7814 return this->numEventsLoggedThisPeriod
;
7817 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount
) {
7818 this->numEventsLoggedThisPeriod
= newCount
;
7821 bool IOPMTimeline::isSleepCycleInProgress() {
7822 return this->sleepCycleInProgress
;
7825 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag
) {
7826 this->sleepCycleInProgress
= flag
;
7828 //*********************************************************************************
7829 //*********************************************************************************
7830 //*********************************************************************************
7832 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked
)
7834 size_t make_buf_size
= 0;
7836 make_buf_size
= sizeof(IOPMTraceBufferHeader
) + (newTracked
* sizeof(IOPMSystemEventRecord
));
7838 IOLockLock(logLock
);
7840 if (pmTraceMemoryDescriptor
) {
7841 pmTraceMemoryDescriptor
->release();
7842 pmTraceMemoryDescriptor
= NULL
;
7848 if (0 == newTracked
)
7850 IOLog("IOPMrootDomain -> erased buffer.\n");
7854 pmTraceMemoryDescriptor
= IOBufferMemoryDescriptor::withOptions(
7855 kIOMemoryKernelUserShared
| kIODirectionIn
| kIOMemoryMapperNone
,
7858 if (!pmTraceMemoryDescriptor
)
7860 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size
);
7864 pmTraceMemoryDescriptor
->prepare(kIODirectionIn
);
7866 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
7867 hdr
= (IOPMTraceBufferHeader
*)pmTraceMemoryDescriptor
->getBytesNoCopy();
7869 // Recorded events occupy the remaining bulk of the buffer
7870 traceBuffer
= (IOPMSystemEventRecord
*)((uint8_t *)hdr
+ sizeof(IOPMTraceBufferHeader
));
7872 bzero(hdr
, make_buf_size
);
7874 hdr
->sizeBytes
= make_buf_size
;
7875 hdr
->sizeEntries
= newTracked
;
7877 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size
, (unsigned int)(uintptr_t)traceBuffer
);
7880 IOLockUnlock(logLock
);
7883 //*********************************************************************************
7884 //*********************************************************************************
7885 //*********************************************************************************
7887 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits
)
7896 /* static helper to IOPMTimeline
7898 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index
, uint32_t limit
)
7908 inc_index
= (was_index
+1)%limit
;
7909 } while (!OSCompareAndSwap(was_index
, inc_index
, index
));
7915 // MARK: PMAssertionsTracker
7917 //*********************************************************************************
7918 //*********************************************************************************
7919 //*********************************************************************************
7920 // class PMAssertionsTracker Implementation
7922 #define kAssertUniqueIDStart 500
7924 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
7926 PMAssertionsTracker
*myself
;
7928 myself
= new PMAssertionsTracker
;
7932 myself
->owner
= rootDomain
;
7933 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
7934 myself
->assertionsArray
= OSArray::withCapacity(5);
7935 myself
->assertionsKernel
= 0;
7936 myself
->assertionsUser
= 0;
7937 myself
->assertionsCombined
= 0;
7938 myself
->assertionsArrayLock
= IOLockAlloc();
7939 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
7941 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
7949 * - Update assertionsKernel to reflect the state of all
7950 * assertions in the kernel.
7951 * - Update assertionsCombined to reflect both kernel & user space.
7953 void PMAssertionsTracker::tabulate(void)
7957 PMAssertStruct
*_a
= NULL
;
7960 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
7961 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
7965 assertionsKernel
= 0;
7966 assertionsCombined
= 0;
7968 if (!assertionsArray
)
7971 if ((count
= assertionsArray
->getCount()))
7973 for (i
=0; i
<count
; i
++)
7975 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7978 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7979 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
7980 assertionsKernel
|= _a
->assertionBits
;
7985 tabulateProducerCount
++;
7986 assertionsCombined
= assertionsKernel
| assertionsUser
;
7988 if ((assertionsKernel
!= oldKernel
) ||
7989 (assertionsCombined
!= oldCombined
))
7991 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
7995 void PMAssertionsTracker::publishProperties( void )
7997 OSArray
*assertionsSummary
= NULL
;
7999 if (tabulateConsumerCount
!= tabulateProducerCount
)
8001 IOLockLock(assertionsArrayLock
);
8003 tabulateConsumerCount
= tabulateProducerCount
;
8005 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8007 assertionsSummary
= copyAssertionsArray();
8008 if (assertionsSummary
)
8010 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
8011 assertionsSummary
->release();
8015 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
8018 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8020 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
8022 IOLockUnlock(assertionsArrayLock
);
8026 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
8028 PMAssertStruct
*_a
= NULL
;
8035 && (count
= assertionsArray
->getCount()))
8037 for (i
=0; i
<count
; i
++)
8039 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8042 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8043 if (_a
&& (_id
== _a
->id
)) {
8060 /* PMAssertionsTracker::handleCreateAssertion
8061 * Perform assertion work on the PM workloop. Do not call directly.
8063 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
8069 IOLockLock(assertionsArrayLock
);
8070 assertionsArray
->setObject(newAssertion
);
8071 IOLockUnlock(assertionsArrayLock
);
8072 newAssertion
->release();
8076 return kIOReturnSuccess
;
8079 /* PMAssertionsTracker::createAssertion
8080 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8083 IOReturn
PMAssertionsTracker::createAssertion(
8084 IOPMDriverAssertionType which
,
8085 IOPMDriverAssertionLevel level
,
8086 IOService
*serviceID
,
8087 const char *whoItIs
,
8088 IOPMDriverAssertionID
*outID
)
8090 OSData
*dataStore
= NULL
;
8091 PMAssertStruct track
;
8093 // Warning: trillions and trillions of created assertions may overflow the unique ID.
8094 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
8095 track
.level
= level
;
8096 track
.assertionBits
= which
;
8097 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
) : 0;
8098 track
.ownerService
= serviceID
;
8099 track
.modifiedTime
= 0;
8100 pmEventTimeStamp(&track
.createdTime
);
8102 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
8105 if (track
.ownerString
)
8106 track
.ownerString
->release();
8107 return kIOReturnNoMemory
;
8112 if (owner
&& owner
->pmPowerStateQueue
) {
8113 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
8116 return kIOReturnSuccess
;
8119 /* PMAssertionsTracker::handleReleaseAssertion
8120 * Runs in PM workloop. Do not call directly.
8122 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
8123 IOPMDriverAssertionID _id
)
8128 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
8131 return kIOReturnNotFound
;
8133 IOLockLock(assertionsArrayLock
);
8134 if (assertStruct
->ownerString
)
8135 assertStruct
->ownerString
->release();
8137 assertionsArray
->removeObject(index
);
8138 IOLockUnlock(assertionsArrayLock
);
8141 return kIOReturnSuccess
;
8144 /* PMAssertionsTracker::releaseAssertion
8145 * Releases an assertion and affects system behavior if appropiate.
8146 * Actual work happens on PM workloop.
8148 IOReturn
PMAssertionsTracker::releaseAssertion(
8149 IOPMDriverAssertionID _id
)
8151 if (owner
&& owner
->pmPowerStateQueue
) {
8152 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
8154 return kIOReturnSuccess
;
8157 /* PMAssertionsTracker::handleSetAssertionLevel
8158 * Runs in PM workloop. Do not call directly.
8160 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
8161 IOPMDriverAssertionID _id
,
8162 IOPMDriverAssertionLevel _level
)
8164 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
8168 if (!assertStruct
) {
8169 return kIOReturnNotFound
;
8172 IOLockLock(assertionsArrayLock
);
8173 pmEventTimeStamp(&assertStruct
->modifiedTime
);
8174 assertStruct
->level
= _level
;
8175 IOLockUnlock(assertionsArrayLock
);
8178 return kIOReturnSuccess
;
8181 /* PMAssertionsTracker::setAssertionLevel
8183 IOReturn
PMAssertionsTracker::setAssertionLevel(
8184 IOPMDriverAssertionID _id
,
8185 IOPMDriverAssertionLevel _level
)
8187 if (owner
&& owner
->pmPowerStateQueue
) {
8188 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
8189 (void *)_level
, _id
);
8192 return kIOReturnSuccess
;
8195 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
8197 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
8201 if (new_user_levels
!= assertionsUser
)
8203 assertionsUser
= new_user_levels
;
8204 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
8208 return kIOReturnSuccess
;
8211 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
8212 IOPMDriverAssertionType new_user_levels
)
8214 if (gIOPMWorkLoop
) {
8215 gIOPMWorkLoop
->runAction(
8216 OSMemberFunctionCast(
8219 &PMAssertionsTracker::handleSetUserAssertionLevels
),
8221 (void *) &new_user_levels
, 0, 0, 0);
8224 return kIOReturnSuccess
;
8228 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
8232 OSArray
*outArray
= NULL
;
8234 if (!assertionsArray
||
8235 (0 == (count
= assertionsArray
->getCount())) ||
8236 (NULL
== (outArray
= OSArray::withCapacity(count
))))
8241 for (i
=0; i
<count
; i
++)
8243 PMAssertStruct
*_a
= NULL
;
8245 OSDictionary
*details
= NULL
;
8247 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8248 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
8250 OSNumber
*_n
= NULL
;
8252 details
= OSDictionary::withCapacity(7);
8256 outArray
->setObject(details
);
8259 _n
= OSNumber::withNumber(_a
->id
, 64);
8261 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
8264 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
8266 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
8269 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
8271 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
8274 _n
= OSNumber::withNumber((uintptr_t)_a
->ownerService
, 64);
8276 details
->setObject(kIOPMDriverAssertionOwnerServiceKey
, _n
);
8279 _n
= OSNumber::withNumber(_a
->level
, 64);
8281 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
8284 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
8286 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
8290 if (_a
->ownerString
) {
8291 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
8300 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
8302 return assertionsCombined
;
8305 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
8306 IOPMDriverAssertionType type
)
8308 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
8310 return kIOPMDriverAssertionLevelOn
;
8312 return kIOPMDriverAssertionLevelOff
;
8316 //*********************************************************************************
8317 //*********************************************************************************
8318 //*********************************************************************************
8321 static void pmEventTimeStamp(uint64_t *recordTS
)
8329 // We assume tsec fits into 32 bits; 32 bits holds enough
8330 // seconds for 136 years since the epoch in 1970.
8331 clock_get_calendar_microtime(&tsec
, &tusec
);
8334 // Pack the sec & microsec calendar time into a uint64_t, for fun.
8336 *recordTS
|= (uint32_t)tusec
;
8337 *recordTS
|= ((uint64_t)tsec
<< 32);
8343 // MARK: IORootParent
8345 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8347 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
8349 // The reason that root domain needs a root parent is to facilitate demand
8350 // sleep, since a power change from the root parent cannot be vetoed.
8352 // The above statement is no longer true since root domain now performs
8353 // demand sleep using overrides. But root parent remains to avoid changing
8354 // the power tree stacking. Root parent is parked at the max power state.
8357 static IOPMPowerState patriarchPowerStates
[2] =
8359 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
8360 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
8363 void IORootParent::initialize( void )
8367 bool IORootParent::start( IOService
* nub
)
8369 IOService::start(nub
);
8370 attachToParent( getRegistryRoot(), gIOPowerPlane
);
8372 registerPowerDriver(this, patriarchPowerStates
, 2);
8377 void IORootParent::shutDownSystem( void )
8381 void IORootParent::restartSystem( void )
8385 void IORootParent::sleepSystem( void )
8389 void IORootParent::dozeSystem( void )
8393 void IORootParent::sleepToDoze( void )
8397 void IORootParent::wakeSystem( void )
8401 OSObject
* IORootParent::copyProperty( const char * aKey
) const
8403 return (IOService::copyProperty(aKey
));