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 <sys/syslog.h>
51 #include <sys/sysctl.h>
53 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
54 #include "IOServicePMPrivate.h"
57 #include <mach/shared_region.h>
60 #if defined(__i386__) || defined(__x86_64__)
62 #include "IOPMrootDomainInternal.h"
66 #define kIOPMrootDomainClass "IOPMrootDomain"
67 #define LOG_PREFIX "PMRD: "
70 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
73 do { kprintf(LOG_PREFIX x); } while (false)
75 #define DLOG(x...) do { \
76 if (kIOLogPMRootDomain & gIOKitDebug) \
77 kprintf(LOG_PREFIX x); } while (false)
81 #define CHECK_THREAD_CONTEXT
82 #ifdef CHECK_THREAD_CONTEXT
83 static IOWorkLoop
* gIOPMWorkLoop
= 0;
84 #define ASSERT_GATED() \
86 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
87 panic("RootDomain: not inside PM gate"); \
91 #define ASSERT_GATED()
92 #endif /* CHECK_THREAD_CONTEXT */
95 (((_pendingCapability & (c)) == 0) && \
96 ((_currentCapability & (c)) != 0))
99 (((_currentCapability & (c)) == 0) && \
100 ((_pendingCapability & (c)) != 0))
102 #define CAP_CHANGE(c) \
103 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
105 #define CAP_CURRENT(c) \
106 ((_currentCapability & (c)) != 0)
108 #define CAP_HIGHEST(c) \
109 ((_highestCapability & (c)) != 0)
111 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 0
113 // Event types for IOPMPowerStateQueue::submitPowerEvent()
115 kPowerEventFeatureChanged
= 1, // 1
116 kPowerEventReceivedPowerNotification
, // 2
117 kPowerEventSystemBootCompleted
, // 3
118 kPowerEventSystemShutdown
, // 4
119 kPowerEventUserDisabledSleep
, // 5
120 kPowerEventRegisterSystemCapabilityClient
, // 6
121 kPowerEventRegisterKernelCapabilityClient
, // 7
122 kPowerEventPolicyStimulus
, // 8
123 kPowerEventAssertionCreate
, // 9
124 kPowerEventAssertionRelease
, // 10
125 kPowerEventAssertionSetLevel
, // 11
126 kPowerEventQueueSleepWakeUUID
, // 12
127 kPowerEventPublishSleepWakeUUID
// 13
130 // For evaluatePolicy()
131 // List of stimuli that affects the root domain policy.
133 kStimulusDisplayWranglerSleep
, // 0
134 kStimulusDisplayWranglerWake
, // 1
135 kStimulusAggressivenessChanged
, // 2
136 kStimulusDemandSystemSleep
, // 3
137 kStimulusAllowSystemSleepChanged
, // 4
138 kStimulusDarkWakeActivityTickle
, // 5
139 kStimulusDarkWakeEntry
, // 6
140 kStimulusDarkWakeReentry
, // 7
141 kStimulusDarkWakeEvaluate
// 8
145 IOReturn
OSKextSystemSleepOrWake( UInt32
);
148 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
149 static void notifySystemShutdown( IOService
* root
, unsigned long event
);
150 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
151 static void pmEventTimeStamp(uint64_t *recordTS
);
153 // "IOPMSetSleepSupported" callPlatformFunction name
154 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
155 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
157 #define kIOSleepSupportedKey "IOSleepSupported"
158 #define kIOPMSystemCapabilitiesKey "System Capabilities"
160 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
161 | kIOPMSupportedOnBatt \
162 | kIOPMSupportedOnUPS)
166 // not idle around autowake time, secs
167 kAutoWakePreWindow
= 45,
168 kAutoWakePostWindow
= 15
171 #define kLocalEvalClamshellCommand (1 << 15)
181 #define ON_POWER kIOPMPowerOn
182 #define RESTART_POWER kIOPMRestart
183 #define SLEEP_POWER kIOPMAuxPowerOn
185 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
187 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
188 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
189 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
190 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
193 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
194 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
195 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
196 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
197 #define kIOPMRootDomainWakeTypeUser "User"
198 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
199 #define kIOPMRootDomainWakeTypeNetwork "Network"
201 // Special interest that entitles the interested client from receiving
202 // all system messages. Only used by powerd.
204 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
209 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
210 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
212 #define kAggressivesMinValue 1
215 kAggressivesStateBusy
= 0x01,
216 kAggressivesStateQuickSpindown
= 0x02
219 struct AggressivesRecord
{
225 struct AggressivesRequest
{
231 AggressivesRecord record
;
236 kAggressivesRequestTypeService
= 1,
237 kAggressivesRequestTypeRecord
241 kAggressivesOptionSynchronous
= 0x00000001,
242 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
243 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
244 kAggressivesOptionQuickSpindownMask
= 0x00000300
248 kAggressivesRecordFlagModified
= 0x00000001,
249 kAggressivesRecordFlagMinValue
= 0x00000002
254 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
255 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
256 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
257 kDarkWakeFlagHIDTickleMask
= 0x03,
258 kDarkWakeFlagIgnoreDiskIOInDark
= 0x04, // ignore disk idle in DW
259 kDarkWakeFlagIgnoreDiskIOAlways
= 0x08, // always ignore disk idle
260 kDarkWakeFlagIgnoreDiskIOMask
= 0x0C,
261 kDarkWakeFlagAlarmIsDark
= 0x0100
264 static IOPMrootDomain
* gRootDomain
;
265 static IONotifier
* gSysPowerDownNotifier
= 0;
266 static UInt32 gSleepOrShutdownPending
= 0;
267 static UInt32 gWillShutdown
= 0;
268 static UInt32 gPagingOff
= 0;
269 static UInt32 gSleepWakeUUIDIsSet
= false;
270 static uint32_t gAggressivesState
= 0;
271 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
272 static bool gRAMDiskImageBoot
= false;
274 struct timeval gIOLastSleepTime
;
275 struct timeval gIOLastWakeTime
;
277 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
278 #define kCPUUnknownIndex 9999999
285 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
286 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
287 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
289 #define kBadPMFeatureID 0
293 * Opaque handle passed to clients of registerPMSettingController()
295 class PMSettingHandle
: public OSObject
297 OSDeclareFinalStructors( PMSettingHandle
)
298 friend class PMSettingObject
;
301 PMSettingObject
*pmso
;
307 * Internal object to track each PM setting controller
309 class PMSettingObject
: public OSObject
311 OSDeclareFinalStructors( PMSettingObject
)
312 friend class IOPMrootDomain
;
315 queue_head_t calloutQueue
;
317 IOPMrootDomain
*parent
;
318 PMSettingHandle
*pmsh
;
319 IOPMSettingControllerCallback func
;
322 uint32_t *publishedFeatureID
;
323 uint32_t settingCount
;
329 static PMSettingObject
*pmSettingObject(
330 IOPMrootDomain
*parent_arg
,
331 IOPMSettingControllerCallback handler_arg
,
332 OSObject
*target_arg
,
333 uintptr_t refcon_arg
,
334 uint32_t supportedPowerSources
,
335 const OSSymbol
*settings
[],
336 OSObject
**handle_obj
);
338 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
339 void clientHandleFreed(void);
342 struct PMSettingCallEntry
{
347 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
348 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
349 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
350 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
352 //*********************************************************************************
353 //*********************************************************************************
354 //*********************************************************************************
356 /* @class IOPMTimeline
357 * @astract Tracks & records PM activity.
358 * @discussion Intended for use only as a helper-class to IOPMrootDomain.
359 * Do not subclass or directly invoke iOPMTimeline
361 class IOPMTimeline
: public OSObject
363 OSDeclareDefaultStructors( IOPMTimeline
);
366 static IOPMTimeline
* timeline(IOPMrootDomain
*root_domain
);
368 bool setProperties(OSDictionary
*d
);
369 OSDictionary
*copyInfoDictionary(void);
371 IOReturn
recordSystemPowerEvent( PMEventDetails
*details
);
373 IOReturn
recordDetailedPowerEvent( PMEventDetails
*details
);
375 IOMemoryDescriptor
*getPMTraceMemoryDescriptor();
377 uint32_t getNumEventsLoggedThisPeriod();
378 void setNumEventsLoggedThisPeriod(uint32_t newCount
);
379 bool isSleepCycleInProgress();
380 void setSleepCycleInProgressFlag(bool flag
);
385 void setEventsTrackedCount(uint32_t newTracked
);
386 void setEventsRecordingLevel(uint32_t eventsTrackedBits
);
387 static uint32_t _atomicIndexIncrement(uint32_t *index
, uint32_t limit
);
390 kPMTimelineRecordTardyDrivers
= 1 << 0,
391 kPMTmielineRecordSystemEvents
= 1 << 1,
392 kPMTimelineRecordAllDrivers
= 1 << 2,
393 kPMTimelineRecordOff
= 0,
394 kPMTimelineRecordDefault
= 3,
395 kPMTimelineRecordDebug
= 7
398 // eventsRecordingLevel is a bitfield defining which PM driver events will get logged
399 // into the PM buffer.
400 uint32_t eventsRecordingLevel
;
402 // pmTraceMemoryDescriptor represents the memory block that IOPMTimeLine records PM trace points into.
403 IOBufferMemoryDescriptor
*pmTraceMemoryDescriptor
;
405 // Pointer to starting address in pmTraceMemoryDescriptor
406 IOPMSystemEventRecord
*traceBuffer
;
407 IOPMTraceBufferHeader
*hdr
;
409 uint16_t systemState
;
412 IOPMrootDomain
*owner
;
414 uint32_t numEventsLoggedThisPeriod
;
415 bool sleepCycleInProgress
;
418 OSDefineMetaClassAndStructors( IOPMTimeline
, OSObject
)
422 * Internal helper object for logging trace points to RTC
423 * IOPMrootDomain and only IOPMrootDomain should instantiate
424 * exactly one of these.
427 typedef void (*IOPMTracePointHandler
)(
428 void * target
, uint32_t code
, uint32_t data
);
430 class PMTraceWorker
: public OSObject
432 OSDeclareDefaultStructors(PMTraceWorker
)
434 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
436 static PMTraceWorker
*tracer( IOPMrootDomain
* );
437 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
438 void tracePoint(uint8_t phase
);
439 void tracePoint(uint8_t phase
, uint8_t data8
);
440 void traceDetail(uint32_t detail
);
441 void traceLoginWindowPhase(uint8_t phase
);
442 int recordTopLevelPCIDevice(IOService
*);
443 void RTC_TRACE(void);
444 virtual bool serialize(OSSerialize
*s
) const;
446 IOPMTracePointHandler tracePointHandler
;
447 void * tracePointTarget
;
449 IOPMrootDomain
*owner
;
450 IOLock
*pciMappingLock
;
451 OSArray
*pciDeviceBitMappings
;
453 uint8_t addedToRegistry
;
455 uint8_t loginWindowPhase
;
457 uint32_t traceData32
;
461 * PMAssertionsTracker
462 * Tracks kernel and user space PM assertions
464 class PMAssertionsTracker
: public OSObject
466 OSDeclareFinalStructors(PMAssertionsTracker
)
468 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
470 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
471 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
472 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
473 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
475 OSArray
*copyAssertionsArray(void);
476 IOPMDriverAssertionType
getActivatedAssertions(void);
477 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
479 IOReturn
handleCreateAssertion(OSData
*);
480 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
481 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
482 IOReturn
handleSetUserAssertionLevels(void * arg0
);
483 void publishProperties(void);
487 IOPMDriverAssertionID id
;
488 IOPMDriverAssertionType assertionBits
;
489 uint64_t createdTime
;
490 uint64_t modifiedTime
;
491 const OSSymbol
*ownerString
;
492 IOService
*ownerService
;
493 IOPMDriverAssertionLevel level
;
496 uint32_t tabulateProducerCount
;
497 uint32_t tabulateConsumerCount
;
499 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
502 IOPMrootDomain
*owner
;
503 OSArray
*assertionsArray
;
504 IOLock
*assertionsArrayLock
;
505 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
506 IOPMDriverAssertionType assertionsKernel
;
507 IOPMDriverAssertionType assertionsUser
;
508 IOPMDriverAssertionType assertionsCombined
;
511 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
515 * Internal helper object for Shutdown/Restart notifications.
517 #define kPMHaltMaxWorkers 8
518 #define kPMHaltTimeoutMS 100
520 class PMHaltWorker
: public OSObject
522 OSDeclareFinalStructors( PMHaltWorker
)
525 IOService
* service
; // service being worked on
526 AbsoluteTime startTime
; // time when work started
527 int depth
; // work on nubs at this PM-tree depth
528 int visits
; // number of nodes visited (debug)
530 bool timeout
; // service took too long
532 static PMHaltWorker
* worker( void );
533 static void main( void * arg
, wait_result_t waitResult
);
534 static void work( PMHaltWorker
* me
);
535 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
536 virtual void free( void );
539 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
542 #define super IOService
543 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
545 static void IOPMRootDomainWillShutdown(void)
547 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
549 OSKext::willShutdown();
550 for (int i
= 0; i
< 100; i
++)
552 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
560 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
562 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
565 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
567 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
570 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
572 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
575 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
577 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
580 IOReturn
rootDomainRestart ( void )
582 return gRootDomain
->restartSystem();
585 IOReturn
rootDomainShutdown ( void )
587 return gRootDomain
->shutdownSystem();
590 void IOSystemShutdownNotification(void)
592 IOPMRootDomainWillShutdown();
593 if (OSCompareAndSwap(0, 1, &gPagingOff
))
596 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
601 int sync_internal(void);
605 A device is always in the highest power state which satisfies its driver,
606 its policy-maker, and any power children it has, but within the constraint
607 of the power state provided by its parent. The driver expresses its desire by
608 calling changePowerStateTo(), the policy-maker expresses its desire by calling
609 changePowerStateToPriv(), and the children express their desires by calling
610 requestPowerDomainState().
612 The Root Power Domain owns the policy for idle and demand sleep for the system.
613 It is a power-managed IOService just like the others in the system.
614 It implements several power states which map to what we see as Sleep and On.
616 The sleep policy is as follows:
617 1. Sleep is prevented if the case is open so that nobody will think the machine
618 is off and plug/unplug cards.
619 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
620 3. System cannot Sleep if some object in the tree is in a power state marked
621 kIOPMPreventSystemSleep.
623 These three conditions are enforced using the "driver clamp" by calling
624 changePowerStateTo(). For example, if the case is opened,
625 changePowerStateTo(ON_STATE) is called to hold the system on regardless
626 of the desires of the children of the root or the state of the other clamp.
628 Demand Sleep is initiated by pressing the front panel power button, closing
629 the clamshell, or selecting the menu item. In this case the root's parent
630 actually initiates the power state change so that the root domain has no
631 choice and does not give applications the opportunity to veto the change.
633 Idle Sleep occurs if no objects in the tree are in a state marked
634 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
635 the root on, so it sets the "policy-maker clamp" by calling
636 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
637 This timer is set for the difference between the sleep timeout slider and the
638 display dim timeout slider. When the timer expires, it releases its clamp and
639 now nothing is holding it awake, so it falls asleep.
641 Demand sleep is prevented when the system is booting. When preferences are
642 transmitted by the loginwindow at the end of boot, a flag is cleared,
643 and this allows subsequent Demand Sleep.
646 //******************************************************************************
648 IOPMrootDomain
* IOPMrootDomain::construct( void )
650 IOPMrootDomain
*root
;
652 root
= new IOPMrootDomain
;
659 //******************************************************************************
661 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
663 IOService
* rootDomain
= (IOService
*) p0
;
664 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
665 uint32_t powerState
= rootDomain
->getPowerState();
667 DLOG("disk_sync_callout ps=%u\n", powerState
);
669 if (ON_STATE
== powerState
)
672 IOHibernateSystemSleep();
679 IOHibernateSystemPostWake();
683 rootDomain
->allowPowerChange(notifyRef
);
684 DLOG("disk_sync_callout finish\n");
687 //******************************************************************************
689 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
691 AbsoluteTime endTime
;
694 clock_get_uptime(&endTime
);
695 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
697 SUB_ABSOLUTETIME(&endTime
, startTime
);
698 absolutetime_to_nanoseconds(endTime
, &nano
);
701 return (UInt32
)(nano
/ 1000000ULL);
704 //******************************************************************************
707 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
709 struct timeval
*swt
= (struct timeval
*)arg1
;
710 struct proc
*p
= req
->p
;
713 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
714 } else if(proc_is64bit(p
)) {
715 struct user64_timeval t
;
716 t
.tv_sec
= swt
->tv_sec
;
717 t
.tv_usec
= swt
->tv_usec
;
718 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
720 struct user32_timeval t
;
721 t
.tv_sec
= swt
->tv_sec
;
722 t
.tv_usec
= swt
->tv_usec
;
723 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
727 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
728 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
729 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
731 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
732 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
733 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
738 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
740 int new_value
, changed
;
741 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
743 if (!gWillShutdown
&& (new_value
== 1)) {
744 IOPMRootDomainWillShutdown();
751 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
752 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
753 0, 0, sysctl_willshutdown
, "I", "");
758 sysctl_progressmeterenable
759 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
762 int new_value
, changed
;
764 error
= sysctl_io_number(req
, vc_progress_meter_enable
, sizeof(int), &new_value
, &changed
);
767 vc_enable_progressmeter(new_value
);
774 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
777 int new_value
, changed
;
779 error
= sysctl_io_number(req
, vc_progress_meter_value
, sizeof(int), &new_value
, &changed
);
782 vc_set_progressmeter(new_value
);
787 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
788 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
789 0, 0, sysctl_progressmeterenable
, "I", "");
791 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
792 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
793 0, 0, sysctl_progressmeter
, "I", "");
797 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
799 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
800 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
801 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
802 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
803 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
805 //******************************************************************************
808 //******************************************************************************
810 #define kRootDomainSettingsCount 17
812 bool IOPMrootDomain::start( IOService
* nub
)
814 OSIterator
*psIterator
;
815 OSDictionary
*tmpDict
;
816 IORootParent
* patriarch
;
821 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
822 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
823 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
824 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
825 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
827 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
828 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
829 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
831 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
832 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
834 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
836 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
837 gIOPMSettingAutoWakeSecondsKey
,
838 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
839 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
),
840 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
841 gIOPMSettingDebugWakeRelativeKey
,
842 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
843 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
844 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
845 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
846 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
847 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
848 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
849 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
850 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
851 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
852 gIOPMSettingSilentRunningKey
855 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
857 IORegistryEntry
* chosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
860 if (chosenEntry
->getProperty("boot-ramdmg-size") &&
861 chosenEntry
->getProperty("boot-ramdmg-extents"))
863 gRAMDiskImageBoot
= true;
865 chosenEntry
->release();
868 queue_init(&aggressivesQueue
);
869 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
870 aggressivesData
= OSData::withCapacity(
871 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
873 featuresDictLock
= IOLockAlloc();
874 settingsCtrlLock
= IOLockAlloc();
875 setPMRootDomain(this);
877 extraSleepTimer
= thread_call_allocate(
878 idleSleepTimerExpired
,
879 (thread_call_param_t
) this);
881 diskSyncCalloutEntry
= thread_call_allocate(
883 (thread_call_param_t
) this);
885 setProperty(kIOSleepSupportedKey
, true);
887 bzero(&pmStats
, sizeof(pmStats
));
889 pmTracer
= PMTraceWorker::tracer(this);
891 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
893 userDisabledAllSleep
= false;
894 systemBooting
= true;
896 idleSleepTimerPending
= false;
898 clamshellClosed
= false;
899 clamshellExists
= false;
900 clamshellDisabled
= true;
901 acAdaptorConnected
= true;
903 // Set the default system capabilities at boot.
904 _currentCapability
= kIOPMSystemCapabilityCPU
|
905 kIOPMSystemCapabilityGraphics
|
906 kIOPMSystemCapabilityAudio
|
907 kIOPMSystemCapabilityNetwork
;
909 _pendingCapability
= _currentCapability
;
910 _desiredCapability
= _currentCapability
;
911 _highestCapability
= _currentCapability
;
912 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
914 queuedSleepWakeUUIDString
= NULL
;
915 pmStatsAppResponses
= OSArray::withCapacity(5);
916 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
917 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
918 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
919 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
920 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
922 idxPMCPUClamshell
= kCPUUnknownIndex
;
923 idxPMCPULimitedPower
= kCPUUnknownIndex
;
925 tmpDict
= OSDictionary::withCapacity(1);
926 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
929 settingsCallbacks
= OSDictionary::withCapacity(1);
931 // Create a list of the valid PM settings that we'll relay to
932 // interested clients in setProperties() => setPMSetting()
933 allowedPMSettings
= OSArray::withObjects(
934 (const OSObject
**)settingsArr
,
935 kRootDomainSettingsCount
,
938 // List of PM settings that should not automatically publish itself
939 // as a feature when registered by a listener.
940 noPublishPMSettings
= OSArray::withObjects(
941 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
943 fPMSettingsDict
= OSDictionary::withCapacity(5);
945 PMinit(); // creates gIOPMWorkLoop
947 // Create IOPMPowerStateQueue used to queue external power
948 // events, and to handle those events on the PM work loop.
949 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
950 this, OSMemberFunctionCast(IOEventSource::Action
, this,
951 &IOPMrootDomain::dispatchPowerEvent
));
952 getPMworkloop()->addEventSource(pmPowerStateQueue
);
953 #ifdef CHECK_THREAD_CONTEXT
954 gIOPMWorkLoop
= getPMworkloop();
957 // create our power parent
958 patriarch
= new IORootParent
;
960 patriarch
->attach(this);
961 patriarch
->start(this);
962 patriarch
->addPowerChild(this);
964 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
965 changePowerStateToPriv(ON_STATE
);
967 if (gIOKitDebug
& (kIOLogDriverPower1
| kIOLogDriverPower2
))
969 // Setup our PM logging & recording code
970 timeline
= IOPMTimeline::timeline(this);
972 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
976 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
982 // install power change handler
983 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
986 // Register for a notification when IODisplayWrangler is published
987 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
989 _displayWranglerNotifier
= addMatchingNotification(
990 gIOPublishNotification
, tmpDict
,
991 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
997 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
998 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
999 ucClassName
->release();
1001 // IOBacklightDisplay can take a long time to load at boot, or it may
1002 // not load at all if you're booting with clamshell closed. We publish
1003 // 'DisplayDims' here redundantly to get it published early and at all.
1004 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
1005 if( psIterator
&& psIterator
->getNextObject() )
1007 // There's at least one battery on the system, so we publish
1008 // 'DisplayDims' support for the LCD.
1009 publishFeature("DisplayDims");
1012 psIterator
->release();
1015 sysctl_register_oid(&sysctl__kern_sleeptime
);
1016 sysctl_register_oid(&sysctl__kern_waketime
);
1017 sysctl_register_oid(&sysctl__kern_willshutdown
);
1018 #if !CONFIG_EMBEDDED
1019 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1020 sysctl_register_oid(&sysctl__kern_progressmeter
);
1021 #endif /* !CONFIG_EMBEDDED */
1024 IOHibernateSystemInit(this);
1027 registerService(); // let clients find us
1032 //******************************************************************************
1035 // Receive a setProperty call
1036 // The "System Boot" property means the system is completely booted.
1037 //******************************************************************************
1039 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1041 IOReturn return_value
= kIOReturnSuccess
;
1042 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1050 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1051 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1052 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1053 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1054 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1055 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1056 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1057 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1058 const OSSymbol
*loginwindow_tracepoint_string
= OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
1059 const OSSymbol
*pmTimelineLogging_string
= OSSymbol::withCString(kIOPMTimelineDictionaryKey
);
1061 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1062 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1063 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1064 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1069 return_value
= kIOReturnBadArgument
;
1073 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(publish_simulated_battery_string
))))
1075 publishResource(publish_simulated_battery_string
, kOSBooleanTrue
);
1078 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(idle_seconds_string
))))
1080 setProperty(idle_seconds_string
, n
);
1081 idleSeconds
= n
->unsigned32BitValue();
1084 if (boot_complete_string
&& dict
->getObject(boot_complete_string
))
1086 pmPowerStateQueue
->submitPowerEvent( kPowerEventSystemBootCompleted
);
1089 if( battery_warning_disabled_string
&& dict
->getObject(battery_warning_disabled_string
))
1091 setProperty( battery_warning_disabled_string
, dict
->getObject(battery_warning_disabled_string
));
1094 if (pmTimelineLogging_string
&& (d
= OSDynamicCast(OSDictionary
, dict
->getObject(pmTimelineLogging_string
))))
1096 if (timeline
&& timeline
->setProperties(d
))
1098 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
1100 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
1106 if( sys_shutdown_string
&& (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sys_shutdown_string
))))
1108 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1111 if( stall_halt_string
&& (b
= OSDynamicCast(OSBoolean
, dict
->getObject(stall_halt_string
))) )
1113 setProperty(stall_halt_string
, b
);
1117 if ( hibernatemode_string
1118 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatemode_string
))))
1120 setProperty(hibernatemode_string
, n
);
1122 if ( hibernatefreeratio_string
1123 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreeratio_string
))))
1125 setProperty(hibernatefreeratio_string
, n
);
1127 if ( hibernatefreetime_string
1128 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreetime_string
))))
1130 setProperty(hibernatefreetime_string
, n
);
1133 if ( hibernatefile_string
1134 && (str
= OSDynamicCast(OSString
, dict
->getObject(hibernatefile_string
))))
1136 setProperty(hibernatefile_string
, str
);
1140 if( sleepdisabled_string
1141 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sleepdisabled_string
))) )
1143 setProperty(sleepdisabled_string
, b
);
1144 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1146 if (ondeck_sleepwake_uuid_string
1147 && (obj
= dict
->getObject(ondeck_sleepwake_uuid_string
)))
1149 if(pmPowerStateQueue
) {
1151 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1156 if (loginwindow_tracepoint_string
1157 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(loginwindow_tracepoint_string
)))
1160 pmTracer
->traceLoginWindowPhase( n
->unsigned8BitValue() );
1163 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(kIOPMDeepSleepEnabledKey
))))
1165 setProperty(kIOPMDeepSleepEnabledKey
, b
);
1167 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(kIOPMDeepSleepDelayKey
))))
1169 setProperty(kIOPMDeepSleepDelayKey
, n
);
1171 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(kIOPMDestroyFVKeyOnStandbyKey
))))
1173 setProperty(kIOPMDestroyFVKeyOnStandbyKey
, b
);
1175 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(kIOPMAutoPowerOffEnabledKey
))))
1177 setProperty(kIOPMAutoPowerOffEnabledKey
, b
);
1179 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(kIOPMAutoPowerOffDelayKey
))))
1181 setProperty(kIOPMAutoPowerOffDelayKey
, n
);
1184 // Relay our allowed PM settings onto our registered PM clients
1185 for(i
= 0; i
< allowedPMSettings
->getCount(); i
++) {
1187 type
= (OSSymbol
*)allowedPMSettings
->getObject(i
);
1190 obj
= dict
->getObject(type
);
1193 if ((gIOPMSettingAutoWakeSecondsKey
== type
) && ((n
= OSDynamicCast(OSNumber
, obj
))))
1195 UInt32 rsecs
= n
->unsigned32BitValue();
1197 autoWakeStart
= autoWakeEnd
= 0;
1200 AbsoluteTime deadline
;
1201 clock_interval_to_deadline(rsecs
+ kAutoWakePostWindow
, kSecondScale
, &deadline
);
1202 autoWakeEnd
= AbsoluteTime_to_scalar(&deadline
);
1203 if (rsecs
> kAutoWakePreWindow
)
1204 rsecs
-= kAutoWakePreWindow
;
1207 clock_interval_to_deadline(rsecs
, kSecondScale
, &deadline
);
1208 autoWakeStart
= AbsoluteTime_to_scalar(&deadline
);
1211 if (gIOPMSettingDebugWakeRelativeKey
== type
)
1213 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1214 _debugWakeSeconds
= n
->unsigned32BitValue();
1216 _debugWakeSeconds
= 0;
1219 return_value
= setPMSetting(type
, obj
);
1221 if(kIOReturnSuccess
!= return_value
) goto exit
;
1225 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1226 if(boot_complete_string
) boot_complete_string
->release();
1227 if(sys_shutdown_string
) sys_shutdown_string
->release();
1228 if(stall_halt_string
) stall_halt_string
->release();
1229 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1230 if(idle_seconds_string
) idle_seconds_string
->release();
1231 if(sleepdisabled_string
) sleepdisabled_string
->release();
1232 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1233 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1234 if(pmTimelineLogging_string
) pmTimelineLogging_string
->release();
1236 if(hibernatemode_string
) hibernatemode_string
->release();
1237 if(hibernatefile_string
) hibernatefile_string
->release();
1238 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1239 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1241 return return_value
;
1245 // MARK: Aggressiveness
1247 //******************************************************************************
1248 // setAggressiveness
1250 // Override IOService::setAggressiveness()
1251 //******************************************************************************
1253 IOReturn
IOPMrootDomain::setAggressiveness(
1255 unsigned long value
)
1257 return setAggressiveness( type
, value
, 0 );
1261 * Private setAggressiveness() with an internal options argument.
1263 IOReturn
IOPMrootDomain::setAggressiveness(
1265 unsigned long value
,
1266 IOOptionBits options
)
1268 AggressivesRequest
* entry
;
1269 AggressivesRequest
* request
;
1272 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1273 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1275 request
= IONew(AggressivesRequest
, 1);
1277 return kIOReturnNoMemory
;
1279 memset(request
, 0, sizeof(*request
));
1280 request
->options
= options
;
1281 request
->dataType
= kAggressivesRequestTypeRecord
;
1282 request
->data
.record
.type
= (uint32_t) type
;
1283 request
->data
.record
.value
= (uint32_t) value
;
1287 // Update disk quick spindown flag used by getAggressiveness().
1288 // Never merge requests with quick spindown flags set.
1290 if (options
& kAggressivesOptionQuickSpindownEnable
)
1291 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1292 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1293 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1296 // Coalesce requests with identical aggressives types.
1297 // Deal with callers that calls us too "aggressively".
1299 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1301 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1302 (entry
->data
.record
.type
== type
) &&
1303 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1305 entry
->data
.record
.value
= value
;
1314 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1317 AGGRESSIVES_UNLOCK();
1320 IODelete(request
, AggressivesRequest
, 1);
1322 if (options
& kAggressivesOptionSynchronous
)
1323 handleAggressivesRequests(); // not truly synchronous
1325 thread_call_enter(aggressivesThreadCall
);
1327 return kIOReturnSuccess
;
1330 //******************************************************************************
1331 // getAggressiveness
1333 // Override IOService::setAggressiveness()
1334 // Fetch the aggressiveness factor with the given type.
1335 //******************************************************************************
1337 IOReturn
IOPMrootDomain::getAggressiveness (
1339 unsigned long * outLevel
)
1345 return kIOReturnBadArgument
;
1349 // Disk quick spindown in effect, report value = 1
1351 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1352 (type
== kPMMinutesToSpinDown
))
1354 value
= kAggressivesMinValue
;
1358 // Consult the pending request queue.
1362 AggressivesRequest
* entry
;
1364 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1366 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1367 (entry
->data
.record
.type
== type
) &&
1368 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1370 value
= entry
->data
.record
.value
;
1377 // Consult the backend records.
1379 if (!source
&& aggressivesData
)
1381 AggressivesRecord
* record
;
1384 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1385 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1387 for (i
= 0; i
< count
; i
++, record
++)
1389 if (record
->type
== type
)
1391 value
= record
->value
;
1398 AGGRESSIVES_UNLOCK();
1402 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1403 source
, (uint32_t) type
, value
);
1404 *outLevel
= (unsigned long) value
;
1405 return kIOReturnSuccess
;
1409 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1410 *outLevel
= 0; // default return = 0, driver may not check for error
1411 return kIOReturnInvalid
;
1415 //******************************************************************************
1416 // joinAggressiveness
1418 // Request from IOService to join future aggressiveness broadcasts.
1419 //******************************************************************************
1421 IOReturn
IOPMrootDomain::joinAggressiveness(
1422 IOService
* service
)
1424 AggressivesRequest
* request
;
1426 if (!service
|| (service
== this))
1427 return kIOReturnBadArgument
;
1429 DLOG("joinAggressiveness %s %p\n", service
->getName(), service
);
1431 request
= IONew(AggressivesRequest
, 1);
1433 return kIOReturnNoMemory
;
1435 service
->retain(); // released by synchronizeAggressives()
1437 memset(request
, 0, sizeof(*request
));
1438 request
->dataType
= kAggressivesRequestTypeService
;
1439 request
->data
.service
= service
;
1442 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1443 AGGRESSIVES_UNLOCK();
1445 thread_call_enter(aggressivesThreadCall
);
1447 return kIOReturnSuccess
;
1450 //******************************************************************************
1451 // handleAggressivesRequests
1453 // Backend thread processes all incoming aggressiveness requests in the queue.
1454 //******************************************************************************
1457 handleAggressivesFunction(
1458 thread_call_param_t param1
,
1459 thread_call_param_t param2
)
1463 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1467 void IOPMrootDomain::handleAggressivesRequests( void )
1469 AggressivesRecord
* start
;
1470 AggressivesRecord
* record
;
1471 AggressivesRequest
* request
;
1472 queue_head_t joinedQueue
;
1476 bool pingSelf
= false;
1480 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1481 queue_empty(&aggressivesQueue
))
1484 gAggressivesState
|= kAggressivesStateBusy
;
1485 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1486 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1491 queue_init(&joinedQueue
);
1495 // Remove request from the incoming queue in FIFO order.
1496 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1497 switch (request
->dataType
)
1499 case kAggressivesRequestTypeRecord
:
1500 // Update existing record if found.
1502 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1504 if (record
->type
== request
->data
.record
.type
)
1508 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1510 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1513 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1514 kAggressivesRecordFlagModified
);
1515 DLOG("disk spindown accelerated, was %u min\n",
1519 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1521 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1524 record
->flags
|= kAggressivesRecordFlagModified
;
1525 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1526 DLOG("disk spindown restored to %u min\n",
1530 else if (record
->value
!= request
->data
.record
.value
)
1532 record
->value
= request
->data
.record
.value
;
1533 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1536 record
->flags
|= kAggressivesRecordFlagModified
;
1543 // No matching record, append a new record.
1545 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1547 AggressivesRecord newRecord
;
1549 newRecord
.flags
= kAggressivesRecordFlagModified
;
1550 newRecord
.type
= request
->data
.record
.type
;
1551 newRecord
.value
= request
->data
.record
.value
;
1552 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1554 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1555 DLOG("disk spindown accelerated\n");
1558 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1560 // OSData may have switched to another (larger) buffer.
1561 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1562 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1566 // Finished processing the request, release it.
1567 IODelete(request
, AggressivesRequest
, 1);
1570 case kAggressivesRequestTypeService
:
1571 // synchronizeAggressives() will free request.
1572 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1576 panic("bad aggressives request type %x\n", request
->dataType
);
1579 } while (!queue_empty(&aggressivesQueue
));
1581 // Release the lock to perform work, with busy flag set.
1582 if (!queue_empty(&joinedQueue
) || broadcast
)
1584 AGGRESSIVES_UNLOCK();
1585 if (!queue_empty(&joinedQueue
))
1586 synchronizeAggressives(&joinedQueue
, start
, count
);
1588 broadcastAggressives(start
, count
);
1592 // Remove the modified flag from all records.
1593 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1595 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1596 ((record
->type
== kPMMinutesToDim
) ||
1597 (record
->type
== kPMMinutesToSleep
)))
1600 record
->flags
&= ~kAggressivesRecordFlagModified
;
1603 // Check the incoming queue again since new entries may have been
1604 // added while lock was released above.
1606 } while (!queue_empty(&aggressivesQueue
));
1608 gAggressivesState
&= ~kAggressivesStateBusy
;
1611 AGGRESSIVES_UNLOCK();
1613 // Root domain is interested in system and display sleep slider changes.
1614 // Submit a power event to handle those changes on the PM work loop.
1616 if (pingSelf
&& pmPowerStateQueue
) {
1617 pmPowerStateQueue
->submitPowerEvent(
1618 kPowerEventPolicyStimulus
,
1619 (void *) kStimulusAggressivenessChanged
);
1623 //******************************************************************************
1624 // synchronizeAggressives
1626 // Push all known aggressiveness records to one or more IOService.
1627 //******************************************************************************
1629 void IOPMrootDomain::synchronizeAggressives(
1630 queue_head_t
* joinedQueue
,
1631 const AggressivesRecord
* array
,
1634 IOService
* service
;
1635 AggressivesRequest
* request
;
1636 const AggressivesRecord
* record
;
1637 IOPMDriverCallEntry callEntry
;
1641 while (!queue_empty(joinedQueue
))
1643 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1644 if (request
->dataType
== kAggressivesRequestTypeService
)
1645 service
= request
->data
.service
;
1649 IODelete(request
, AggressivesRequest
, 1);
1654 if (service
->assertPMDriverCall(&callEntry
))
1656 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1658 value
= record
->value
;
1659 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1660 value
= kAggressivesMinValue
;
1662 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1663 record
->type
, value
, service
->getName());
1664 service
->setAggressiveness(record
->type
, value
);
1666 service
->deassertPMDriverCall(&callEntry
);
1668 service
->release(); // retained by joinAggressiveness()
1673 //******************************************************************************
1674 // broadcastAggressives
1676 // Traverse PM tree and call setAggressiveness() for records that have changed.
1677 //******************************************************************************
1679 void IOPMrootDomain::broadcastAggressives(
1680 const AggressivesRecord
* array
,
1683 IORegistryIterator
* iter
;
1684 IORegistryEntry
* entry
;
1685 IOPowerConnection
* connect
;
1686 IOService
* service
;
1687 const AggressivesRecord
* record
;
1688 IOPMDriverCallEntry callEntry
;
1692 iter
= IORegistryIterator::iterateOver(
1693 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1699 while ((entry
= iter
->getNextObject()))
1701 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1702 if (!connect
|| !connect
->getReadyFlag())
1705 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1707 if (service
->assertPMDriverCall(&callEntry
))
1709 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1711 if (record
->flags
& kAggressivesRecordFlagModified
)
1713 value
= record
->value
;
1714 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1715 value
= kAggressivesMinValue
;
1716 _LOG("broadcastAggressives %x = %u to %s\n",
1717 record
->type
, value
, service
->getName());
1718 service
->setAggressiveness(record
->type
, value
);
1721 service
->deassertPMDriverCall(&callEntry
);
1727 while (!entry
&& !iter
->isValid());
1733 // MARK: System Sleep
1735 //******************************************************************************
1736 // startIdleSleepTimer
1738 //******************************************************************************
1740 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1742 AbsoluteTime deadline
;
1747 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1748 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1749 idleSleepTimerPending
= true;
1750 DLOG("idle timer set for %u seconds\n", inSeconds
);
1754 //******************************************************************************
1755 // cancelIdleSleepTimer
1757 //******************************************************************************
1759 void IOPMrootDomain::cancelIdleSleepTimer( void )
1762 if (idleSleepTimerPending
)
1764 DLOG("idle timer cancelled\n");
1765 thread_call_cancel(extraSleepTimer
);
1766 idleSleepTimerPending
= false;
1770 //******************************************************************************
1771 // idleSleepTimerExpired
1773 //******************************************************************************
1775 static void idleSleepTimerExpired(
1776 thread_call_param_t us
, thread_call_param_t
)
1778 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
1781 //******************************************************************************
1782 // handleSleepTimerExpiration
1784 // The time between the sleep idle timeout and the next longest one has elapsed.
1785 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1786 //******************************************************************************
1788 void IOPMrootDomain::handleSleepTimerExpiration( void )
1790 if (!getPMworkloop()->inGate())
1792 getPMworkloop()->runAction(
1793 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1794 &IOPMrootDomain::handleSleepTimerExpiration
),
1801 DLOG("sleep timer expired\n");
1804 idleSleepTimerPending
= false;
1806 clock_get_uptime(&time
);
1807 if ((AbsoluteTime_to_scalar(&time
) > autoWakeStart
) &&
1808 (AbsoluteTime_to_scalar(&time
) < autoWakeEnd
))
1810 thread_call_enter_delayed(extraSleepTimer
, *((AbsoluteTime
*) &autoWakeEnd
));
1814 setQuickSpinDownTimeout();
1815 adjustPowerState(true);
1818 //******************************************************************************
1819 // setQuickSpinDownTimeout
1821 //******************************************************************************
1823 void IOPMrootDomain::setQuickSpinDownTimeout( void )
1827 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
1830 //******************************************************************************
1831 // restoreUserSpinDownTimeout
1833 //******************************************************************************
1835 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
1839 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
1842 //******************************************************************************
1845 //******************************************************************************
1848 IOReturn
IOPMrootDomain::sleepSystem( void )
1850 return sleepSystemOptions(NULL
);
1854 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
1856 /* sleepSystem is a public function, and may be called by any kernel driver.
1857 * And that's bad - drivers should sleep the system by calling
1858 * receivePowerNotification() instead. Drivers should not use sleepSystem.
1860 * Note that user space app calls to IOPMSleepSystem() will also travel
1861 * this code path and thus be correctly identified as software sleeps.
1864 if (options
&& options
->getObject("OSSwitch"))
1866 // Log specific sleep cause for OS Switch hibernation
1867 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
1869 return privateSleepSystem( kIOPMSleepReasonSoftware
);
1874 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
1876 static const char * IOPMSleepReasons
[] = {
1878 kIOPMClamshellSleepKey
,
1879 kIOPMPowerButtonSleepKey
,
1880 kIOPMSoftwareSleepKey
,
1881 kIOPMOSSwitchHibernationKey
,
1883 kIOPMLowPowerSleepKey
,
1884 kIOPMClamshellSleepKey
,
1885 kIOPMThermalEmergencySleepKey
,
1886 kIOPMMaintenanceSleepKey
1889 PMEventDetails
*details
;
1891 if (!checkSystemCanSleep())
1893 // Record why the system couldn't sleep
1894 details
= PMEventDetails::eventDetails(kIOPMEventTypeSleep
, NULL
,
1895 sleepReason
, kIOReturnNotPermitted
);
1897 recordAndReleasePMEvent( details
);
1898 return kIOReturnNotPermitted
;
1902 timeline
->setSleepCycleInProgressFlag(true);
1904 // Time to publish a UUID for the Sleep --> Wake cycle
1905 if(pmPowerStateQueue
) {
1906 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
1910 // Log the beginning of system sleep.
1911 details
= PMEventDetails::eventDetails(kIOPMEventTypeSleep
, NULL
,
1912 sleepReason
, kIOReturnSuccess
);
1914 recordAndReleasePMEvent( details
);
1916 // Record sleep cause in IORegistry
1917 lastSleepReason
= sleepReason
;
1918 sleepReason
-= (kIOPMSleepReasonClamshell
- 1);
1919 if (sleepReason
&& (sleepReason
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0]))) {
1920 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[sleepReason
]);
1923 if (pmPowerStateQueue
)
1924 pmPowerStateQueue
->submitPowerEvent(
1925 kPowerEventPolicyStimulus
,
1926 (void *) kStimulusDemandSystemSleep
);
1928 return kIOReturnSuccess
;
1931 IOReturn
IOPMrootDomain::recordPMEventGated(PMEventDetails
*record
)
1933 // If we don't have a place to log to, we can't actually
1934 // log anything. Chances are, the person who is asking us to do
1935 // the PM logging has forgotten to set the right bootflags
1937 return kIOReturnSuccess
;
1939 if(gIOPMWorkLoop
->inGate() == false) {
1941 IOReturn ret
= gIOPMWorkLoop
->runAction(
1942 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::recordPMEventGated
),
1949 // Now that we're guaranteed to be running in gate ...
1951 // Check the validity of the argument we are given
1953 return kIOReturnBadArgument
;
1955 // Record a driver event, or a system event
1956 if(record
->eventClassifier
== kIOPMEventClassDriverEvent
1957 || record
->eventClassifier
== kIOPMEventClassSystemEvent
)
1958 return this->recordPMEvent(record
);
1961 return kIOReturnBadArgument
;
1965 IOReturn
IOPMrootDomain::recordAndReleasePMEventGated(PMEventDetails
*record
)
1967 IOReturn ret
= kIOReturnBadArgument
;
1971 ret
= recordPMEventGated(record
);
1978 //******************************************************************************
1981 // This overrides powerChangeDone in IOService.
1982 //******************************************************************************
1984 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
1986 PMEventDetails
*details
;
1989 DLOG("PowerChangeDone: %u->%u\n",
1990 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
1992 switch ( getPowerState() )
1995 if (previousPowerState
!= ON_STATE
)
1998 details
= PMEventDetails::eventDetails(
1999 kIOPMEventTypeSleepDone
,
2004 recordAndReleasePMEvent( details
);
2006 // re-enable this timer for next sleep
2007 cancelIdleSleepTimer();
2010 clock_usec_t microsecs
;
2011 clock_get_calendar_microtime(&secs
, µsecs
);
2013 gIOLastSleepTime
.tv_sec
= secs
;
2014 gIOLastSleepTime
.tv_usec
= microsecs
;
2015 gIOLastWakeTime
.tv_sec
= 0;
2016 gIOLastWakeTime
.tv_usec
= 0;
2019 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2021 IOHibernateSystemHasSlept();
2023 evaluateSystemSleepPolicyFinal();
2025 LOG("System Sleep\n");
2028 getPlatform()->sleepKernel();
2030 // The CPU(s) are off at this point,
2031 // Code will resume execution here upon wake.
2033 clock_get_uptime(&systemWakeTime
);
2036 IOHibernateSystemWake();
2039 // sleep transition complete
2040 gSleepOrShutdownPending
= 0;
2042 // trip the reset of the calendar clock
2043 clock_wakeup_calendar();
2046 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2050 getPlatform()->PMLog(kIOPMrootDomainClass
, kPMLogSystemWake
, 0, 0);
2051 lowBatteryCondition
= false;
2052 lastSleepReason
= 0;
2054 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2055 _debugWakeSeconds
= 0;
2057 // And start logging the wake event here
2058 // TODO: Publish the wakeReason string as an integer
2059 details
= PMEventDetails::eventDetails(
2065 recordAndReleasePMEvent( details
);
2071 #if defined(__i386__) || defined(__x86_64__)
2072 wranglerTickled
= false;
2073 graphicsSuppressed
= false;
2074 darkWakePostTickle
= false;
2075 logGraphicsClamp
= true;
2076 logWranglerTickle
= true;
2077 sleepTimerMaintenance
= false;
2079 OSString
* wakeType
= OSDynamicCast(
2080 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2081 OSString
* wakeReason
= OSDynamicCast(
2082 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2084 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2086 lowBatteryCondition
= true;
2087 darkWakeMaintenance
= true;
2088 darkWakeToSleepASAP
= true;
2090 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2092 OSNumber
* hibOptions
= OSDynamicCast(
2093 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2095 if (hibernateAborted
|| ((hibOptions
&&
2096 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2098 // Hibernate aborted, or EFI brought up graphics
2099 wranglerTickled
= true;
2103 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2104 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2106 // User wake or RTC alarm
2107 wranglerTickled
= true;
2111 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2113 // SMC standby timer trumps SleepX
2114 darkWakeMaintenance
= true;
2115 darkWakeToSleepASAP
= true;
2116 sleepTimerMaintenance
= true;
2119 if ((_lastDebugWakeSeconds
!= 0) &&
2120 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2122 // SleepX before maintenance
2123 wranglerTickled
= true;
2127 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2129 darkWakeMaintenance
= true;
2130 darkWakeToSleepASAP
= true;
2134 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2136 darkWakeToSleepASAP
= true;
2137 // darkWakeMaintenance = true; // ????
2138 darkWakeSleepService
= true;
2142 // Unidentified wake source, resume to full wake if debug
2143 // alarm is pending.
2145 if (_lastDebugWakeSeconds
&&
2146 (!wakeReason
|| wakeReason
->isEqualTo("")))
2147 wranglerTickled
= true;
2149 darkWakeToSleepASAP
= true;
2155 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2157 darkWakeMaintenance
= true;
2158 darkWakeToSleepASAP
= true;
2159 sleepTimerMaintenance
= true;
2161 else if (hibernateAborted
|| !wakeType
||
2162 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2163 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2165 // Post a HID tickle immediately - except for RTC maintenance wake.
2166 wranglerTickled
= true;
2170 darkWakeMaintenance
= true;
2171 darkWakeToSleepASAP
= true;
2175 if (wranglerTickled
)
2177 else if (!darkWakeMaintenance
)
2179 // Early/late tickle for non-maintenance wake.
2180 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2181 kDarkWakeFlagHIDTickleEarly
) ||
2182 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2183 kDarkWakeFlagHIDTickleLate
))
2185 darkWakePostTickle
= true;
2188 #else /* !__i386__ && !__x86_64__ */
2189 // stay awake for at least 30 seconds
2190 wranglerTickled
= true;
2191 startIdleSleepTimer(30);
2194 changePowerStateToPriv(ON_STATE
);
2198 bool wasPrevented
= childPreventSystemSleep
;
2200 details
= PMEventDetails::eventDetails(
2201 kIOPMEventTypeWakeDone
,
2206 recordAndReleasePMEvent( details
);
2208 // Update childPreventSystemSleep flag using the capability computed
2209 // by IOSevice::rebuildChildClampBits().
2211 childPreventSystemSleep
=
2212 ((currentCapability() & kIOPMChildClamp2
) != 0);
2214 if (wasPrevented
&& !childPreventSystemSleep
)
2216 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2222 //******************************************************************************
2223 // requestPowerDomainState
2225 // Extend implementation in IOService. Running on PM work loop thread.
2227 // Examine children desires and initiate idle-sleep if all children are idle,
2228 // prevent idle and system sleep flags are not set.
2229 //******************************************************************************
2231 IOReturn
IOPMrootDomain::requestPowerDomainState (
2232 IOPMPowerFlags childDesire
,
2233 IOPowerConnection
* childConnection
,
2234 unsigned long specification
)
2238 IOPowerConnection
*connection
;
2239 IOPMPowerFlags mergedChildDesire
= 0;
2240 IOPMPowerFlags editedChildDesire
;
2241 IOPMPowerFlags thisDesire
;
2242 bool sleepASAP
= false;
2246 // Disregard disk I/O (anything besides the display wrangler) as a
2247 // factor in preventing idle sleep - based on a runtime setting.
2249 if ((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOAlways
) &&
2250 (kIOPMPreventIdleSleep
& childDesire
) &&
2251 (childConnection
!= wranglerConnection
))
2253 childDesire
&= ~kIOPMPreventIdleSleep
;
2256 // Force the child's input power requirement to 0 unless the prevent
2257 // idle-sleep flag is set. Nil input power flags maps to our state 0.
2258 // Our power clamp (deviceDesire) clamps the lowest power state at 2.
2260 editedChildDesire
= 0;
2261 if (childDesire
& kIOPMPreventIdleSleep
)
2262 editedChildDesire
|= (kIOPMPowerOn
| kIOPMPreventIdleSleep
);
2263 if (childDesire
& kIOPMPreventSystemSleep
)
2264 editedChildDesire
|= (kIOPMPowerOn
| kIOPMPreventSystemSleep
);
2266 iter
= getChildIterator(gIOPowerPlane
);
2269 while ( (next
= iter
->getNextObject()) )
2271 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
2273 // Ignore child that are in the process of joining.
2274 if (connection
->getReadyFlag() == false)
2277 // OR in the child's input power requirements.
2278 // Is this connection attached to the child that called
2279 // requestPowerDomainState()?
2281 if (connection
== childConnection
)
2283 thisDesire
= editedChildDesire
;
2288 if (connection
->getPreventIdleSleepFlag())
2289 thisDesire
|= (kIOPMPowerOn
| kIOPMPreventIdleSleep
);
2290 if (connection
->getPreventSystemSleepFlag())
2291 thisDesire
|= (kIOPMPowerOn
| kIOPMPreventSystemSleep
);
2294 mergedChildDesire
|= thisDesire
;
2295 if (thisDesire
&& (kIOLogPMRootDomain
& gIOKitDebug
))
2298 (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
2299 LOG("child %p, noIdle %d, noSleep %d - %s\n",
2301 ((thisDesire
& kIOPMPreventIdleSleep
) != 0),
2302 ((thisDesire
& kIOPMPreventSystemSleep
) != 0),
2303 child
? child
->getName() : "?");
2310 DLOG("mergedChildDesire 0x%lx, extraSleepDelay %ld\n",
2311 mergedChildDesire
, extraSleepDelay
);
2313 if ( !mergedChildDesire
&& !systemBooting
)
2317 changePowerStateToPriv(ON_STATE
);
2320 // stay awake for at least idleSeconds
2321 startIdleSleepTimer(idleSeconds
);
2324 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
2330 // Drop our power clamp to SLEEP_STATE when all children became idle,
2331 // and system sleep and display sleep slider values are equal.
2333 adjustPowerState(sleepASAP
);
2335 // If our power clamp has already dropped to SLEEP_STATE, and no child
2336 // is keeping us at ON_STATE, then the following will trigger idle sleep.
2338 return super::requestPowerDomainState(
2339 editedChildDesire
, childConnection
, specification
);
2342 //******************************************************************************
2345 // Override the superclass implementation to send a different message type.
2346 //******************************************************************************
2348 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2350 DLOG("tellChangeDown %u->%u\n",
2351 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2353 if (SLEEP_STATE
== stateNum
)
2355 if (!ignoreTellChangeDown
)
2356 tracePoint( kIOPMTracePointSleepApplications
);
2358 tracePoint( kIOPMTracePointSleepPriorityClients
);
2361 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2363 userActivityAtSleep
= userActivityCount
;
2364 hibernateAborted
= false;
2365 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2367 // Direct callout into OSKext so it can disable kext unloads
2368 // during sleep/wake to prevent deadlocks.
2369 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2371 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2373 // Notify platform that sleep has begun
2374 getPlatform()->callPlatformFunction(
2375 sleepMessagePEFunction
, false,
2376 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2379 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2380 // But tellClientsWithResponse() must be called for both.
2381 ignoreTellChangeDown
= true;
2384 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2387 //******************************************************************************
2390 // Override the superclass implementation to send a different message type.
2391 // This must be idle sleep since we don't ask during any other power change.
2392 //******************************************************************************
2394 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2396 DLOG("askChangeDown %u->%u\n",
2397 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2399 // Don't log for dark wake entry
2400 if (kSystemTransitionSleep
== _systemTransitionType
)
2401 tracePoint( kIOPMTracePointSleepApplications
);
2403 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2406 //******************************************************************************
2407 // askChangeDownDone
2409 // Called by PM after all apps have responded to kIOMessageCanSystemSleep.
2410 // pmconfigd may create a deny sleep assertion before ack'ing.
2411 //******************************************************************************
2413 void IOPMrootDomain::askChangeDownDone(
2414 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2416 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2417 *inOutChangeFlags
, *cancel
,
2418 _systemTransitionType
,
2419 _currentCapability
, _pendingCapability
);
2421 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2423 // Dark->Sleep transition.
2424 // Check if there are any deny sleep assertions.
2425 // Full->Dark transition is never cancelled.
2427 if (!checkSystemCanSleep(true))
2429 // Cancel dark wake to sleep transition.
2430 // Must re-scan assertions upon entering dark wake.
2433 DLOG("cancel dark->sleep\n");
2438 //******************************************************************************
2441 // Notify registered applications and kernel clients that we are not dropping
2444 // We override the superclass implementation so we can send a different message
2445 // type to the client or application being notified.
2447 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2448 //******************************************************************************
2450 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2452 DLOG("tellNoChangeDown %u->%u\n",
2453 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2455 if (idleSeconds
&& !wrangler
)
2457 // stay awake for at least idleSeconds
2458 startIdleSleepTimer(idleSeconds
);
2460 return tellClients( kIOMessageSystemWillNotSleep
);
2463 //******************************************************************************
2466 // Notify registered applications and kernel clients that we are raising power.
2468 // We override the superclass implementation so we can send a different message
2469 // type to the client or application being notified.
2470 //******************************************************************************
2472 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2474 OSData
*publishPMStats
= NULL
;
2476 DLOG("tellChangeUp %u->%u\n",
2477 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2479 ignoreTellChangeDown
= false;
2481 if ( stateNum
== ON_STATE
)
2483 // Direct callout into OSKext so it can disable kext unloads
2484 // during sleep/wake to prevent deadlocks.
2485 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2487 // Notify platform that sleep was cancelled or resumed.
2488 getPlatform()->callPlatformFunction(
2489 sleepMessagePEFunction
, false,
2490 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2493 if (getPowerState() == ON_STATE
)
2495 // this is a quick wake from aborted sleep
2496 if (idleSeconds
&& !wrangler
)
2498 // stay awake for at least idleSeconds
2499 startIdleSleepTimer(idleSeconds
);
2501 tellClients( kIOMessageSystemWillPowerOn
);
2504 tracePoint( kIOPMTracePointWakeApplications
);
2505 publishPMStats
= OSData::withBytes(&pmStats
, sizeof(pmStats
));
2506 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
2507 publishPMStats
->release();
2508 bzero(&pmStats
, sizeof(pmStats
));
2510 if (pmStatsAppResponses
)
2512 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
2513 pmStatsAppResponses
->release();
2514 pmStatsAppResponses
= OSArray::withCapacity(5);
2517 tellClients( kIOMessageSystemHasPoweredOn
);
2521 //******************************************************************************
2522 // sysPowerDownHandler
2524 // Perform a vfs sync before system sleep.
2525 //******************************************************************************
2527 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2528 void * target
, void * refCon
,
2529 UInt32 messageType
, IOService
* service
,
2530 void * messageArgs
, vm_size_t argSize
)
2534 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2537 return kIOReturnUnsupported
;
2539 if (messageType
== kIOMessageSystemCapabilityChange
)
2541 IOPMSystemCapabilityChangeParameters
* params
=
2542 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2544 // Interested applications have been notified of an impending power
2545 // change and have acked (when applicable).
2546 // This is our chance to save whatever state we can before powering
2548 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2551 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2552 params
->fromCapabilities
, params
->toCapabilities
,
2553 params
->changeFlags
);
2555 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2556 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2557 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2559 // We will ack within 20 seconds
2560 params
->maxWaitForReply
= 20 * 1000 * 1000;
2562 gRootDomain
->evaluateSystemSleepPolicyEarly();
2564 // add in time we could spend freeing pages
2565 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2567 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2569 DLOG("sysPowerDownHandler timeout %d s\n", (int) (params
->maxWaitForReply
/ 1000 / 1000));
2572 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2574 // Purposely delay the ack and hope that shutdown occurs quickly.
2575 // Another option is not to schedule the thread and wait for
2577 AbsoluteTime deadline
;
2578 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2579 thread_call_enter1_delayed(
2580 gRootDomain
->diskSyncCalloutEntry
,
2581 (thread_call_param_t
) params
->notifyRef
,
2586 gRootDomain
->diskSyncCalloutEntry
,
2587 (thread_call_param_t
) params
->notifyRef
);
2591 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2592 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2593 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2595 // We will ack within 110 seconds
2596 params
->maxWaitForReply
= 110 * 1000 * 1000;
2599 gRootDomain
->diskSyncCalloutEntry
,
2600 (thread_call_param_t
) params
->notifyRef
);
2603 ret
= kIOReturnSuccess
;
2609 //******************************************************************************
2610 // handleQueueSleepWakeUUID
2612 // Called from IOPMrootDomain when we're initiating a sleep,
2613 // or indirectly from PM configd when PM decides to clear the UUID.
2614 // PM clears the UUID several minutes after successful wake from sleep,
2615 // so that we might associate App spindumps with the immediately previous
2618 // @param obj has a retain on it. We're responsible for releasing that retain.
2619 //******************************************************************************
2621 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2623 OSString
*str
= NULL
;
2625 if (kOSBooleanFalse
== obj
)
2627 handlePublishSleepWakeUUID(NULL
);
2629 else if ((str
= OSDynamicCast(OSString
, obj
)))
2631 // This branch caches the UUID for an upcoming sleep/wake
2632 if (queuedSleepWakeUUIDString
) {
2633 queuedSleepWakeUUIDString
->release();
2634 queuedSleepWakeUUIDString
= NULL
;
2636 queuedSleepWakeUUIDString
= str
;
2637 queuedSleepWakeUUIDString
->retain();
2639 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2648 //******************************************************************************
2649 // handlePublishSleepWakeUUID
2651 // Called from IOPMrootDomain when we're initiating a sleep,
2652 // or indirectly from PM configd when PM decides to clear the UUID.
2653 // PM clears the UUID several minutes after successful wake from sleep,
2654 // so that we might associate App spindumps with the immediately previous
2656 //******************************************************************************
2658 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2663 * Clear the current UUID
2665 if (gSleepWakeUUIDIsSet
)
2667 DLOG("SleepWake UUID cleared\n");
2669 OSString
*UUIDstring
= NULL
;
2672 (UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))))
2674 PMEventDetails
*details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDClear
,
2675 UUIDstring
->getCStringNoCopy(), NULL
, 0);
2677 timeline
->recordSystemPowerEvent( details
);
2680 timeline
->setNumEventsLoggedThisPeriod(0);
2683 gSleepWakeUUIDIsSet
= false;
2685 removeProperty(kIOPMSleepWakeUUIDKey
);
2686 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2690 * Optionally, publish a new UUID
2692 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2694 OSString
*publishThisUUID
= NULL
;
2696 publishThisUUID
= queuedSleepWakeUUIDString
;
2697 publishThisUUID
->retain();
2700 PMEventDetails
*details
;
2701 details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDSet
,
2702 publishThisUUID
->getCStringNoCopy(), NULL
, 0);
2704 timeline
->recordSystemPowerEvent( details
);
2709 if (publishThisUUID
)
2711 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
2712 publishThisUUID
->release();
2715 gSleepWakeUUIDIsSet
= true;
2716 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
2718 queuedSleepWakeUUIDString
->release();
2719 queuedSleepWakeUUIDString
= NULL
;
2723 //******************************************************************************
2724 // changePowerStateTo & changePowerStateToPriv
2726 // Override of these methods for logging purposes.
2727 //******************************************************************************
2729 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
2731 return kIOReturnUnsupported
; // ignored
2734 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
2736 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
2738 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2739 return kIOReturnUnsupported
;
2741 return super::changePowerStateToPriv(ordinal
);
2744 //******************************************************************************
2747 //******************************************************************************
2749 bool IOPMrootDomain::activitySinceSleep(void)
2751 return (userActivityCount
!= userActivityAtSleep
);
2754 bool IOPMrootDomain::abortHibernation(void)
2756 bool ret
= activitySinceSleep();
2758 if (ret
&& !hibernateAborted
)
2760 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
2761 hibernateAborted
= true;
2767 hibernate_should_abort(void)
2770 return (gRootDomain
->abortHibernation());
2775 //******************************************************************************
2776 // sleepOnClamshellClosed
2778 // contains the logic to determine if the system should sleep when the clamshell
2780 //******************************************************************************
2782 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2784 if (!clamshellExists
)
2787 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d\n",
2788 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
);
2790 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) );
2793 void IOPMrootDomain::sendClientClamshellNotification( void )
2795 /* Only broadcast clamshell alert if clamshell exists. */
2796 if (!clamshellExists
)
2799 setProperty(kAppleClamshellStateKey
,
2800 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
2802 setProperty(kAppleClamshellCausesSleepKey
,
2803 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
2805 /* Argument to message is a bitfiel of
2806 * ( kClamshellStateBit | kClamshellSleepBit )
2808 messageClients(kIOPMMessageClamshellStateChange
,
2809 (void *) ( (clamshellClosed
? kClamshellStateBit
: 0)
2810 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
2813 //******************************************************************************
2814 // getSleepSupported
2817 //******************************************************************************
2819 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
2821 return( platformSleepSupport
);
2824 //******************************************************************************
2825 // setSleepSupported
2828 //******************************************************************************
2830 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
2832 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
2833 OSBitOrAtomic(flags
, &platformSleepSupport
);
2836 //******************************************************************************
2840 //******************************************************************************
2842 void IOPMrootDomain::wakeFromDoze( void )
2844 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
2850 //******************************************************************************
2853 // Adds a new feature to the supported features dictionary
2854 //******************************************************************************
2856 void IOPMrootDomain::publishFeature( const char * feature
)
2858 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
2861 //******************************************************************************
2862 // publishFeature (with supported power source specified)
2864 // Adds a new feature to the supported features dictionary
2865 //******************************************************************************
2867 void IOPMrootDomain::publishFeature(
2868 const char *feature
,
2869 uint32_t supportedWhere
,
2870 uint32_t *uniqueFeatureID
)
2872 static uint16_t next_feature_id
= 500;
2874 OSNumber
*new_feature_data
= NULL
;
2875 OSNumber
*existing_feature
= NULL
;
2876 OSArray
*existing_feature_arr
= NULL
;
2877 OSObject
*osObj
= NULL
;
2878 uint32_t feature_value
= 0;
2880 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
2882 if(!supportedWhere
) {
2883 // Feature isn't supported anywhere!
2887 if(next_feature_id
> 5000) {
2888 // Far, far too many features!
2892 if(featuresDictLock
) IOLockLock(featuresDictLock
);
2894 OSDictionary
*features
=
2895 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
2897 // Create new features dict if necessary
2898 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
2899 features
= OSDictionary::withDictionary(features
);
2901 features
= OSDictionary::withCapacity(1);
2904 // Create OSNumber to track new feature
2906 next_feature_id
+= 1;
2907 if( uniqueFeatureID
) {
2908 // We don't really mind if the calling kext didn't give us a place
2909 // to stash their unique id. Many kexts don't plan to unload, and thus
2910 // have no need to remove themselves later.
2911 *uniqueFeatureID
= next_feature_id
;
2914 feature_value
= (uint32_t)next_feature_id
;
2915 feature_value
<<= 16;
2916 feature_value
+= supportedWhere
;
2918 new_feature_data
= OSNumber::withNumber(
2919 (unsigned long long)feature_value
, 32);
2921 // Does features object already exist?
2922 if( (osObj
= features
->getObject(feature
)) )
2924 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
2926 // We need to create an OSArray to hold the now 2 elements.
2927 existing_feature_arr
= OSArray::withObjects(
2928 (const OSObject
**)&existing_feature
, 1, 2);
2929 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
2931 // Add object to existing array
2932 existing_feature_arr
= OSArray::withArray(
2933 existing_feature_arr
,
2934 existing_feature_arr
->getCount() + 1);
2937 if (existing_feature_arr
)
2939 existing_feature_arr
->setObject(new_feature_data
);
2940 features
->setObject(feature
, existing_feature_arr
);
2941 existing_feature_arr
->release();
2942 existing_feature_arr
= 0;
2945 // The easy case: no previously existing features listed. We simply
2946 // set the OSNumber at key 'feature' and we're on our way.
2947 features
->setObject(feature
, new_feature_data
);
2950 new_feature_data
->release();
2952 setProperty(kRootDomainSupportedFeatures
, features
);
2954 features
->release();
2956 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
2958 // Notify EnergySaver and all those in user space so they might
2959 // re-populate their feature specific UI
2960 if(pmPowerStateQueue
) {
2961 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
2965 //******************************************************************************
2966 // removePublishedFeature
2968 // Removes previously published feature
2969 //******************************************************************************
2971 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
2973 IOReturn ret
= kIOReturnError
;
2974 uint32_t feature_value
= 0;
2975 uint16_t feature_id
= 0;
2976 bool madeAChange
= false;
2978 OSSymbol
*dictKey
= NULL
;
2979 OSCollectionIterator
*dictIterator
= NULL
;
2980 OSArray
*arrayMember
= NULL
;
2981 OSNumber
*numberMember
= NULL
;
2982 OSObject
*osObj
= NULL
;
2983 OSNumber
*osNum
= NULL
;
2984 OSArray
*arrayMemberCopy
;
2986 if (kBadPMFeatureID
== removeFeatureID
)
2987 return kIOReturnNotFound
;
2989 if(featuresDictLock
) IOLockLock(featuresDictLock
);
2991 OSDictionary
*features
=
2992 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
2994 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
2996 // Any modifications to the dictionary are made to the copy to prevent
2997 // races & crashes with userland clients. Dictionary updated
2998 // automically later.
2999 features
= OSDictionary::withDictionary(features
);
3002 ret
= kIOReturnNotFound
;
3006 // We iterate 'features' dictionary looking for an entry tagged
3007 // with 'removeFeatureID'. If found, we remove it from our tracking
3008 // structures and notify the OS via a general interest message.
3010 dictIterator
= OSCollectionIterator::withCollection(features
);
3015 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3017 osObj
= features
->getObject(dictKey
);
3019 // Each Feature is either tracked by an OSNumber
3020 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3022 feature_value
= numberMember
->unsigned32BitValue();
3023 feature_id
= (uint16_t)(feature_value
>> 16);
3025 if( feature_id
== (uint16_t)removeFeatureID
)
3028 features
->removeObject(dictKey
);
3033 // Or tracked by an OSArray of OSNumbers
3034 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3036 unsigned int arrayCount
= arrayMember
->getCount();
3038 for(unsigned int i
=0; i
<arrayCount
; i
++)
3040 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3045 feature_value
= osNum
->unsigned32BitValue();
3046 feature_id
= (uint16_t)(feature_value
>> 16);
3048 if( feature_id
== (uint16_t)removeFeatureID
)
3051 if( 1 == arrayCount
) {
3052 // If the array only contains one element, remove
3054 features
->removeObject(dictKey
);
3056 // Otherwise remove the element from a copy of the array.
3057 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3058 if (arrayMemberCopy
)
3060 arrayMemberCopy
->removeObject(i
);
3061 features
->setObject(dictKey
, arrayMemberCopy
);
3062 arrayMemberCopy
->release();
3073 dictIterator
->release();
3077 ret
= kIOReturnSuccess
;
3079 setProperty(kRootDomainSupportedFeatures
, features
);
3081 // Notify EnergySaver and all those in user space so they might
3082 // re-populate their feature specific UI
3083 if(pmPowerStateQueue
) {
3084 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3087 ret
= kIOReturnNotFound
;
3091 if(features
) features
->release();
3092 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3096 //******************************************************************************
3097 // publishPMSetting (private)
3099 // Should only be called by PMSettingObject to publish a PM Setting as a
3100 // supported feature.
3101 //******************************************************************************
3103 void IOPMrootDomain::publishPMSetting(
3104 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3106 if (noPublishPMSettings
&&
3107 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3109 // Setting found in noPublishPMSettings array
3110 *featureID
= kBadPMFeatureID
;
3115 feature
->getCStringNoCopy(), where
, featureID
);
3118 //******************************************************************************
3119 // setPMSetting (private)
3121 // Internal helper to relay PM settings changes from user space to individual
3122 // drivers. Should be called only by IOPMrootDomain::setProperties.
3123 //******************************************************************************
3125 IOReturn
IOPMrootDomain::setPMSetting(
3126 const OSSymbol
*type
,
3129 PMSettingCallEntry
*entries
= 0;
3130 OSArray
*chosen
= 0;
3131 const OSArray
*array
;
3132 PMSettingObject
*pmso
;
3133 thread_t thisThread
;
3134 int i
, j
, count
, capacity
;
3137 return kIOReturnBadArgument
;
3141 // Update settings dict so changes are visible from copyPMSetting().
3142 fPMSettingsDict
->setObject(type
, object
);
3144 // Prep all PMSetting objects with the given 'type' for callout.
3145 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3146 if (!array
|| ((capacity
= array
->getCount()) == 0))
3149 // Array to retain PMSetting objects targeted for callout.
3150 chosen
= OSArray::withCapacity(capacity
);
3152 goto unlock_exit
; // error
3154 entries
= IONew(PMSettingCallEntry
, capacity
);
3156 goto unlock_exit
; // error
3157 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3159 thisThread
= current_thread();
3161 for (i
= 0, j
= 0; i
<capacity
; i
++)
3163 pmso
= (PMSettingObject
*) array
->getObject(i
);
3166 entries
[j
].thread
= thisThread
;
3167 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3168 chosen
->setObject(pmso
);
3177 // Call each pmso in the chosen array.
3178 for (i
=0; i
<count
; i
++)
3180 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3181 pmso
->dispatchPMSetting(type
, object
);
3185 for (i
=0; i
<count
; i
++)
3187 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3188 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3189 if (pmso
->waitThread
)
3191 PMSETTING_WAKEUP(pmso
);
3197 if (chosen
) chosen
->release();
3198 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3200 return kIOReturnSuccess
;
3203 //******************************************************************************
3204 // copyPMSetting (public)
3206 // Allows kexts to safely read setting values, without being subscribed to
3208 //******************************************************************************
3210 OSObject
* IOPMrootDomain::copyPMSetting(
3211 OSSymbol
*whichSetting
)
3213 OSObject
*obj
= NULL
;
3215 if(!whichSetting
) return NULL
;
3218 obj
= fPMSettingsDict
->getObject(whichSetting
);
3227 //******************************************************************************
3228 // registerPMSettingController (public)
3230 // direct wrapper to registerPMSettingController with uint32_t power source arg
3231 //******************************************************************************
3233 IOReturn
IOPMrootDomain::registerPMSettingController(
3234 const OSSymbol
* settings
[],
3235 IOPMSettingControllerCallback func
,
3240 return registerPMSettingController(
3242 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3243 func
, target
, refcon
, handle
);
3246 //******************************************************************************
3247 // registerPMSettingController (public)
3249 // Kexts may register for notifications when a particular setting is changed.
3250 // A list of settings is available in IOPM.h.
3252 // * settings - An OSArray containing OSSymbols. Caller should populate this
3253 // array with a list of settings caller wants notifications from.
3254 // * func - A C function callback of the type IOPMSettingControllerCallback
3255 // * target - caller may provide an OSObject *, which PM will pass as an
3256 // target to calls to "func"
3257 // * refcon - caller may provide an void *, which PM will pass as an
3258 // argument to calls to "func"
3259 // * handle - This is a return argument. We will populate this pointer upon
3260 // call success. Hold onto this and pass this argument to
3261 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3263 // kIOReturnSuccess on success
3264 //******************************************************************************
3266 IOReturn
IOPMrootDomain::registerPMSettingController(
3267 const OSSymbol
* settings
[],
3268 uint32_t supportedPowerSources
,
3269 IOPMSettingControllerCallback func
,
3274 PMSettingObject
*pmso
= NULL
;
3275 OSObject
*pmsh
= NULL
;
3276 OSArray
*list
= NULL
;
3279 if (NULL
== settings
||
3283 return kIOReturnBadArgument
;
3286 pmso
= PMSettingObject::pmSettingObject(
3287 (IOPMrootDomain
*) this, func
, target
,
3288 refcon
, supportedPowerSources
, settings
, &pmsh
);
3292 return kIOReturnInternalError
;
3296 for (i
=0; settings
[i
]; i
++)
3298 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3300 // New array of callbacks for this setting
3301 list
= OSArray::withCapacity(1);
3302 settingsCallbacks
->setObject(settings
[i
], list
);
3306 // Add caller to the callback list
3307 list
->setObject(pmso
);
3311 // Return handle to the caller, the setting object is private.
3314 return kIOReturnSuccess
;
3317 //******************************************************************************
3318 // deregisterPMSettingObject (private)
3320 // Only called from PMSettingObject.
3321 //******************************************************************************
3323 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3325 thread_t thisThread
= current_thread();
3326 PMSettingCallEntry
*callEntry
;
3327 OSCollectionIterator
*iter
;
3335 pmso
->disabled
= true;
3337 // Wait for all callout threads to finish.
3340 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3342 if (callEntry
->thread
!= thisThread
)
3350 assert(0 == pmso
->waitThread
);
3351 pmso
->waitThread
= thisThread
;
3352 PMSETTING_WAIT(pmso
);
3353 pmso
->waitThread
= 0;
3357 // Search each PM settings array in the kernel.
3358 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3361 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3363 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3364 index
= array
->getNextIndexOfObject(pmso
, 0);
3366 array
->removeObject(index
);
3377 //******************************************************************************
3378 // informCPUStateChange
3380 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3381 // running on battery, with the lid closed, etc.
3383 // informCPUStateChange is a no-op on non x86 systems
3384 // only x86 has explicit support in the IntelCPUPowerManagement kext
3385 //******************************************************************************
3387 void IOPMrootDomain::informCPUStateChange(
3391 #if defined(__i386__) || defined(__x86_64__)
3393 pmioctlVariableInfo_t varInfoStruct
;
3395 const char *varNameStr
= NULL
;
3396 int32_t *varIndex
= NULL
;
3398 if (kInformAC
== type
) {
3399 varNameStr
= kIOPMRootDomainBatPowerCString
;
3400 varIndex
= &idxPMCPULimitedPower
;
3401 } else if (kInformLid
== type
) {
3402 varNameStr
= kIOPMRootDomainLidCloseCString
;
3403 varIndex
= &idxPMCPUClamshell
;
3408 // Set the new value!
3409 // pmCPUControl will assign us a new ID if one doesn't exist yet
3410 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3411 varInfoStruct
.varID
= *varIndex
;
3412 varInfoStruct
.varType
= vBool
;
3413 varInfoStruct
.varInitValue
= value
;
3414 varInfoStruct
.varCurValue
= value
;
3415 strncpy( (char *)varInfoStruct
.varName
,
3416 (const char *)varNameStr
,
3417 strlen(varNameStr
) + 1 );
3420 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3422 // pmCPU only assigns numerical id's when a new varName is specified
3424 && (*varIndex
== kCPUUnknownIndex
))
3426 // pmCPUControl has assigned us a new variable ID.
3427 // Let's re-read the structure we just SET to learn that ID.
3428 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3432 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3433 *varIndex
= varInfoStruct
.varID
;
3439 #endif /* __i386__ || __x86_64__ */
3443 // MARK: Deep Sleep Policy
3447 //******************************************************************************
3448 // evaluateSystemSleepPolicy
3449 //******************************************************************************
3451 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3455 kIOPMSleepFlagHibernate
= 0x00000001,
3456 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3459 struct IOPMSystemSleepPolicyEntry
3461 uint32_t factorMask
;
3462 uint32_t factorBits
;
3463 uint32_t sleepFlags
;
3464 uint32_t wakeEvents
;
3465 } __attribute__((packed
));
3467 struct IOPMSystemSleepPolicyTable
3471 uint16_t entryCount
;
3472 IOPMSystemSleepPolicyEntry entries
[];
3473 } __attribute__((packed
));
3475 bool IOPMrootDomain::evaluateSystemSleepPolicy(
3476 IOPMSystemSleepParameters
* params
, int sleepPhase
)
3478 const IOPMSystemSleepPolicyTable
* pt
;
3479 OSObject
* prop
= 0;
3480 OSData
* policyData
;
3481 uint64_t currentFactors
= 0;
3482 uint32_t standbyDelay
;
3483 uint32_t powerOffDelay
;
3485 bool standbyEnabled
;
3486 bool powerOffEnabled
;
3489 // Get platform's sleep policy table
3490 if (!_sleepPolicyHandler
)
3492 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3493 if (!prop
) goto done
;
3496 // Fetch additional settings
3497 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
3498 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
3499 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
3500 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
3501 DLOG("standby %d delay %u, powerOff %d delay %u, hibernate %u\n",
3502 standbyEnabled
, standbyDelay
, powerOffEnabled
, powerOffDelay
,
3505 // pmset level overrides
3506 if ((hibernateMode
& kIOHibernateModeOn
) == 0)
3508 standbyEnabled
= false;
3509 powerOffEnabled
= false;
3511 else if (!(hibernateMode
& kIOHibernateModeSleep
))
3513 // Force hibernate (i.e. mode 25)
3514 // If standby is enabled, force standy.
3515 // If poweroff is enabled, force poweroff.
3517 currentFactors
|= kIOPMSleepFactorStandbyForced
;
3518 else if (powerOffEnabled
)
3519 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
3521 currentFactors
|= kIOPMSleepFactorHibernateForced
;
3524 // Current factors based on environment and assertions
3525 if (sleepTimerMaintenance
)
3526 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3527 if (!clamshellClosed
)
3528 currentFactors
|= kIOPMSleepFactorLidOpen
;
3529 if (acAdaptorConnected
)
3530 currentFactors
|= kIOPMSleepFactorACPower
;
3531 if (lowBatteryCondition
)
3532 currentFactors
|= kIOPMSleepFactorBatteryLow
;
3534 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
3535 if (!standbyEnabled
)
3536 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
3537 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3538 kIOPMDriverAssertionLevelOff
)
3539 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3540 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3541 kIOPMDriverAssertionLevelOff
)
3542 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3543 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3544 kIOPMDriverAssertionLevelOff
)
3545 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3546 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
3547 kIOPMDriverAssertionLevelOff
)
3548 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
3549 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit8
) !=
3550 kIOPMDriverAssertionLevelOff
)
3551 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
3552 if (!powerOffEnabled
)
3553 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
3555 DLOG("sleep factors 0x%llx\n", currentFactors
);
3557 // Clear the output params
3558 bzero(params
, sizeof(*params
));
3560 if (_sleepPolicyHandler
)
3562 if (!_sleepPolicyVars
)
3564 _sleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
3565 if (!_sleepPolicyVars
)
3567 bzero(_sleepPolicyVars
, sizeof(*_sleepPolicyVars
));
3569 _sleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
3570 _sleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
3571 if (kIOPMSleepPhase1
== sleepPhase
)
3573 _sleepPolicyVars
->currentCapability
= _currentCapability
;
3574 _sleepPolicyVars
->highestCapability
= _highestCapability
;
3575 _sleepPolicyVars
->sleepReason
= lastSleepReason
;
3576 _sleepPolicyVars
->hibernateMode
= hibernateMode
;
3577 _sleepPolicyVars
->standbyDelay
= standbyDelay
;
3578 _sleepPolicyVars
->poweroffDelay
= powerOffDelay
;
3580 _sleepPolicyVars
->sleepFactors
= currentFactors
;
3581 _sleepPolicyVars
->sleepPhase
= sleepPhase
;
3583 if ((_sleepPolicyHandler(_sleepPolicyTarget
, _sleepPolicyVars
, params
) !=
3584 kIOReturnSuccess
) || (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
3585 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
3586 (kIOPMSystemSleepParametersVersion
!= params
->version
))
3588 MSG("sleep policy handler error\n");
3592 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
3593 params
->version
, params
->sleepType
, params
->sleepFlags
,
3594 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
3599 // Policy table is meaningless without standby enabled
3600 if (!standbyEnabled
)
3603 // Validate the sleep policy table
3604 policyData
= OSDynamicCast(OSData
, prop
);
3605 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
3608 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
3609 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
3610 (pt
->version
!= 1) || (0 == pt
->entryCount
))
3613 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
3614 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
3617 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
3619 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
3620 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
3622 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
3623 entry
->factorMask
, entry
->factorBits
,
3624 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
3628 DLOG("^ found match\n");
3631 params
->version
= kIOPMSystemSleepParametersVersion
;
3632 params
->reserved1
= 1;
3633 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
3634 params
->sleepType
= kIOPMSleepTypeStandby
;
3636 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
3638 params
->ecWakeEvents
= entry
->wakeEvents
;
3639 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
3640 params
->ecWakeTimer
= standbyDelay
;
3651 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
3653 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
3655 // Evaluate early (priority interest phase), before drivers sleep.
3657 DLOG("%s\n", __FUNCTION__
);
3658 removeProperty(kIOPMSystemSleepParametersKey
);
3660 hibernateDisabled
= false;
3662 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
3664 // Save for late evaluation if sleep is aborted
3665 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
3667 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
))
3669 if (!hibernateNoDefeat
&&
3670 (gEarlySystemSleepParams
.sleepType
== kIOPMSleepTypeNormalSleep
))
3672 // Disable hibernate setup for normal sleep
3673 hibernateDisabled
= true;
3677 // Publish IOPMSystemSleepType
3678 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
3679 if (sleepType
== kIOPMSleepTypeInvalid
)
3682 sleepType
= kIOPMSleepTypeNormalSleep
;
3683 if (hibernateMode
& kIOHibernateModeOn
)
3684 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
3685 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
3687 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
3688 (gEarlySystemSleepParams
.ecPoweroffTimer
))
3690 // report the lowest possible sleep state
3691 sleepType
= kIOPMSleepTypePowerOff
;
3694 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
3697 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
3699 IOPMSystemSleepParameters params
;
3700 OSData
* paramsData
;
3702 // Evaluate sleep policy after sleeping drivers but before platform sleep.
3704 DLOG("%s\n", __FUNCTION__
);
3706 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
))
3708 if ((hibernateDisabled
|| hibernateAborted
) &&
3709 (params
.sleepType
!= kIOPMSleepTypeNormalSleep
))
3711 // Final evaluation picked a state requiring hibernation,
3712 // but hibernate setup was skipped. Retry using the early
3713 // sleep parameters.
3715 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
3716 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
3717 params
.ecWakeTimer
= 1;
3718 hibernateNoDefeat
= true;
3719 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
3720 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
);
3724 hibernateNoDefeat
= false;
3727 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
3730 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
3731 paramsData
->release();
3734 if (params
.sleepType
>= kIOPMSleepTypeHibernate
)
3736 // Disable safe sleep to force the hibernate path
3737 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
3742 bool IOPMrootDomain::getHibernateSettings(
3743 uint32_t * hibernateModePtr
,
3744 uint32_t * hibernateFreeRatio
,
3745 uint32_t * hibernateFreeTime
)
3747 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
3748 // has updated the hibernateDisabled flag.
3750 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
3751 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
3752 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
3753 if (hibernateDisabled
)
3754 *hibernateModePtr
= 0;
3755 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
3759 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
3761 OSObject
* optionsProp
;
3762 OSDictionary
* optionsDict
;
3767 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
3768 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
3772 obj
= optionsDict
->getObject(key
);
3773 if (obj
) obj
->retain();
3777 obj
= copyProperty(key
);
3779 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)))
3781 *option
= num
->unsigned32BitValue();
3788 optionsProp
->release();
3792 #endif /* HIBERNATION */
3795 // MARK: Shutdown and Restart
3797 //******************************************************************************
3798 // handlePlatformHaltRestart
3800 //******************************************************************************
3802 struct HaltRestartApplierContext
{
3803 IOPMrootDomain
* RootDomain
;
3804 unsigned long PowerState
;
3805 IOPMPowerFlags PowerFlags
;
3811 platformHaltRestartApplier( OSObject
* object
, void * context
)
3813 IOPowerStateChangeNotification notify
;
3814 HaltRestartApplierContext
* ctx
;
3815 AbsoluteTime startTime
;
3818 ctx
= (HaltRestartApplierContext
*) context
;
3820 memset(¬ify
, 0, sizeof(notify
));
3821 notify
.powerRef
= (void *)ctx
->Counter
;
3822 notify
.returnValue
= 0;
3823 notify
.stateNumber
= ctx
->PowerState
;
3824 notify
.stateFlags
= ctx
->PowerFlags
;
3826 clock_get_uptime(&startTime
);
3827 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
3828 deltaTime
= computeDeltaTimeMS(&startTime
);
3830 if ((deltaTime
> kPMHaltTimeoutMS
) ||
3831 (gIOKitDebug
& kIOLogPMRootDomain
))
3833 _IOServiceInterestNotifier
* notifier
;
3834 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
3836 // IOService children of IOPMrootDomain are not instrumented.
3837 // Only IORootParent currently falls under that group.
3841 LOG("%s handler %p took %u ms\n",
3842 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
3843 (ctx
->MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
3844 notifier
->handler
, (uint32_t) deltaTime
);
3851 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
3853 HaltRestartApplierContext ctx
;
3854 AbsoluteTime startTime
;
3857 memset(&ctx
, 0, sizeof(ctx
));
3858 ctx
.RootDomain
= this;
3860 clock_get_uptime(&startTime
);
3864 case kPEUPSDelayHaltCPU
:
3865 ctx
.PowerState
= OFF_STATE
;
3866 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
3870 ctx
.PowerState
= RESTART_STATE
;
3871 ctx
.MessageType
= kIOMessageSystemWillRestart
;
3875 ctx
.PowerState
= ON_STATE
;
3876 ctx
.MessageType
= kIOMessageSystemPagingOff
;
3877 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
3884 // Notify legacy clients
3885 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
3887 // For normal shutdown, turn off File Server Mode.
3888 if (kPEHaltCPU
== pe_type
)
3890 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
3891 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
3894 setPMSetting(setting
, num
);
3900 if (kPEPagingOff
!= pe_type
)
3902 // Notify in power tree order
3903 notifySystemShutdown(this, ctx
.MessageType
);
3906 deltaTime
= computeDeltaTimeMS(&startTime
);
3907 LOG("%s all drivers took %u ms\n",
3908 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
3909 (ctx
.MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
3910 (uint32_t) deltaTime
);
3913 //******************************************************************************
3916 //******************************************************************************
3918 IOReturn
IOPMrootDomain::shutdownSystem( void )
3920 return kIOReturnUnsupported
;
3923 //******************************************************************************
3926 //******************************************************************************
3928 IOReturn
IOPMrootDomain::restartSystem( void )
3930 return kIOReturnUnsupported
;
3934 // MARK: System Capability
3936 //******************************************************************************
3937 // tagPowerPlaneService
3939 // Running on PM work loop thread.
3940 //******************************************************************************
3942 void IOPMrootDomain::tagPowerPlaneService(
3943 IOService
* service
,
3944 IOPMActions
* actions
)
3947 bool isDisplayWrangler
;
3949 memset(actions
, 0, sizeof(*actions
));
3950 actions
->target
= this;
3952 if (service
== this)
3954 actions
->actionPowerChangeStart
=
3955 OSMemberFunctionCast(
3956 IOPMActionPowerChangeStart
, this,
3957 &IOPMrootDomain::handleOurPowerChangeStart
);
3959 actions
->actionPowerChangeDone
=
3960 OSMemberFunctionCast(
3961 IOPMActionPowerChangeDone
, this,
3962 &IOPMrootDomain::handleOurPowerChangeDone
);
3964 actions
->actionPowerChangeOverride
=
3965 OSMemberFunctionCast(
3966 IOPMActionPowerChangeOverride
, this,
3967 &IOPMrootDomain::overrideOurPowerChange
);
3972 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
3973 if (isDisplayWrangler
)
3976 wranglerConnection
= (IOService
*) service
->getParentEntry(gIOPowerPlane
);
3979 isDisplayWrangler
= false;
3982 #if defined(__i386__) || defined(__x86_64__)
3983 if (isDisplayWrangler
)
3984 flags
|= kPMActionsFlagIsDisplayWrangler
;
3985 if (service
->getProperty("IOPMStrictTreeOrder"))
3986 flags
|= kPMActionsFlagIsGraphicsDevice
;
3987 if (service
->getProperty("IOPMUnattendedWakePowerState"))
3988 flags
|= kPMActionsFlagIsAudioDevice
;
3991 // Find the power connection object that is a child of the PCI host
3992 // bridge, and has a graphics/audio device attached below. Mark the
3993 // power branch for delayed child notifications.
3997 IORegistryEntry
* child
= service
;
3998 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4000 while (child
!= this)
4002 if ((parent
== pciHostBridgeDriver
) ||
4005 if (OSDynamicCast(IOPowerConnection
, child
))
4007 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4008 conn
->delayChildNotification
= true;
4013 parent
= child
->getParentEntry(gIOPowerPlane
);
4019 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4020 actions
->parameter
|= flags
;
4021 actions
->actionPowerChangeOverride
=
4022 OSMemberFunctionCast(
4023 IOPMActionPowerChangeOverride
, this,
4024 &IOPMrootDomain::overridePowerChangeForUIService
);
4026 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4028 actions
->actionActivityTickle
=
4029 OSMemberFunctionCast(
4030 IOPMActionActivityTickle
, this,
4031 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4036 // Locate the first PCI host bridge for PMTrace.
4037 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4039 IOService
* provider
= service
->getProvider();
4040 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4041 provider
->inPlane(gIODTPlane
))
4043 pciHostBridgeDevice
= provider
;
4044 pciHostBridgeDriver
= service
;
4045 DLOG("PMTrace found PCI host bridge %s->%s\n",
4046 provider
->getName(), service
->getName());
4050 // Tag top-level PCI devices. The order of PMinit() call does not
4051 // change across boots and is used as the PCI bit number.
4052 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4054 // Would prefer to check built-in property, but tagPowerPlaneService()
4055 // is called before pciDevice->registerService().
4056 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4057 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4059 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4062 // Save the assigned bit for fast lookup.
4063 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4065 actions
->actionPowerChangeStart
=
4066 OSMemberFunctionCast(
4067 IOPMActionPowerChangeStart
, this,
4068 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4070 actions
->actionPowerChangeDone
=
4071 OSMemberFunctionCast(
4072 IOPMActionPowerChangeDone
, this,
4073 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4079 //******************************************************************************
4080 // PM actions for root domain
4081 //******************************************************************************
4083 void IOPMrootDomain::overrideOurPowerChange(
4084 IOService
* service
,
4085 IOPMActions
* actions
,
4086 unsigned long * inOutPowerState
,
4087 uint32_t * inOutChangeFlags
)
4089 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4090 uint32_t changeFlags
= *inOutChangeFlags
;
4091 uint32_t currentPowerState
= (uint32_t) getPowerState();
4093 if ((currentPowerState
== powerState
) ||
4094 (changeFlags
& kIOPMParentInitiated
))
4096 // FIXME: cancel any parent change (unexpected)
4097 // Root parent is permanently pegged at max power,
4098 // kIOPMParentInitiated is unexpected.
4102 if (powerState
< currentPowerState
)
4104 if ((changeFlags
& kIOPMSkipAskPowerDown
) == 0)
4106 /* Convenient place to run any code at idle sleep time
4107 * IOPMrootDomain initiates an idle sleep here
4109 * Set last sleep cause accordingly.
4111 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
4113 lastSleepReason
= kIOPMSleepReasonIdle
;
4114 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
4116 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4118 // Root domain is dropping power state ON->SLEEP.
4119 // If system is in full wake, first drop to dark wake.
4121 darkWakeToSleepASAP
= true;
4123 // Drop graphics capability.
4124 // No transition if system is already in dark wake.
4126 _desiredCapability
&= ~(
4127 kIOPMSystemCapabilityGraphics
|
4128 kIOPMSystemCapabilityAudio
);
4130 *inOutPowerState
= ON_STATE
;
4131 *inOutChangeFlags
|= kIOPMSynchronize
;
4133 // Revert device desire from SLEEP->ON.
4134 changePowerStateToPriv(ON_STATE
);
4139 void IOPMrootDomain::handleOurPowerChangeStart(
4140 IOService
* service
,
4141 IOPMActions
* actions
,
4142 uint32_t powerState
,
4143 uint32_t * inOutChangeFlags
)
4145 uint32_t changeFlags
= *inOutChangeFlags
;
4146 uint32_t currentPowerState
= (uint32_t) getPowerState();
4148 _systemTransitionType
= kSystemTransitionNone
;
4149 _systemMessageClientMask
= 0;
4150 capabilityLoss
= false;
4152 // 1. Explicit capability change.
4154 if (changeFlags
& kIOPMSynchronize
)
4156 if (powerState
== ON_STATE
)
4158 if (changeFlags
& kIOPMSyncNoChildNotify
)
4159 _systemTransitionType
= kSystemTransitionNewCapClient
;
4161 _systemTransitionType
= kSystemTransitionCapability
;
4165 // 2. Going to sleep (cancellation still possible).
4167 else if (powerState
< currentPowerState
)
4168 _systemTransitionType
= kSystemTransitionSleep
;
4170 // 3. Woke from (idle or demand) sleep.
4172 else if (!systemBooting
&&
4173 (changeFlags
& kIOPMSelfInitiated
) &&
4174 (powerState
> currentPowerState
))
4176 _systemTransitionType
= kSystemTransitionWake
;
4177 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4178 kIOPMSystemCapabilityNetwork
;
4180 // Check for early HID events (e.g. LID open)
4181 if (wranglerTickled
)
4183 _desiredCapability
|= (
4184 kIOPMSystemCapabilityGraphics
|
4185 kIOPMSystemCapabilityAudio
);
4189 // Update pending wake capability at the beginning of every
4190 // state transition (including synchronize). This will become
4191 // the current capability at the end of the transition.
4193 if (kSystemTransitionSleep
== _systemTransitionType
)
4195 _pendingCapability
= 0;
4196 capabilityLoss
= true;
4198 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4200 _pendingCapability
= _desiredCapability
|
4201 kIOPMSystemCapabilityCPU
|
4202 kIOPMSystemCapabilityNetwork
;
4204 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4205 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4207 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4208 (_pendingCapability
== _currentCapability
))
4210 // Cancel the PM state change.
4211 _systemTransitionType
= kSystemTransitionNone
;
4212 *inOutChangeFlags
|= kIOPMNotDone
;
4214 if (__builtin_popcount(_pendingCapability
) <
4215 __builtin_popcount(_currentCapability
))
4216 capabilityLoss
= true;
4217 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4218 rejectWranglerTickle
= true;
4221 // 1. Capability change.
4223 if (kSystemTransitionCapability
== _systemTransitionType
)
4225 // Dark to Full transition.
4226 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4228 tracePoint( kIOPMTracePointDarkWakeExit
);
4229 wranglerSleepIgnored
= false;
4230 sleepTimerMaintenance
= false;
4231 hibernateNoDefeat
= false;
4232 _systemMessageClientMask
= kSystemMessageClientUser
;
4233 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4234 _systemMessageClientMask
|= kSystemMessageClientKernel
;
4236 tellClients(kIOMessageSystemWillPowerOn
);
4239 // Full to Dark transition.
4240 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4242 tracePoint( kIOPMTracePointDarkWakeEntry
);
4243 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4244 _systemMessageClientMask
= kSystemMessageClientUser
;
4250 else if (kSystemTransitionSleep
== _systemTransitionType
)
4252 // Beginning of a system sleep transition.
4253 // Cancellation is still possible.
4254 tracePoint( kIOPMTracePointSleepStarted
, lastSleepReason
);
4256 _systemMessageClientMask
= kSystemMessageClientAll
;
4257 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4258 _systemMessageClientMask
&= ~kSystemMessageClientApp
;
4259 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4260 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4262 // Optimization to ignore wrangler power down thus skipping
4263 // the disk spindown and arming the idle timer for demand sleep.
4265 if (changeFlags
& kIOPMIgnoreChildren
)
4267 wranglerSleepIgnored
= true;
4270 logWranglerTickle
= false;
4275 else if (kSystemTransitionWake
== _systemTransitionType
)
4277 wranglerSleepIgnored
= false;
4279 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4281 _systemMessageClientMask
= kSystemMessageClientAll
;
4285 _systemMessageClientMask
= kSystemMessageClientConfigd
;
4288 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4289 tellClients(kIOMessageSystemWillPowerOn
);
4292 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4293 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4295 _systemStateGeneration
++;
4296 systemDarkWake
= false;
4298 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4300 currentPowerState
, powerState
, *inOutChangeFlags
,
4301 _systemTransitionType
, _systemStateGeneration
,
4302 _systemMessageClientMask
,
4303 _desiredCapability
, _currentCapability
, _pendingCapability
);
4307 void IOPMrootDomain::handleOurPowerChangeDone(
4308 IOService
* service
,
4309 IOPMActions
* actions
,
4310 uint32_t powerState
,
4311 uint32_t changeFlags
)
4313 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4315 _systemTransitionType
= kSystemTransitionNone
;
4319 if (_systemTransitionType
!= kSystemTransitionNone
)
4321 uint32_t currentPowerState
= (uint32_t) getPowerState();
4323 if (changeFlags
& kIOPMNotDone
)
4325 // Power down was cancelled or vetoed.
4326 _pendingCapability
= _currentCapability
;
4327 lastSleepReason
= 0;
4329 if (((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4330 (_currentCapability
& kIOPMSystemCapabilityCPU
))
4332 pmPowerStateQueue
->submitPowerEvent(
4333 kPowerEventPolicyStimulus
,
4334 (void *) kStimulusDarkWakeReentry
,
4335 _systemStateGeneration
);
4338 // Revert device desire to max.
4339 changePowerStateToPriv(ON_STATE
);
4343 // Send message on dark wake to full wake promotion.
4344 // tellChangeUp() handles the normal SLEEP->ON case.
4346 if (kSystemTransitionCapability
== _systemTransitionType
)
4348 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4350 tellClients(kIOMessageSystemHasPoweredOn
);
4351 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4352 // Re-evaluate clamshell state ourselves when graphics
4353 // will not get kIOMessageSystemHasPoweredOn.
4355 if (clamshellClosed
&&
4356 ((_systemMessageClientMask
& kSystemMessageClientKernel
) == 0))
4358 receivePowerNotification( kLocalEvalClamshellCommand
);
4362 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4363 wranglerTickled
= false;
4366 // Reset state after exiting from dark wake.
4368 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
4369 CAP_LOSS(kIOPMSystemCapabilityCPU
))
4371 darkWakeMaintenance
= false;
4372 darkWakeToSleepASAP
= false;
4373 pciCantSleepValid
= false;
4374 rejectWranglerTickle
= false;
4377 // Entered dark mode.
4379 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4380 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
4382 if (((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOInDark
) == 0) &&
4383 (kSystemTransitionWake
== _systemTransitionType
) &&
4384 (_lastDebugWakeSeconds
== 0))
4386 OSObject
* prop
= copyProperty(kIOPMRootDomainWakeTypeKey
);
4389 OSString
* wakeType
= OSDynamicCast(OSString
, prop
);
4391 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeNetwork
))
4393 // Woke from network and entered dark wake.
4394 if (darkWakeToSleepASAP
)
4396 DLOG("cleared darkWakeToSleepASAP\n");
4397 darkWakeToSleepASAP
= false;
4404 // Queue an evaluation of whether to remain in dark wake,
4405 // and for how long. This serves the purpose of draining
4406 // any assertions from the queue.
4408 pmPowerStateQueue
->submitPowerEvent(
4409 kPowerEventPolicyStimulus
,
4410 (void *) kStimulusDarkWakeEntry
,
4411 _systemStateGeneration
);
4415 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4416 "dcp %x:%x:%x, dbgtimer %u\n",
4417 currentPowerState
, powerState
, changeFlags
,
4418 _systemTransitionType
, _systemStateGeneration
,
4419 _systemMessageClientMask
,
4420 _desiredCapability
, _currentCapability
, _pendingCapability
,
4421 _lastDebugWakeSeconds
);
4423 // Update current system capability.
4425 if (_currentCapability
!= _pendingCapability
)
4426 _currentCapability
= _pendingCapability
;
4428 // Update highest system capability.
4430 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU
))
4431 _highestCapability
= 0; // reset at sleep state
4433 _highestCapability
|= _currentCapability
;
4435 if (darkWakePostTickle
&&
4436 (kSystemTransitionWake
== _systemTransitionType
) &&
4437 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4438 kDarkWakeFlagHIDTickleLate
)
4440 darkWakePostTickle
= false;
4444 // Reset tracepoint at completion of capability change,
4445 // completion of wake transition, and aborted sleep transition.
4447 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
4448 (_systemTransitionType
== kSystemTransitionWake
) ||
4449 ((_systemTransitionType
== kSystemTransitionSleep
) &&
4450 (changeFlags
& kIOPMNotDone
)))
4452 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
4453 tracePoint( kIOPMTracePointSystemUp
, 0 );
4456 _systemTransitionType
= kSystemTransitionNone
;
4457 _systemMessageClientMask
= 0;
4459 logGraphicsClamp
= false;
4463 //******************************************************************************
4464 // PM actions for graphics and audio.
4465 //******************************************************************************
4467 void IOPMrootDomain::overridePowerChangeForUIService(
4468 IOService
* service
,
4469 IOPMActions
* actions
,
4470 unsigned long * inOutPowerState
,
4471 uint32_t * inOutChangeFlags
)
4473 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4474 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
4476 if (kSystemTransitionNone
== _systemTransitionType
)
4478 // Not in midst of a system transition.
4479 // Do not modify power limit enable state.
4481 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4483 // Activate power limiter.
4485 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4486 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4488 actions
->parameter
|= kPMActionsFlagLimitPower
;
4490 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4491 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0))
4493 actions
->parameter
|= kPMActionsFlagLimitPower
;
4495 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
4496 (_systemTransitionType
== kSystemTransitionSleep
))
4498 // For graphics devices, arm the limiter when entering
4499 // system sleep. Not when dropping to dark wake.
4500 actions
->parameter
|= kPMActionsFlagLimitPower
;
4503 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4505 DLOG("+ plimit %s %p\n",
4506 service
->getName(), service
);
4511 // Remove power limit.
4513 if ((actions
->parameter
& (
4514 kPMActionsFlagIsDisplayWrangler
|
4515 kPMActionsFlagIsGraphicsDevice
)) &&
4516 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
4518 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4520 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4521 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
4523 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4526 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4528 DLOG("- plimit %s %p\n",
4529 service
->getName(), service
);
4533 if (gRAMDiskImageBoot
&&
4534 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
4536 // Tag devices subject to power suppression.
4537 *inOutChangeFlags
|= kIOPMPowerSuppressed
;
4540 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4542 uint32_t maxPowerState
= (uint32_t)(-1);
4544 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
4546 // Enforce limit for system power/cap transitions.
4549 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4550 (!gRAMDiskImageBoot
|| (service
->getPowerState() > 0)))
4552 // Forces a 3->1 transition sequence
4553 if (changeFlags
& kIOPMDomainWillChange
)
4561 // Deny all self-initiated changes when power is limited.
4562 // Wrangler tickle should never defeat the limiter.
4564 maxPowerState
= service
->getPowerState();
4567 if (powerState
> maxPowerState
)
4569 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4570 service
->getName(), service
, powerState
, maxPowerState
,
4572 *inOutPowerState
= maxPowerState
;
4574 if (darkWakePostTickle
&&
4575 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4576 (changeFlags
& kIOPMDomainWillChange
) &&
4577 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4578 kDarkWakeFlagHIDTickleEarly
))
4580 darkWakePostTickle
= false;
4585 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
4587 if (logGraphicsClamp
)
4592 clock_get_uptime(&now
);
4593 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
4594 absolutetime_to_nanoseconds(now
, &nsec
);
4595 MSG("Graphics suppressed %u ms\n",
4596 ((int)((nsec
) / 1000000ULL)));
4598 graphicsSuppressed
= true;
4603 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4604 IOService
* service
,
4605 IOPMActions
* actions
)
4607 // Warning: Not running in PM work loop context - don't modify state !!!
4608 // Trap tickle directed to IODisplayWrangler while running with graphics
4609 // capability suppressed.
4611 assert(service
== wrangler
);
4613 if (service
== wrangler
)
4615 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
4616 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
4618 userActivityCount
++;
4619 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
4623 if (!wranglerTickled
&& !lowBatteryCondition
&&
4624 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4626 DLOG("display wrangler tickled\n");
4627 if (kIOLogPMRootDomain
& gIOKitDebug
)
4628 OSReportWithBacktrace("Dark wake display tickle");
4629 if (pmPowerStateQueue
)
4631 pmPowerStateQueue
->submitPowerEvent(
4632 kPowerEventPolicyStimulus
,
4633 (void *) kStimulusDarkWakeActivityTickle
);
4638 //******************************************************************************
4639 // Approve usage of delayed child notification by PM.
4640 //******************************************************************************
4642 bool IOPMrootDomain::shouldDelayChildNotification(
4643 IOService
* service
)
4645 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
4647 (kSystemTransitionWake
== _systemTransitionType
))
4649 DLOG("%s: delay child notify\n", service
->getName());
4655 //******************************************************************************
4656 // PM actions for PCI device.
4657 //******************************************************************************
4659 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
4660 IOService
* service
,
4661 IOPMActions
* actions
,
4662 uint32_t powerState
,
4663 uint32_t * inOutChangeFlags
)
4665 pmTracer
->tracePCIPowerChange(
4666 PMTraceWorker::kPowerChangeStart
,
4667 service
, *inOutChangeFlags
,
4668 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
4671 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
4672 IOService
* service
,
4673 IOPMActions
* actions
,
4674 uint32_t powerState
,
4675 uint32_t changeFlags
)
4677 pmTracer
->tracePCIPowerChange(
4678 PMTraceWorker::kPowerChangeCompleted
,
4679 service
, changeFlags
,
4680 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
4683 //******************************************************************************
4686 // Override IOService::registerInterest() to intercept special clients.
4687 //******************************************************************************
4689 IONotifier
* IOPMrootDomain::registerInterest(
4690 const OSSymbol
* typeOfInterest
,
4691 IOServiceInterestHandler handler
,
4692 void * target
, void * ref
)
4694 IONotifier
* notifier
;
4695 bool isSystemCapabilityClient
;
4696 bool isKernelCapabilityClient
;
4698 isSystemCapabilityClient
=
4700 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
4702 isKernelCapabilityClient
=
4704 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
4706 if (isSystemCapabilityClient
)
4707 typeOfInterest
= gIOAppPowerStateInterest
;
4709 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
4710 if (notifier
&& pmPowerStateQueue
)
4712 if (isSystemCapabilityClient
)
4715 if (pmPowerStateQueue
->submitPowerEvent(
4716 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
4717 notifier
->release();
4720 if (isKernelCapabilityClient
)
4723 if (pmPowerStateQueue
->submitPowerEvent(
4724 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
4725 notifier
->release();
4732 //******************************************************************************
4733 // systemMessageFilter
4735 //******************************************************************************
4737 bool IOPMrootDomain::systemMessageFilter(
4738 void * object
, void * arg1
, void * arg2
, void * arg3
)
4740 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
4741 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
4742 bool isCapClient
= false;
4746 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
4747 (!isCapMsg
|| !_joinedCapabilityClients
||
4748 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
4751 // Capability change message for app and kernel clients.
4755 if ((context
->notifyType
== kNotifyPriority
) ||
4756 (context
->notifyType
== kNotifyCapabilityChangePriority
))
4759 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
4760 (object
== (void *) systemCapabilityNotifier
))
4766 IOPMSystemCapabilityChangeParameters
* capArgs
=
4767 (IOPMSystemCapabilityChangeParameters
*) arg2
;
4769 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4771 capArgs
->fromCapabilities
= 0;
4772 capArgs
->toCapabilities
= _currentCapability
;
4773 capArgs
->changeFlags
= 0;
4777 capArgs
->fromCapabilities
= _currentCapability
;
4778 capArgs
->toCapabilities
= _pendingCapability
;
4780 if (context
->isPreChange
)
4781 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
4783 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
4786 // Capability change messages only go to the PM configd plugin.
4787 // Wait for response post-change if capabilitiy is increasing.
4788 // Wait for response pre-change if capability is decreasing.
4790 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
4791 ( (capabilityLoss
&& context
->isPreChange
) ||
4792 (!capabilityLoss
&& !context
->isPreChange
) ) )
4794 // app has not replied yet, wait for it
4795 *((OSObject
**) arg3
) = kOSBooleanFalse
;
4802 // Capability client will always see kIOMessageCanSystemSleep,
4803 // even for demand sleep.
4805 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
4806 (kIOMessageSystemWillNotSleep
== context
->messageType
))
4808 if (object
== (OSObject
*) systemCapabilityNotifier
)
4814 // Not idle sleep, don't ask apps.
4815 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
4821 // Reject capability change messages for legacy clients.
4822 // Reject legacy system sleep messages for capability client.
4824 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
4829 // Filter system sleep messages.
4831 if ((context
->notifyType
== kNotifyApps
) &&
4832 (_systemMessageClientMask
& kSystemMessageClientApp
))
4836 else if ((context
->notifyType
== kNotifyPriority
) &&
4837 (_systemMessageClientMask
& kSystemMessageClientKernel
))
4844 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
4846 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
4847 if (_joinedCapabilityClients
->getCount() == 0)
4849 DLOG("destroyed capability client set %p\n",
4850 _joinedCapabilityClients
);
4851 _joinedCapabilityClients
->release();
4852 _joinedCapabilityClients
= 0;
4859 //******************************************************************************
4860 // setMaintenanceWakeCalendar
4862 //******************************************************************************
4864 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
4865 const IOPMCalendarStruct
* calendar
)
4871 return kIOReturnBadArgument
;
4873 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
4875 return kIOReturnNoMemory
;
4877 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
4878 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
4880 if (kPMCalendarTypeSleepService
== calendar
->selector
)
4882 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
4891 // MARK: Display Wrangler
4893 //******************************************************************************
4894 // displayWranglerNotification
4896 // Handle the notification when the IODisplayWrangler changes power state.
4897 //******************************************************************************
4899 IOReturn
IOPMrootDomain::displayWranglerNotification(
4900 void * target
, void * refCon
,
4901 UInt32 messageType
, IOService
* service
,
4902 void * messageArgument
, vm_size_t argSize
)
4905 int displayPowerState
;
4906 IOPowerStateChangeNotification
* params
=
4907 (IOPowerStateChangeNotification
*) messageArgument
;
4909 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
4910 (messageType
!= kIOMessageDeviceHasPoweredOn
))
4911 return kIOReturnUnsupported
;
4915 return kIOReturnUnsupported
;
4917 displayPowerState
= params
->stateNumber
;
4918 DLOG("DisplayWrangler message 0x%x, power state %d\n",
4919 (uint32_t) messageType
, displayPowerState
);
4921 switch (messageType
) {
4922 case kIOMessageDeviceWillPowerOff
:
4924 // Display wrangler has dropped power due to display idle
4925 // or force system sleep.
4930 // 1 Not visible to user
4931 // 0 Not visible to user
4933 if (displayPowerState
> 2)
4936 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
4939 case kIOMessageDeviceHasPoweredOn
:
4941 // Display wrangler has powered on due to user activity
4942 // or wake from sleep.
4944 if ( 4 != displayPowerState
)
4947 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
4951 return kIOReturnUnsupported
;
4954 //*********************************************************************************
4955 // displayWranglerMatchPublished
4957 // Receives a notification when the IODisplayWrangler is published.
4958 // When it's published we install a power state change handler.
4959 //******************************************************************************
4961 bool IOPMrootDomain::displayWranglerMatchPublished(
4964 IOService
* newService
,
4965 IONotifier
* notifier __unused
)
4968 // found the display wrangler, now install a handler
4969 if( !newService
->registerInterest( gIOGeneralInterest
,
4970 &displayWranglerNotification
, target
, 0) )
4978 //******************************************************************************
4981 //******************************************************************************
4983 void IOPMrootDomain::reportUserInput( void )
4990 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
4993 wrangler
= (IOService
*) iter
->getNextObject();
4999 wrangler
->activityTickle(0,0);
5006 //******************************************************************************
5009 // Notification on battery class IOPowerSource appearance
5010 //******************************************************************************
5012 bool IOPMrootDomain::batteryPublished(
5015 IOService
* resourceService
,
5016 IONotifier
* notifier __unused
)
5018 // rdar://2936060&4435589
5019 // All laptops have dimmable LCD displays
5020 // All laptops have batteries
5021 // So if this machine has a battery, publish the fact that the backlight
5022 // supports dimming.
5023 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
5029 // MARK: System PM Policy
5031 //******************************************************************************
5032 // checkSystemCanSleep
5034 //******************************************************************************
5036 bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options
)
5040 // Conditions that prevent idle and demand system sleep.
5043 if (userDisabledAllSleep
)
5045 err
= 1; // 1. user-space sleep kill switch
5049 if (systemBooting
|| systemShutdown
)
5051 err
= 2; // 2. restart or shutdown in progress
5058 // Conditions above pegs the system at full wake.
5059 // Conditions below prevent system sleep but does not prevent
5060 // dark wake, and must be called from gated context.
5063 err
= 3; // 3. config does not support sleep
5067 if (lowBatteryCondition
)
5069 break; // always sleep on low battery
5072 if (childPreventSystemSleep
)
5074 err
= 4; // 4. child prevent system sleep clamp
5078 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
5079 kIOPMDriverAssertionLevelOn
)
5081 err
= 5; // 5. CPU assertion
5085 if (pciCantSleepValid
)
5087 if (pciCantSleepFlag
)
5088 err
= 6; // 6. PCI card does not support PM (cached)
5091 else if (sleepSupportedPEFunction
&&
5092 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5095 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
5096 ret
= getPlatform()->callPlatformFunction(
5097 sleepSupportedPEFunction
, false,
5098 NULL
, NULL
, NULL
, NULL
);
5099 pciCantSleepValid
= true;
5100 pciCantSleepFlag
= false;
5101 if ((platformSleepSupport
& kPCICantSleep
) ||
5102 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
5104 err
= 6; // 6. PCI card does not support PM
5105 pciCantSleepFlag
= true;
5114 DLOG("System sleep prevented by %d\n", err
);
5120 //******************************************************************************
5123 // Conditions that affect our wake/sleep decision has changed.
5124 // If conditions dictate that the system must remain awake, clamp power
5125 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
5126 // is TRUE, then remove the power clamp and allow the power state to drop
5128 //******************************************************************************
5130 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
5132 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
5133 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
5137 if ((sleepSlider
== 0) || !checkSystemCanSleep())
5139 changePowerStateToPriv(ON_STATE
);
5141 else if ( sleepASAP
)
5143 changePowerStateToPriv(SLEEP_STATE
);
5147 //******************************************************************************
5148 // dispatchPowerEvent
5150 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
5151 //******************************************************************************
5153 void IOPMrootDomain::dispatchPowerEvent(
5154 uint32_t event
, void * arg0
, uint64_t arg1
)
5156 DLOG("power event %u args %p 0x%llx\n", event
, arg0
, arg1
);
5161 case kPowerEventFeatureChanged
:
5162 messageClients(kIOPMMessageFeatureChange
, this);
5165 case kPowerEventReceivedPowerNotification
:
5166 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
5169 case kPowerEventSystemBootCompleted
:
5172 systemBooting
= false;
5174 // If lid is closed, re-send lid closed notification
5175 // now that booting is complete.
5176 if ( clamshellClosed
)
5178 handlePowerNotification(kLocalEvalClamshellCommand
);
5180 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
5184 case kPowerEventSystemShutdown
:
5185 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
5187 /* We set systemShutdown = true during shutdown
5188 to prevent sleep at unexpected times while loginwindow is trying
5189 to shutdown apps and while the OS is trying to transition to
5192 Set to true during shutdown, as soon as loginwindow shows
5193 the "shutdown countdown dialog", through individual app
5194 termination, and through black screen kernel shutdown.
5196 systemShutdown
= true;
5199 A shutdown was initiated, but then the shutdown
5200 was cancelled, clearing systemShutdown to false here.
5202 systemShutdown
= false;
5206 case kPowerEventUserDisabledSleep
:
5207 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
5210 case kPowerEventRegisterSystemCapabilityClient
:
5211 if (systemCapabilityNotifier
)
5213 systemCapabilityNotifier
->release();
5214 systemCapabilityNotifier
= 0;
5218 systemCapabilityNotifier
= (IONotifier
*) arg0
;
5219 systemCapabilityNotifier
->retain();
5221 /* intentional fall-through */
5223 case kPowerEventRegisterKernelCapabilityClient
:
5224 if (!_joinedCapabilityClients
)
5225 _joinedCapabilityClients
= OSSet::withCapacity(8);
5228 IONotifier
* notify
= (IONotifier
*) arg0
;
5229 if (_joinedCapabilityClients
)
5231 _joinedCapabilityClients
->setObject(notify
);
5232 synchronizePowerTree( kIOPMSyncNoChildNotify
);
5238 case kPowerEventPolicyStimulus
:
5241 int stimulus
= (uintptr_t) arg0
;
5242 evaluatePolicy( stimulus
, (uint32_t) arg1
);
5246 case kPowerEventAssertionCreate
:
5248 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
5253 case kPowerEventAssertionRelease
:
5255 pmAssertions
->handleReleaseAssertion(arg1
);
5259 case kPowerEventAssertionSetLevel
:
5261 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
5265 case kPowerEventQueueSleepWakeUUID
:
5266 handleQueueSleepWakeUUID((OSObject
*)arg0
);
5268 case kPowerEventPublishSleepWakeUUID
:
5269 handlePublishSleepWakeUUID((bool)arg0
);
5274 //******************************************************************************
5275 // systemPowerEventOccurred
5277 // The power controller is notifying us of a hardware-related power management
5278 // event that we must handle.
5280 // systemPowerEventOccurred covers the same functionality that
5281 // receivePowerNotification does; it simply provides a richer API for conveying
5282 // more information.
5283 //******************************************************************************
5285 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5286 const OSSymbol
*event
,
5289 IOReturn attempt
= kIOReturnSuccess
;
5290 OSNumber
*newNumber
= NULL
;
5293 return kIOReturnBadArgument
;
5295 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
5297 return kIOReturnInternalError
;
5299 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
5301 newNumber
->release();
5306 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5307 const OSSymbol
*event
,
5310 OSDictionary
*thermalsDict
= NULL
;
5311 bool shouldUpdate
= true;
5313 if (!event
|| !value
)
5314 return kIOReturnBadArgument
;
5317 // We reuse featuresDict Lock because it already exists and guards
5318 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5319 // of stepping on that lock.
5320 if (featuresDictLock
) IOLockLock(featuresDictLock
);
5322 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
5324 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
5325 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
5327 thermalsDict
= OSDictionary::withCapacity(1);
5330 if (!thermalsDict
) {
5331 shouldUpdate
= false;
5335 thermalsDict
->setObject (event
, value
);
5337 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
5339 thermalsDict
->release();
5343 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
5346 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
5348 return kIOReturnSuccess
;
5351 //******************************************************************************
5352 // receivePowerNotification
5354 // The power controller is notifying us of a hardware-related power management
5355 // event that we must handle. This may be a result of an 'environment' interrupt
5356 // from the power mgt micro.
5357 //******************************************************************************
5359 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
5361 pmPowerStateQueue
->submitPowerEvent(
5362 kPowerEventReceivedPowerNotification
, (void *) msg
);
5363 return kIOReturnSuccess
;
5366 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
5368 bool eval_clamshell
= false;
5373 * Local (IOPMrootDomain only) eval clamshell command
5375 if (msg
& kLocalEvalClamshellCommand
)
5377 eval_clamshell
= true;
5383 if (msg
& kIOPMOverTemp
)
5385 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
5386 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
5392 if (msg
& kIOPMSleepNow
)
5394 privateSleepSystem (kIOPMSleepReasonSoftware
);
5400 if (msg
& kIOPMPowerEmergency
)
5402 lowBatteryCondition
= true;
5403 privateSleepSystem (kIOPMSleepReasonLowPower
);
5409 if (msg
& kIOPMClamshellOpened
)
5411 // Received clamshel open message from clamshell controlling driver
5412 // Update our internal state and tell general interest clients
5413 clamshellClosed
= false;
5414 clamshellExists
= true;
5416 if (msg
& kIOPMSetValue
)
5422 informCPUStateChange(kInformLid
, 0);
5424 // Tell general interest clients
5425 sendClientClamshellNotification();
5427 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
5428 || (lastSleepReason
== kIOPMSleepReasonIdle
)
5429 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
5430 if (aborting
) userActivityCount
++;
5431 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
5436 * Send the clamshell interest notification since the lid is closing.
5438 if (msg
& kIOPMClamshellClosed
)
5440 // Received clamshel open message from clamshell controlling driver
5441 // Update our internal state and tell general interest clients
5442 clamshellClosed
= true;
5443 clamshellExists
= true;
5446 informCPUStateChange(kInformLid
, 1);
5448 // Tell general interest clients
5449 sendClientClamshellNotification();
5451 // And set eval_clamshell = so we can attempt
5452 eval_clamshell
= true;
5456 * Set Desktop mode (sent from graphics)
5458 * -> reevaluate lid state
5460 if (msg
& kIOPMSetDesktopMode
)
5462 desktopMode
= (0 != (msg
& kIOPMSetValue
));
5463 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
5465 sendClientClamshellNotification();
5467 // Re-evaluate the lid state
5468 if( clamshellClosed
)
5470 eval_clamshell
= true;
5475 * AC Adaptor connected
5477 * -> reevaluate lid state
5479 if (msg
& kIOPMSetACAdaptorConnected
)
5481 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
5482 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
5485 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
5487 // Tell BSD if AC is connected
5488 // 0 == external power source; 1 == on battery
5489 post_sys_powersource(acAdaptorConnected
? 0:1);
5491 sendClientClamshellNotification();
5493 // Re-evaluate the lid state
5494 if( clamshellClosed
)
5496 eval_clamshell
= true;
5501 * Enable Clamshell (external display disappear)
5503 * -> reevaluate lid state
5505 if (msg
& kIOPMEnableClamshell
)
5507 // Re-evaluate the lid state
5508 // System should sleep on external display disappearance
5509 // in lid closed operation.
5510 if( clamshellClosed
&& (true == clamshellDisabled
) )
5512 eval_clamshell
= true;
5515 clamshellDisabled
= false;
5517 sendClientClamshellNotification();
5521 * Disable Clamshell (external display appeared)
5522 * We don't bother re-evaluating clamshell state. If the system is awake,
5523 * the lid is probably open.
5525 if (msg
& kIOPMDisableClamshell
)
5527 clamshellDisabled
= true;
5529 sendClientClamshellNotification();
5533 * Evaluate clamshell and SLEEP if appropiate
5535 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
5540 privateSleepSystem (kIOPMSleepReasonClamshell
);
5542 else if ( eval_clamshell
)
5544 evaluatePolicy(kStimulusDarkWakeEvaluate
);
5550 if (msg
& kIOPMPowerButton
)
5552 if (!wranglerAsleep
)
5554 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
5555 // Check that power button sleep is enabled
5557 if( kOSBooleanTrue
!= getProperty(pbs
))
5558 privateSleepSystem (kIOPMSleepReasonPowerButton
);
5566 //******************************************************************************
5569 // Evaluate root-domain policy in response to external changes.
5570 //******************************************************************************
5572 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
5576 int idleSleepEnabled
: 1;
5577 int idleSleepDisabled
: 1;
5578 int displaySleep
: 1;
5579 int sleepDelayChanged
: 1;
5580 int evaluateDarkWake
: 1;
5585 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
5592 case kStimulusDisplayWranglerSleep
:
5593 if (!wranglerAsleep
)
5595 wranglerAsleep
= true;
5596 clock_get_uptime(&wranglerSleepTime
);
5597 flags
.bit
.displaySleep
= true;
5601 case kStimulusDisplayWranglerWake
:
5602 wranglerAsleep
= false;
5603 flags
.bit
.idleSleepDisabled
= true;
5606 case kStimulusAggressivenessChanged
:
5608 unsigned long minutesToIdleSleep
= 0;
5609 unsigned long minutesToDisplayDim
= 0;
5610 unsigned long minutesDelta
= 0;
5612 // Fetch latest display and system sleep slider values.
5613 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
5614 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
5615 DLOG("aggressiveness changed: system %u->%u, display %u\n",
5616 (uint32_t) sleepSlider
,
5617 (uint32_t) minutesToIdleSleep
,
5618 (uint32_t) minutesToDisplayDim
);
5620 DLOG("idle time -> %ld secs (ena %d)\n",
5621 idleSeconds
, (minutesToIdleSleep
!= 0));
5623 if (0x7fffffff == minutesToIdleSleep
)
5624 minutesToIdleSleep
= idleSeconds
;
5626 // How long to wait before sleeping the system once
5627 // the displays turns off is indicated by 'extraSleepDelay'.
5629 if ( minutesToIdleSleep
> minutesToDisplayDim
)
5630 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
5632 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
5633 flags
.bit
.idleSleepEnabled
= true;
5635 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
5636 flags
.bit
.idleSleepDisabled
= true;
5638 if ((minutesDelta
!= extraSleepDelay
) &&
5639 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
5640 flags
.bit
.sleepDelayChanged
= true;
5642 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
5643 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
5645 // Reconsider decision to remain in dark wake
5646 flags
.bit
.evaluateDarkWake
= true;
5649 sleepSlider
= minutesToIdleSleep
;
5650 extraSleepDelay
= minutesDelta
;
5653 case kStimulusDemandSystemSleep
:
5654 changePowerStateWithOverrideTo( SLEEP_STATE
);
5657 case kStimulusAllowSystemSleepChanged
:
5658 // FIXME: de-compose to change flags.
5662 case kStimulusDarkWakeActivityTickle
:
5663 if (false == wranglerTickled
)
5665 uint32_t options
= 0;
5666 IOService
* pciRoot
= 0;
5668 if (rejectWranglerTickle
)
5670 DLOG("rejected tickle, type %u capability %x:%x\n",
5671 _systemTransitionType
,
5672 _currentCapability
, _pendingCapability
);
5676 _desiredCapability
|=
5677 (kIOPMSystemCapabilityGraphics
|
5678 kIOPMSystemCapabilityAudio
);
5680 if ((kSystemTransitionWake
== _systemTransitionType
) &&
5681 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5682 !graphicsSuppressed
)
5684 DLOG("Promoting to full wake\n");
5686 // Elevate to full wake while waking up to dark wake.
5687 // PM will hold off notifying the graphics subsystem about
5688 // system wake as late as possible, so if a HID event does
5689 // arrive, we can turn on graphics on this wake cycle, and
5690 // not have to wait till the following cycle. That latency
5691 // can be huge on some systems. However, once any graphics
5692 // suppression has taken effect, it is too late. All other
5693 // graphics devices must be similarly suppressed. But the
5694 // delay till the following cycle should be very short.
5696 _pendingCapability
|=
5697 (kIOPMSystemCapabilityGraphics
|
5698 kIOPMSystemCapabilityAudio
);
5700 // Immediately bring up audio and graphics.
5701 pciRoot
= pciHostBridgeDriver
;
5703 // Notify clients about full wake.
5704 _systemMessageClientMask
= kSystemMessageClientAll
;
5705 tellClients(kIOMessageSystemWillPowerOn
);
5708 // Unsafe to cancel once graphics was powered.
5709 // If system woke from dark wake, the return to sleep can
5710 // be cancelled. But "awake -> dark -> sleep" transition
5711 // cannot be cancelled.
5713 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
5714 options
|= kIOPMSyncCancelPowerDown
;
5717 synchronizePowerTree( options
, pciRoot
);
5718 wranglerTickled
= true;
5719 // IOGraphics doesn't lit the display even though graphics
5720 // is enanbled in kIOMessageSystemCapabilityChange message(radar 9502104)
5721 // So, do an explicit activity tickle
5723 wrangler
->activityTickle(0,0);
5725 if (logWranglerTickle
)
5730 clock_get_uptime(&now
);
5731 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
5732 absolutetime_to_nanoseconds(now
, &nsec
);
5733 MSG("HID tickle %u ms\n",
5734 ((int)((nsec
) / 1000000ULL)));
5735 logWranglerTickle
= false;
5740 case kStimulusDarkWakeEntry
:
5741 case kStimulusDarkWakeReentry
:
5742 // Any system transitions since the last dark wake transition
5743 // will invalid the stimulus.
5745 if (arg
== _systemStateGeneration
)
5747 DLOG("dark wake entry\n");
5748 systemDarkWake
= true;
5749 wranglerAsleep
= true;
5750 clock_get_uptime(&wranglerSleepTime
);
5752 // Always accelerate disk spindown while in dark wake,
5753 // even if system does not support/allow sleep.
5755 cancelIdleSleepTimer();
5756 setQuickSpinDownTimeout();
5757 flags
.bit
.evaluateDarkWake
= true;
5761 case kStimulusDarkWakeEvaluate
:
5764 flags
.bit
.evaluateDarkWake
= true;
5766 #if !DARK_TO_FULL_EVALUATE_CLAMSHELL
5769 // Not through kLocalEvalClamshellCommand to avoid loop.
5770 if (clamshellClosed
&& shouldSleepOnClamshellClosed() &&
5771 checkSystemCanSleep(true))
5773 privateSleepSystem( kIOPMSleepReasonClamshell
);
5779 } /* switch(stimulus) */
5781 if (flags
.bit
.evaluateDarkWake
&& !wranglerTickled
)
5783 if (darkWakeToSleepASAP
||
5784 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
5786 // System currently in dark wake, and no children and
5787 // assertion prevent system sleep.
5789 if (checkSystemCanSleep(true))
5791 if (lowBatteryCondition
)
5793 lastSleepReason
= kIOPMSleepReasonLowPower
;
5794 setProperty(kRootDomainSleepReasonKey
, kIOPMLowPowerSleepKey
);
5796 else if (darkWakeMaintenance
)
5798 lastSleepReason
= kIOPMSleepReasonMaintenance
;
5799 setProperty(kRootDomainSleepReasonKey
, kIOPMMaintenanceSleepKey
);
5801 else if (darkWakeSleepService
)
5803 lastSleepReason
= kIOPMSleepReasonSleepServiceExit
;
5804 setProperty(kRootDomainSleepReasonKey
, kIOPMSleepServiceExitKey
);
5806 changePowerStateWithOverrideTo( SLEEP_STATE
);
5810 // Parked in dark wake, a tickle will return to full wake
5811 rejectWranglerTickle
= false;
5813 } else // non-maintenance (network) dark wake
5815 if (checkSystemCanSleep(true))
5817 // Release power clamp, and wait for children idle.
5818 adjustPowerState(true);
5822 changePowerStateToPriv(ON_STATE
);
5824 rejectWranglerTickle
= false;
5830 // The rest are irrelevant while system is in dark wake.
5834 if (flags
.bit
.displaySleep
|| flags
.bit
.sleepDelayChanged
)
5836 bool cancelQuickSpindown
= false;
5838 if (flags
.bit
.sleepDelayChanged
)
5840 DLOG("extra sleep timer changed\n");
5841 cancelIdleSleepTimer();
5842 cancelQuickSpindown
= true;
5846 DLOG("display sleep\n");
5849 if (wranglerAsleep
&& !wranglerSleepIgnored
)
5851 if ( extraSleepDelay
)
5853 // Start a timer here if the System Sleep timer is greater
5854 // than the Display Sleep timer.
5856 startIdleSleepTimer(gRootDomain
->extraSleepDelay
* 60);
5858 else if ( sleepSlider
)
5860 // Accelerate disk spindown if system sleep and display sleep
5861 // sliders are set to the same value (e.g. both set to 5 min),
5862 // and display is about to go dark. Check the system sleep is
5863 // not set to never sleep. Disk sleep setting is ignored.
5865 setQuickSpinDownTimeout();
5866 cancelQuickSpindown
= false;
5870 if (cancelQuickSpindown
)
5871 restoreUserSpinDownTimeout();
5874 if (flags
.bit
.idleSleepEnabled
)
5876 DLOG("idle sleep timer enabled\n");
5879 changePowerStateToPriv(ON_STATE
);
5882 startIdleSleepTimer( idleSeconds
);
5887 // Start idle sleep timer if wrangler went to sleep
5888 // while system sleep was disabled. Disk spindown is
5889 // accelerated upon timer expiration.
5895 uint32_t minutesSinceDisplaySleep
= 0;
5896 uint32_t sleepDelay
;
5898 clock_get_uptime(&now
);
5899 if (CMP_ABSOLUTETIME(&now
, &wranglerSleepTime
) > 0)
5901 SUB_ABSOLUTETIME(&now
, &wranglerSleepTime
);
5902 absolutetime_to_nanoseconds(now
, &nanos
);
5903 minutesSinceDisplaySleep
= nanos
/ (60000000000ULL);
5906 if (extraSleepDelay
> minutesSinceDisplaySleep
)
5908 sleepDelay
= extraSleepDelay
- minutesSinceDisplaySleep
;
5912 sleepDelay
= 1; // 1 min
5915 startIdleSleepTimer(sleepDelay
* 60);
5916 DLOG("display slept %u min, set idle timer to %u min\n",
5917 minutesSinceDisplaySleep
, sleepDelay
);
5922 if (flags
.bit
.idleSleepDisabled
)
5924 DLOG("idle sleep timer disabled\n");
5925 cancelIdleSleepTimer();
5926 restoreUserSpinDownTimeout();
5931 //******************************************************************************
5932 // evaluateAssertions
5934 //******************************************************************************
5935 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
5937 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
5939 messageClients(kIOPMMessageDriverAssertionsChanged
);
5941 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
5944 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
5946 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
5947 wrangler
->setIgnoreIdleTimer( value
);
5950 if (changedBits
& kIOPMDriverAssertionCPUBit
)
5951 evaluatePolicy(kStimulusDarkWakeEvaluate
);
5959 //******************************************************************************
5962 //******************************************************************************
5964 void IOPMrootDomain::pmStatsRecordEvent(
5966 AbsoluteTime timestamp
)
5968 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
5969 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
5973 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
5975 absolutetime_to_nanoseconds(timestamp
, &nsec
);
5977 switch (eventIndex
) {
5978 case kIOPMStatsHibernateImageWrite
:
5980 pmStats
.hibWrite
.start
= nsec
;
5982 pmStats
.hibWrite
.stop
= nsec
;
5985 delta
= pmStats
.hibWrite
.stop
- pmStats
.hibWrite
.start
;
5986 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
5989 case kIOPMStatsHibernateImageRead
:
5991 pmStats
.hibRead
.start
= nsec
;
5993 pmStats
.hibRead
.stop
= nsec
;
5996 delta
= pmStats
.hibRead
.stop
- pmStats
.hibRead
.start
;
5997 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
6004 * Appends a record of the application response to
6005 * IOPMrootDomain::pmStatsAppResponses
6007 void IOPMrootDomain::pmStatsRecordApplicationResponse(
6008 const OSSymbol
*response
,
6014 OSDictionary
*responseDescription
= NULL
;
6015 OSNumber
*delayNum
= NULL
;
6016 OSNumber
*pidNum
= NULL
;
6017 OSNumber
*msgNum
= NULL
;
6018 const OSSymbol
*appname
;
6019 const OSSymbol
*entryName
;
6020 OSObject
*entryType
;
6023 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
6027 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
6029 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
6030 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
6031 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
))
6033 OSNumber
* entryValue
;
6034 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
6035 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
6036 entryValue
->setValue(delay_ms
);
6041 responseDescription
= OSDictionary::withCapacity(5);
6042 if (responseDescription
)
6045 responseDescription
->setObject(_statsResponseTypeKey
, response
);
6048 if (messageType
!= 0) {
6049 msgNum
= OSNumber::withNumber(messageType
, 32);
6051 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
6056 if (name
&& (strlen(name
) > 0))
6058 appname
= OSSymbol::withCString(name
);
6060 responseDescription
->setObject(_statsNameKey
, appname
);
6065 if (app_pid
!= -1) {
6066 pidNum
= OSNumber::withNumber(app_pid
, 32);
6068 responseDescription
->setObject(_statsPIDKey
, pidNum
);
6073 delayNum
= OSNumber::withNumber(delay_ms
, 32);
6075 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
6076 delayNum
->release();
6079 if (pmStatsAppResponses
) {
6080 pmStatsAppResponses
->setObject(responseDescription
);
6083 responseDescription
->release();
6089 // MARK: PMTraceWorker
6091 //******************************************************************************
6092 // TracePoint support
6094 //******************************************************************************
6096 #define kIOPMRegisterNVRAMTracePointHandlerKey \
6097 "IOPMRegisterNVRAMTracePointHandler"
6099 IOReturn
IOPMrootDomain::callPlatformFunction(
6100 const OSSymbol
* functionName
,
6101 bool waitForFunction
,
6102 void * param1
, void * param2
,
6103 void * param3
, void * param4
)
6105 if (pmTracer
&& functionName
&&
6106 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
6107 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
6109 uint32_t tracePointPhases
, tracePointPCI
;
6110 uint64_t statusCode
;
6112 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
6113 pmTracer
->tracePointTarget
= (void *) param2
;
6114 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
6115 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
6116 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
6117 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
6119 MSG("Sleep failure code 0x%08x 0x%08x\n",
6120 tracePointPCI
, tracePointPhases
);
6122 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
6123 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
6125 return kIOReturnSuccess
;
6127 else if (functionName
&&
6128 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
6130 if (_sleepPolicyHandler
)
6131 return kIOReturnExclusiveAccess
;
6133 return kIOReturnBadArgument
;
6134 _sleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
6135 _sleepPolicyTarget
= (void *) param2
;
6136 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
6137 return kIOReturnSuccess
;
6140 return super::callPlatformFunction(
6141 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
6144 void IOPMrootDomain::tracePoint( uint8_t point
)
6147 pmTracer
->tracePoint(point
);
6150 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
6153 pmTracer
->tracePoint(point
, data
);
6156 void IOPMrootDomain::traceDetail( uint32_t detail
)
6159 pmTracer
->traceDetail( detail
);
6162 //******************************************************************************
6163 // PMTraceWorker Class
6165 //******************************************************************************
6168 #define super OSObject
6169 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
6171 #define kPMBestGuessPCIDevicesCount 25
6172 #define kPMMaxRTCBitfieldSize 32
6174 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
6178 me
= OSTypeAlloc( PMTraceWorker
);
6179 if (!me
|| !me
->init())
6184 DLOG("PMTraceWorker %p\n", me
);
6186 // Note that we cannot instantiate the PCI device -> bit mappings here, since
6187 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
6188 // this dictionary lazily.
6190 me
->pciDeviceBitMappings
= NULL
;
6191 me
->pciMappingLock
= IOLockAlloc();
6192 me
->tracePhase
= kIOPMTracePointSystemUp
;
6193 me
->loginWindowPhase
= 0;
6194 me
->traceData32
= 0;
6198 void PMTraceWorker::RTC_TRACE(void)
6200 if (tracePointHandler
&& tracePointTarget
)
6204 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
6207 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
6208 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
6212 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
6214 const OSSymbol
* deviceName
;
6217 IOLockLock(pciMappingLock
);
6219 if (!pciDeviceBitMappings
)
6221 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
6222 if (!pciDeviceBitMappings
)
6226 // Check for bitmask overflow.
6227 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
6230 if ((deviceName
= pciDevice
->copyName()) &&
6231 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
6232 pciDeviceBitMappings
->setObject(deviceName
))
6234 index
= pciDeviceBitMappings
->getCount() - 1;
6235 _LOG("PMTrace PCI array: set object %s => %d\n",
6236 deviceName
->getCStringNoCopy(), index
);
6239 deviceName
->release();
6240 if (!addedToRegistry
&& (index
>= 0))
6241 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
6244 IOLockUnlock(pciMappingLock
);
6248 bool PMTraceWorker::serialize(OSSerialize
*s
) const
6251 if (pciDeviceBitMappings
)
6253 IOLockLock(pciMappingLock
);
6254 ok
= pciDeviceBitMappings
->serialize(s
);
6255 IOLockUnlock(pciMappingLock
);
6260 void PMTraceWorker::tracePoint(uint8_t phase
)
6262 // clear trace detail when phase begins
6263 if (tracePhase
!= phase
)
6268 DLOG("trace point 0x%02x\n", tracePhase
);
6272 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
6274 // clear trace detail when phase begins
6275 if (tracePhase
!= phase
)
6281 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
6285 void PMTraceWorker::traceDetail(uint32_t detail
)
6287 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
6290 traceData32
= detail
;
6291 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
6296 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
6298 loginWindowPhase
= phase
;
6300 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
6304 void PMTraceWorker::tracePCIPowerChange(
6305 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
6308 uint32_t expectedFlag
;
6310 // Ignore PCI changes outside of system sleep/wake.
6311 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
6312 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
6315 // Only record the WillChange transition when going to sleep,
6316 // and the DidChange on the way up.
6317 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
6318 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
6319 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
6320 if (changeFlags
!= expectedFlag
)
6323 // Mark this device off in our bitfield
6324 if (bitNum
< kPMMaxRTCBitfieldSize
)
6326 bitMask
= (1 << bitNum
);
6328 if (kPowerChangeStart
== type
)
6330 traceData32
|= bitMask
;
6331 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
6332 service
->getName(), bitNum
, bitMask
, traceData32
);
6336 traceData32
&= ~bitMask
;
6337 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
6338 service
->getName(), bitNum
, bitMask
, traceData32
);
6346 // MARK: PMHaltWorker
6348 //******************************************************************************
6349 // PMHaltWorker Class
6351 //******************************************************************************
6353 static unsigned int gPMHaltBusyCount
;
6354 static unsigned int gPMHaltIdleCount
;
6355 static int gPMHaltDepth
;
6356 static unsigned long gPMHaltEvent
;
6357 static IOLock
* gPMHaltLock
= 0;
6358 static OSArray
* gPMHaltArray
= 0;
6359 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
6361 PMHaltWorker
* PMHaltWorker::worker( void )
6367 me
= OSTypeAlloc( PMHaltWorker
);
6368 if (!me
|| !me
->init())
6371 me
->lock
= IOLockAlloc();
6375 DLOG("PMHaltWorker %p\n", me
);
6376 me
->retain(); // thread holds extra retain
6377 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
6382 thread_deallocate(thread
);
6387 if (me
) me
->release();
6391 void PMHaltWorker::free( void )
6393 DLOG("PMHaltWorker free %p\n", this);
6399 return OSObject::free();
6402 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
6404 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
6406 IOLockLock( gPMHaltLock
);
6408 me
->depth
= gPMHaltDepth
;
6409 IOLockUnlock( gPMHaltLock
);
6411 while (me
->depth
>= 0)
6413 PMHaltWorker::work( me
);
6415 IOLockLock( gPMHaltLock
);
6416 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
6418 // This is the last thread to finish work on this level,
6419 // inform everyone to start working on next lower level.
6421 me
->depth
= gPMHaltDepth
;
6422 gPMHaltIdleCount
= 0;
6423 thread_wakeup((event_t
) &gPMHaltIdleCount
);
6427 // One or more threads are still working on this level,
6428 // this thread must wait.
6429 me
->depth
= gPMHaltDepth
- 1;
6431 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
6432 } while (me
->depth
!= gPMHaltDepth
);
6434 IOLockUnlock( gPMHaltLock
);
6437 // No more work to do, terminate thread
6438 DLOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
6439 thread_wakeup( &gPMHaltDepth
);
6443 void PMHaltWorker::work( PMHaltWorker
* me
)
6445 IOService
* service
;
6447 AbsoluteTime startTime
;
6456 // Claim an unit of work from the shared pool
6457 IOLockLock( gPMHaltLock
);
6458 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
6461 service
= (IOService
*)inner
->getAnyObject();
6465 inner
->removeObject(service
);
6468 IOLockUnlock( gPMHaltLock
);
6470 break; // no more work at this depth
6472 clock_get_uptime(&startTime
);
6474 if (!service
->isInactive() &&
6475 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
6477 IOLockLock(me
->lock
);
6478 me
->startTime
= startTime
;
6479 me
->service
= service
;
6480 me
->timeout
= false;
6481 IOLockUnlock(me
->lock
);
6483 service
->systemWillShutdown( gPMHaltEvent
);
6485 // Wait for driver acknowledgement
6486 IOLockLock(me
->lock
);
6487 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
6489 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
6492 timeout
= me
->timeout
;
6493 IOLockUnlock(me
->lock
);
6496 deltaTime
= computeDeltaTimeMS(&startTime
);
6497 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
6498 (gIOKitDebug
& kIOLogPMRootDomain
))
6500 LOG("%s driver %s (%p) took %u ms\n",
6501 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
6502 "PowerOff" : "Restart",
6503 service
->getName(), service
,
6504 (uint32_t) deltaTime
);
6512 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
6515 AbsoluteTime startTime
;
6516 AbsoluteTime endTime
;
6520 IOLockLock(me
->lock
);
6521 if (me
->service
&& !me
->timeout
)
6523 startTime
= me
->startTime
;
6525 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
6527 SUB_ABSOLUTETIME(&endTime
, &startTime
);
6528 absolutetime_to_nanoseconds(endTime
, &nano
);
6530 if (nano
> 3000000000ULL)
6533 MSG("%s still waiting on %s\n",
6534 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
6535 "PowerOff" : "Restart",
6536 me
->service
->getName());
6539 IOLockUnlock(me
->lock
);
6543 //******************************************************************************
6544 // acknowledgeSystemWillShutdown
6546 // Acknowledgement from drivers that they have prepared for shutdown/restart.
6547 //******************************************************************************
6549 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
6551 PMHaltWorker
* worker
;
6557 //DLOG("%s acknowledged\n", from->getName());
6558 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
6561 worker
= (PMHaltWorker
*) prop
;
6562 IOLockLock(worker
->lock
);
6563 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
6564 thread_wakeup((event_t
) worker
);
6565 IOLockUnlock(worker
->lock
);
6570 DLOG("%s acknowledged without worker property\n",
6576 //******************************************************************************
6577 // notifySystemShutdown
6579 // Notify all objects in PM tree that system will shutdown or restart
6580 //******************************************************************************
6583 notifySystemShutdown( IOService
* root
, unsigned long event
)
6585 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
6586 IORegistryIterator
* iter
;
6587 IORegistryEntry
* entry
;
6590 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
6591 AbsoluteTime deadline
;
6592 unsigned int totalNodes
= 0;
6594 unsigned int rootDepth
;
6595 unsigned int numWorkers
;
6601 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
6603 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
6605 // Iterate the entire PM tree starting from root
6607 rootDepth
= root
->getDepth( gIOPowerPlane
);
6608 if (!rootDepth
) goto done
;
6610 // debug - for repeated test runs
6611 while (PMHaltWorker::metaClass
->getInstanceCount())
6616 gPMHaltArray
= OSArray::withCapacity(40);
6617 if (!gPMHaltArray
) goto done
;
6620 gPMHaltArray
->flushCollection();
6624 gPMHaltLock
= IOLockAlloc();
6625 if (!gPMHaltLock
) goto done
;
6628 if (!gPMHaltClientAcknowledgeKey
)
6630 gPMHaltClientAcknowledgeKey
=
6631 OSSymbol::withCStringNoCopy("PMShutdown");
6632 if (!gPMHaltClientAcknowledgeKey
) goto done
;
6635 gPMHaltEvent
= event
;
6637 // Depth-first walk of PM plane
6639 iter
= IORegistryIterator::iterateOver(
6640 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
6644 while ((entry
= iter
->getNextObject()))
6646 node
= OSDynamicCast(IOService
, entry
);
6651 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
6654 depth
= node
->getDepth( gIOPowerPlane
);
6655 if (depth
<= rootDepth
)
6660 // adjust to zero based depth
6661 depth
-= (rootDepth
+ 1);
6663 // gPMHaltArray is an array of containers, each container
6664 // refers to nodes with the same depth.
6666 count
= gPMHaltArray
->getCount();
6667 while (depth
>= count
)
6669 // expand array and insert placeholders
6670 gPMHaltArray
->setObject(PLACEHOLDER
);
6673 count
= gPMHaltArray
->getCount();
6676 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
6677 if (inner
== PLACEHOLDER
)
6679 inner
= OSSet::withCapacity(40);
6682 gPMHaltArray
->replaceObject(depth
, inner
);
6687 // PM nodes that appear more than once in the tree will have
6688 // the same depth, OSSet will refuse to add the node twice.
6690 ok
= inner
->setObject(node
);
6693 DLOG("Skipped PM node %s\n", node
->getName());
6699 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
6702 if (inner
!= PLACEHOLDER
)
6703 count
= inner
->getCount();
6704 DLOG("Nodes at depth %u = %u\n", i
, count
);
6707 // strip placeholders (not all depths are populated)
6709 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
6711 if (inner
== PLACEHOLDER
)
6713 gPMHaltArray
->removeObject(i
);
6716 count
= inner
->getCount();
6717 if (count
> numWorkers
)
6719 totalNodes
+= count
;
6723 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
6726 gPMHaltBusyCount
= 0;
6727 gPMHaltIdleCount
= 0;
6728 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
6730 // Create multiple workers (and threads)
6732 if (numWorkers
> kPMHaltMaxWorkers
)
6733 numWorkers
= kPMHaltMaxWorkers
;
6735 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
6736 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
6738 for (unsigned int i
= 0; i
< numWorkers
; i
++)
6739 workers
[i
] = PMHaltWorker::worker();
6741 // Wait for workers to exhaust all available work
6743 IOLockLock(gPMHaltLock
);
6744 while (gPMHaltDepth
>= 0)
6746 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
6748 waitResult
= IOLockSleepDeadline(
6749 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
6750 if (THREAD_TIMED_OUT
== waitResult
)
6753 clock_get_uptime(&now
);
6755 IOLockUnlock(gPMHaltLock
);
6756 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
6759 PMHaltWorker::checkTimeout(workers
[i
], &now
);
6761 IOLockLock(gPMHaltLock
);
6764 IOLockUnlock(gPMHaltLock
);
6766 // Release all workers
6768 for (unsigned int i
= 0; i
< numWorkers
; i
++)
6771 workers
[i
]->release();
6772 // worker also retained by it's own thread
6776 DLOG("%s done\n", __FUNCTION__
);
6780 //*********************************************************************************
6781 // Sleep/Wake logging
6783 //*********************************************************************************
6785 IOMemoryDescriptor
*IOPMrootDomain::getPMTraceMemoryDescriptor(void)
6788 return timeline
->getPMTraceMemoryDescriptor();
6793 // Forwards external reports of detailed events to IOPMTimeline
6794 IOReturn
IOPMrootDomain::recordPMEvent(PMEventDetails
*details
)
6796 if (timeline
&& details
) {
6800 // Record a detailed driver power change event, or...
6801 if(details
->eventClassifier
== kIOPMEventClassDriverEvent
) {
6802 rc
= timeline
->recordDetailedPowerEvent( details
);
6805 // Record a system power management event
6806 else if(details
->eventClassifier
== kIOPMEventClassSystemEvent
) {
6807 rc
= timeline
->recordSystemPowerEvent( details
);
6810 return kIOReturnBadArgument
;
6813 // If we get to record this message, then we've reached the
6814 // end of another successful Sleep --> Wake cycle
6815 // At this point, we pat ourselves in the back and allow
6816 // our Sleep --> Wake UUID to be published
6817 if(details
->eventType
== kIOPMEventTypeWakeDone
) {
6818 timeline
->setSleepCycleInProgressFlag(false);
6822 // Check if its time to clear the timeline buffer
6823 if(getProperty(kIOPMSleepWakeUUIDKey)
6824 && timeline->isSleepCycleInProgress() == false
6825 && timeline->getNumEventsLoggedThisPeriod() > 500) {
6827 // Clear the old UUID
6828 if(pmPowerStateQueue) {
6829 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
6836 return kIOReturnNotReady
;
6839 IOReturn
IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails
*details
)
6841 IOReturn ret
= kIOReturnBadArgument
;
6845 ret
= recordPMEvent(details
);
6852 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6854 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
6855 IOPMDriverAssertionType whichAssertionBits
,
6856 IOPMDriverAssertionLevel assertionLevel
,
6857 IOService
*ownerService
,
6858 const char *ownerDescription
)
6861 IOPMDriverAssertionID newAssertion
;
6866 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
6868 if (kIOReturnSuccess
== ret
)
6869 return newAssertion
;
6874 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
6877 return kIOReturnInternalError
;
6879 return pmAssertions
->releaseAssertion(releaseAssertion
);
6882 IOReturn
IOPMrootDomain::setPMAssertionLevel(
6883 IOPMDriverAssertionID assertionID
,
6884 IOPMDriverAssertionLevel assertionLevel
)
6886 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
6889 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
6891 IOPMDriverAssertionType sysLevels
;
6893 if (!pmAssertions
|| whichAssertion
== 0)
6894 return kIOPMDriverAssertionLevelOff
;
6896 sysLevels
= pmAssertions
->getActivatedAssertions();
6898 // Check that every bit set in argument 'whichAssertion' is asserted
6899 // in the aggregate bits.
6900 if ((sysLevels
& whichAssertion
) == whichAssertion
)
6901 return kIOPMDriverAssertionLevelOn
;
6903 return kIOPMDriverAssertionLevelOff
;
6906 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
6909 return kIOReturnNotFound
;
6911 return pmAssertions
->setUserAssertionLevels(inLevels
);
6914 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
6918 pmAssertions
->publishProperties();
6920 return( IOService::serializeProperties(s
) );
6923 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6926 // MARK: PMSettingHandle
6928 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
6930 void PMSettingHandle::free( void )
6934 pmso
->clientHandleFreed();
6943 // MARK: PMSettingObject
6946 #define super OSObject
6947 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
6950 * Static constructor/initializer for PMSettingObject
6952 PMSettingObject
*PMSettingObject::pmSettingObject(
6953 IOPMrootDomain
*parent_arg
,
6954 IOPMSettingControllerCallback handler_arg
,
6955 OSObject
*target_arg
,
6956 uintptr_t refcon_arg
,
6957 uint32_t supportedPowerSources
,
6958 const OSSymbol
* settings
[],
6959 OSObject
**handle_obj
)
6961 uint32_t settingCount
= 0;
6962 PMSettingObject
*pmso
= 0;
6963 PMSettingHandle
*pmsh
= 0;
6965 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
6968 // count OSSymbol entries in NULL terminated settings array
6969 while (settings
[settingCount
]) {
6972 if (0 == settingCount
)
6975 pmso
= new PMSettingObject
;
6976 if (!pmso
|| !pmso
->init())
6979 pmsh
= new PMSettingHandle
;
6980 if (!pmsh
|| !pmsh
->init())
6983 queue_init(&pmso
->calloutQueue
);
6984 pmso
->parent
= parent_arg
;
6985 pmso
->func
= handler_arg
;
6986 pmso
->target
= target_arg
;
6987 pmso
->refcon
= refcon_arg
;
6988 pmso
->settingCount
= settingCount
;
6990 pmso
->retain(); // handle holds a retain on pmso
6994 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
6995 if (pmso
->publishedFeatureID
) {
6996 for (unsigned int i
=0; i
<settingCount
; i
++) {
6997 // Since there is now at least one listener to this setting, publish
6998 // PM root domain support for it.
6999 parent_arg
->publishPMSetting( settings
[i
],
7000 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
7008 if (pmso
) pmso
->release();
7009 if (pmsh
) pmsh
->release();
7013 void PMSettingObject::free( void )
7015 if (publishedFeatureID
) {
7016 for (uint32_t i
=0; i
<settingCount
; i
++) {
7017 if (publishedFeatureID
[i
]) {
7018 parent
->removePublishedFeature( publishedFeatureID
[i
] );
7022 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
7028 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
7030 (*func
)(target
, type
, object
, refcon
);
7033 void PMSettingObject::clientHandleFreed( void )
7035 parent
->deregisterPMSettingObject(this);
7039 // MARK: IOPMTimeline
7042 #define super OSObject
7044 //*********************************************************************************
7045 //*********************************************************************************
7046 //*********************************************************************************
7048 IOPMTimeline
*IOPMTimeline::timeline(IOPMrootDomain
*root_domain
)
7050 IOPMTimeline
*myself
;
7055 myself
= new IOPMTimeline
;
7058 myself
->owner
= root_domain
;
7065 bool IOPMTimeline::init(void)
7067 if (!super::init()) {
7071 logLock
= IOLockAlloc();
7073 // Fresh timeline, no events logged yet
7074 this->numEventsLoggedThisPeriod
= 0;
7075 this->sleepCycleInProgress
= false;
7077 //this->setEventsRecordingLevel(1); // TODO
7078 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked
);
7083 void IOPMTimeline::free(void)
7085 if (pmTraceMemoryDescriptor
) {
7086 pmTraceMemoryDescriptor
->release();
7087 pmTraceMemoryDescriptor
= NULL
;
7090 IOLockFree(logLock
);
7095 IOMemoryDescriptor
*IOPMTimeline::getPMTraceMemoryDescriptor()
7097 return pmTraceMemoryDescriptor
;
7100 //*********************************************************************************
7101 //*********************************************************************************
7102 //*********************************************************************************
7104 bool IOPMTimeline::setProperties(OSDictionary
*d
)
7107 OSBoolean
*b
= NULL
;
7108 bool changed
= false;
7110 /* Changes size of detailed events buffer */
7111 n
= (OSNumber
*)d
->getObject(kIOPMTimelineSystemNumberTrackedKey
);
7112 if (OSDynamicCast(OSNumber
, n
))
7115 this->setEventsTrackedCount(n
->unsigned32BitValue());
7119 /* enables or disables system events */
7120 b
= (OSBoolean
*)d
->getObject(kIOPMTimelineEnabledKey
);
7124 this->setEventsRecordingLevel((int)(kOSBooleanTrue
== b
));
7130 //*********************************************************************************
7131 //*********************************************************************************
7132 //*********************************************************************************
7134 OSDictionary
*IOPMTimeline::copyInfoDictionary(void)
7136 OSDictionary
*out
= OSDictionary::withCapacity(3);
7142 n
= OSNumber::withNumber(hdr
->sizeEntries
, 32);
7143 out
->setObject(kIOPMTimelineSystemNumberTrackedKey
, n
);
7146 n
= OSNumber::withNumber(hdr
->sizeBytes
, 32);
7147 out
->setObject(kIOPMTimelineSystemBufferSizeKey
, n
);
7151 out
->setObject(kIOPMTimelineEnabledKey
, eventsRecordingLevel
? kOSBooleanTrue
: kOSBooleanFalse
);
7156 //*********************************************************************************
7157 //*********************************************************************************
7158 //*********************************************************************************
7160 /* IOPMTimeline::recordSystemPowerEvent()
7162 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
7163 * Type arguments include "system events", and "Intermediate events"
7165 * - System Events have paired "start" and "stop" events.
7166 * - A start event shall be followed by a stop event.
7167 * - Any number of Intermediate Events may fall between the
7168 * start and stop events.
7169 * - Intermediate events are meaningless outside the bounds of a system event's
7170 * start & stoup routines.
7171 * - It's invalid to record a Start event without a following Stop event; e.g. two
7172 * Start events without an intervenining Stop event is invalid.
7175 * - The first recorded system event shall be preceded by an entry with type == 0
7176 * - IOPMTimeline may choose not to record intermediate events while there's not
7177 * a system event in process.
7179 IOReturn
IOPMTimeline::recordSystemPowerEvent( PMEventDetails
*details
)
7181 static bool wakeDonePending
= true;
7182 IOPMSystemEventRecord
*record_to
= NULL
;
7183 OSString
*swUUIDKey
= NULL
;
7184 uint32_t useIndex
= 0;
7187 return kIOReturnBadArgument
;
7190 return kIOReturnNotReady
;
7192 if (details
->eventType
== kIOPMEventTypeWakeDone
)
7194 if(!wakeDonePending
)
7195 return kIOReturnBadArgument
;
7198 IOLockLock(logLock
);
7200 if (details
->eventType
== kIOPMEventTypeWake
) {
7201 wakeDonePending
= true;
7202 } else if (details
->eventType
== kIOPMEventTypeWakeDone
) {
7203 wakeDonePending
= false;
7206 systemState
= details
->eventType
;
7208 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7210 // The entry immediately after the latest entry (and thus
7211 // immediately before the first entry) shall have a type 0.
7212 if (useIndex
+ 1 >= hdr
->sizeEntries
) {
7213 traceBuffer
[useIndex
+ 1].eventType
= 0;
7215 traceBuffer
[0].eventType
= 0;
7218 record_to
= &traceBuffer
[useIndex
];
7219 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7222 record_to
->eventType
= details
->eventType
;
7223 record_to
->eventReason
= details
->reason
;
7224 record_to
->eventResult
= details
->result
;
7225 pmEventTimeStamp(&record_to
->timestamp
);
7227 // If caller doesn't provide a UUID, we'll use the UUID that's posted
7228 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
7229 if (!details
->uuid
) {
7230 swUUIDKey
= OSDynamicCast(OSString
, owner
->copyProperty(kIOPMSleepWakeUUIDKey
));
7233 details
->uuid
= swUUIDKey
->getCStringNoCopy();
7237 strncpy(record_to
->uuid
, details
->uuid
, kMaxPMStringLength
);
7240 swUUIDKey
->release();
7242 numEventsLoggedThisPeriod
++;
7245 IOLockUnlock(logLock
);
7247 return kIOReturnSuccess
;
7251 //*********************************************************************************
7252 //*********************************************************************************
7253 //*********************************************************************************
7255 IOReturn
IOPMTimeline::recordDetailedPowerEvent( PMEventDetails
*details
)
7257 IOPMSystemEventRecord
*record_to
= NULL
;
7260 if (!details
->eventType
|| !details
->ownerName
)
7261 return kIOReturnBadArgument
;
7263 IOLockLock(logLock
);
7265 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7267 record_to
= (IOPMSystemEventRecord
*)&traceBuffer
[useIndex
];
7268 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7271 record_to
->eventType
= details
->eventType
;
7272 if (details
->ownerName
&& (strlen(details
->ownerName
) > 1)) {
7273 strlcpy( record_to
->ownerName
,
7275 sizeof(record_to
->ownerName
));
7278 record_to
->ownerDisambiguateID
= details
->ownerUnique
;
7280 if (details
->interestName
&& (strlen(details
->interestName
) > 1)) {
7281 strlcpy(record_to
->interestName
,
7282 details
->interestName
,
7283 sizeof(record_to
->interestName
));
7286 record_to
->oldState
= details
->oldState
;
7287 record_to
->newState
= details
->newState
;
7288 record_to
->eventResult
= details
->result
;
7289 record_to
->elapsedTimeUS
= details
->elapsedTimeUS
;
7290 pmEventTimeStamp(&record_to
->timestamp
);
7292 numEventsLoggedThisPeriod
++;
7295 IOLockUnlock(logLock
);
7296 return kIOReturnSuccess
;
7299 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
7300 return this->numEventsLoggedThisPeriod
;
7303 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount
) {
7304 this->numEventsLoggedThisPeriod
= newCount
;
7307 bool IOPMTimeline::isSleepCycleInProgress() {
7308 return this->sleepCycleInProgress
;
7311 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag
) {
7312 this->sleepCycleInProgress
= flag
;
7314 //*********************************************************************************
7315 //*********************************************************************************
7316 //*********************************************************************************
7318 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked
)
7320 size_t make_buf_size
= 0;
7322 make_buf_size
= sizeof(IOPMTraceBufferHeader
) + (newTracked
* sizeof(IOPMSystemEventRecord
));
7324 IOLockLock(logLock
);
7326 if (pmTraceMemoryDescriptor
) {
7327 pmTraceMemoryDescriptor
->release();
7328 pmTraceMemoryDescriptor
= NULL
;
7334 if (0 == newTracked
)
7336 IOLog("IOPMrootDomain -> erased buffer.\n");
7340 pmTraceMemoryDescriptor
= IOBufferMemoryDescriptor::withOptions(
7341 kIOMemoryKernelUserShared
| kIODirectionIn
, make_buf_size
);
7343 if (!pmTraceMemoryDescriptor
)
7345 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size
);
7349 pmTraceMemoryDescriptor
->prepare(kIODirectionIn
);
7351 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
7352 hdr
= (IOPMTraceBufferHeader
*)pmTraceMemoryDescriptor
->getBytesNoCopy();
7354 // Recorded events occupy the remaining bulk of the buffer
7355 traceBuffer
= (IOPMSystemEventRecord
*)((uint8_t *)hdr
+ sizeof(IOPMTraceBufferHeader
));
7357 bzero(hdr
, make_buf_size
);
7359 hdr
->sizeBytes
= make_buf_size
;
7360 hdr
->sizeEntries
= newTracked
;
7362 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size
, (unsigned int)(uintptr_t)traceBuffer
);
7365 IOLockUnlock(logLock
);
7368 //*********************************************************************************
7369 //*********************************************************************************
7370 //*********************************************************************************
7372 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits
)
7381 /* static helper to IOPMTimeline
7383 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index
, uint32_t limit
)
7393 inc_index
= (was_index
+1)%limit
;
7394 } while (!OSCompareAndSwap(was_index
, inc_index
, index
));
7400 // MARK: PMAssertionsTracker
7402 //*********************************************************************************
7403 //*********************************************************************************
7404 //*********************************************************************************
7405 // class PMAssertionsTracker Implementation
7407 #define kAssertUniqueIDStart 500
7409 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
7411 PMAssertionsTracker
*myself
;
7413 myself
= new PMAssertionsTracker
;
7417 myself
->owner
= rootDomain
;
7418 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
7419 myself
->assertionsArray
= OSArray::withCapacity(5);
7420 myself
->assertionsKernel
= 0;
7421 myself
->assertionsUser
= 0;
7422 myself
->assertionsCombined
= 0;
7423 myself
->assertionsArrayLock
= IOLockAlloc();
7424 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
7426 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
7434 * - Update assertionsKernel to reflect the state of all
7435 * assertions in the kernel.
7436 * - Update assertionsCombined to reflect both kernel & user space.
7438 void PMAssertionsTracker::tabulate(void)
7442 PMAssertStruct
*_a
= NULL
;
7445 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
7446 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
7450 assertionsKernel
= 0;
7451 assertionsCombined
= 0;
7453 if (!assertionsArray
)
7456 if ((count
= assertionsArray
->getCount()))
7458 for (i
=0; i
<count
; i
++)
7460 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7463 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7464 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
7465 assertionsKernel
|= _a
->assertionBits
;
7470 tabulateProducerCount
++;
7471 assertionsCombined
= assertionsKernel
| assertionsUser
;
7473 if ((assertionsKernel
!= oldKernel
) ||
7474 (assertionsCombined
!= oldCombined
))
7476 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
7480 void PMAssertionsTracker::publishProperties( void )
7482 OSArray
*assertionsSummary
= NULL
;
7484 if (tabulateConsumerCount
!= tabulateProducerCount
)
7486 IOLockLock(assertionsArrayLock
);
7488 tabulateConsumerCount
= tabulateProducerCount
;
7490 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
7492 assertionsSummary
= copyAssertionsArray();
7493 if (assertionsSummary
)
7495 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
7496 assertionsSummary
->release();
7500 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
7503 /* Publish the IOPMrootDomain property "DriverPMAssertions"
7505 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
7507 IOLockUnlock(assertionsArrayLock
);
7511 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
7513 PMAssertStruct
*_a
= NULL
;
7520 && (count
= assertionsArray
->getCount()))
7522 for (i
=0; i
<count
; i
++)
7524 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7527 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7528 if (_a
&& (_id
== _a
->id
)) {
7545 /* PMAssertionsTracker::handleCreateAssertion
7546 * Perform assertion work on the PM workloop. Do not call directly.
7548 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
7554 IOLockLock(assertionsArrayLock
);
7555 assertionsArray
->setObject(newAssertion
);
7556 IOLockUnlock(assertionsArrayLock
);
7557 newAssertion
->release();
7561 return kIOReturnSuccess
;
7564 /* PMAssertionsTracker::createAssertion
7565 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
7568 IOReturn
PMAssertionsTracker::createAssertion(
7569 IOPMDriverAssertionType which
,
7570 IOPMDriverAssertionLevel level
,
7571 IOService
*serviceID
,
7572 const char *whoItIs
,
7573 IOPMDriverAssertionID
*outID
)
7575 OSData
*dataStore
= NULL
;
7576 PMAssertStruct track
;
7578 // Warning: trillions and trillions of created assertions may overflow the unique ID.
7579 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
7580 track
.level
= level
;
7581 track
.assertionBits
= which
;
7582 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
) : 0;
7583 track
.ownerService
= serviceID
;
7584 track
.modifiedTime
= 0;
7585 pmEventTimeStamp(&track
.createdTime
);
7587 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
7590 if (track
.ownerString
)
7591 track
.ownerString
->release();
7592 return kIOReturnNoMemory
;
7597 if (owner
&& owner
->pmPowerStateQueue
) {
7598 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
7601 return kIOReturnSuccess
;
7604 /* PMAssertionsTracker::handleReleaseAssertion
7605 * Runs in PM workloop. Do not call directly.
7607 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
7608 IOPMDriverAssertionID _id
)
7613 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
7616 return kIOReturnNotFound
;
7618 IOLockLock(assertionsArrayLock
);
7619 if (assertStruct
->ownerString
)
7620 assertStruct
->ownerString
->release();
7622 assertionsArray
->removeObject(index
);
7623 IOLockUnlock(assertionsArrayLock
);
7626 return kIOReturnSuccess
;
7629 /* PMAssertionsTracker::releaseAssertion
7630 * Releases an assertion and affects system behavior if appropiate.
7631 * Actual work happens on PM workloop.
7633 IOReturn
PMAssertionsTracker::releaseAssertion(
7634 IOPMDriverAssertionID _id
)
7636 if (owner
&& owner
->pmPowerStateQueue
) {
7637 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
7639 return kIOReturnSuccess
;
7642 /* PMAssertionsTracker::handleSetAssertionLevel
7643 * Runs in PM workloop. Do not call directly.
7645 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
7646 IOPMDriverAssertionID _id
,
7647 IOPMDriverAssertionLevel _level
)
7649 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
7653 if (!assertStruct
) {
7654 return kIOReturnNotFound
;
7657 IOLockLock(assertionsArrayLock
);
7658 pmEventTimeStamp(&assertStruct
->modifiedTime
);
7659 assertStruct
->level
= _level
;
7660 IOLockUnlock(assertionsArrayLock
);
7663 return kIOReturnSuccess
;
7666 /* PMAssertionsTracker::setAssertionLevel
7668 IOReturn
PMAssertionsTracker::setAssertionLevel(
7669 IOPMDriverAssertionID _id
,
7670 IOPMDriverAssertionLevel _level
)
7672 if (owner
&& owner
->pmPowerStateQueue
) {
7673 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
7674 (void *)_level
, _id
);
7677 return kIOReturnSuccess
;
7680 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
7682 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
7686 if (new_user_levels
!= assertionsUser
)
7688 assertionsUser
= new_user_levels
;
7689 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
7693 return kIOReturnSuccess
;
7696 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
7697 IOPMDriverAssertionType new_user_levels
)
7699 if (gIOPMWorkLoop
) {
7700 gIOPMWorkLoop
->runAction(
7701 OSMemberFunctionCast(
7704 &PMAssertionsTracker::handleSetUserAssertionLevels
),
7706 (void *) &new_user_levels
, 0, 0, 0);
7709 return kIOReturnSuccess
;
7713 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
7717 OSArray
*outArray
= NULL
;
7719 if (!assertionsArray
||
7720 (0 == (count
= assertionsArray
->getCount())) ||
7721 (NULL
== (outArray
= OSArray::withCapacity(count
))))
7726 for (i
=0; i
<count
; i
++)
7728 PMAssertStruct
*_a
= NULL
;
7730 OSDictionary
*details
= NULL
;
7732 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7733 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
7735 OSNumber
*_n
= NULL
;
7737 details
= OSDictionary::withCapacity(7);
7741 outArray
->setObject(details
);
7744 _n
= OSNumber::withNumber(_a
->id
, 64);
7746 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
7749 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
7751 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
7754 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
7756 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
7759 _n
= OSNumber::withNumber((uintptr_t)_a
->ownerService
, 64);
7761 details
->setObject(kIOPMDriverAssertionOwnerServiceKey
, _n
);
7764 _n
= OSNumber::withNumber(_a
->level
, 64);
7766 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
7769 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
7771 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
7775 if (_a
->ownerString
) {
7776 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
7785 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
7787 return assertionsCombined
;
7790 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
7791 IOPMDriverAssertionType type
)
7793 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
7795 return kIOPMDriverAssertionLevelOn
;
7797 return kIOPMDriverAssertionLevelOff
;
7801 //*********************************************************************************
7802 //*********************************************************************************
7803 //*********************************************************************************
7806 static void pmEventTimeStamp(uint64_t *recordTS
)
7814 // We assume tsec fits into 32 bits; 32 bits holds enough
7815 // seconds for 136 years since the epoch in 1970.
7816 clock_get_calendar_microtime(&tsec
, &tusec
);
7819 // Pack the sec & microsec calendar time into a uint64_t, for fun.
7821 *recordTS
|= (uint32_t)tusec
;
7822 *recordTS
|= ((uint64_t)tsec
<< 32);
7828 // MARK: IORootParent
7830 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7832 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
7834 // The reason that root domain needs a root parent is to facilitate demand
7835 // sleep, since a power change from the root parent cannot be vetoed.
7837 // The above statement is no longer true since root domain now performs
7838 // demand sleep using overrides. But root parent remains to avoid changing
7839 // the power tree stacking. Root parent is parked at the max power state.
7842 static IOPMPowerState patriarchPowerStates
[2] =
7844 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
7845 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
7848 void IORootParent::initialize( void )
7852 bool IORootParent::start( IOService
* nub
)
7854 IOService::start(nub
);
7855 attachToParent( getRegistryRoot(), gIOPowerPlane
);
7857 registerPowerDriver(this, patriarchPowerStates
, 2);
7862 void IORootParent::shutDownSystem( void )
7866 void IORootParent::restartSystem( void )
7870 void IORootParent::sleepSystem( void )
7874 void IORootParent::dozeSystem( void )
7878 void IORootParent::sleepToDoze( void )
7882 void IORootParent::wakeSystem( void )
7886 OSObject
* IORootParent::copyProperty( const char * aKey
) const
7888 return (IOService::copyProperty(aKey
));